├── .gitignore ├── admin-scripts ├── add-user.sh ├── add-sudoer.sh ├── add-db.sh ├── rm-site.sh └── add-site.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | test* 2 | 3 | -------------------------------------------------------------------------------- /admin-scripts/add-user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ================================================================== # 3 | # Shell script to add a new sudoer 4 | # ================================================================== # 5 | # Copyright (c) 2012 Matt Thomas http://betweenbrain.com 6 | # This script is licensed under GNU GPL version 2.0 or above 7 | # ================================================================== # 8 | # 9 | read -p "Enter new user's username: " NEWUSER 10 | # 11 | useradd -s /bin/bash -m -d /home/$NEWUSER --user-group $NEWUSER 12 | passwd $NEWUSER 13 | # 14 | 15 | -------------------------------------------------------------------------------- /admin-scripts/add-sudoer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ================================================================== # 3 | # Shell script to add a new sudoer 4 | # ================================================================== # 5 | # Copyright (c) 2012 Matt Thomas http://betweenbrain.com 6 | # This script is licensed under GNU GPL version 2.0 or above 7 | # ================================================================== # 8 | # 9 | read -p "Enter new sudoer username: " SUDOER 10 | # 11 | sudo cp /etc/sudoers /etc/sudoers.tmp 12 | sudo chmod 0640 /etc/sudoers.tmp 13 | echo "$SUDOER ALL=(ALL) ALL" >> /etc/sudoers.tmp 14 | sudo chmod 0440 /etc/sudoers.tmp 15 | sudo mv /etc/sudoers.tmp /etc/sudoers 16 | # 17 | echo "$SUDOER is now a sudoer" 18 | # 19 | 20 | -------------------------------------------------------------------------------- /admin-scripts/add-db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ================================================================== # 3 | # Shell script to add a mysql database and user with db access. 4 | # ================================================================== # 5 | # Copyright (c) 2012 Matt Thomas http://betweenbrain.com 6 | # This script is licensed under GNU GPL version 2.0 or above 7 | # ================================================================== # 8 | # 9 | read -s -p "Enter your MySQL user password: " MYSQLPW 10 | echo 11 | read -p "Enter new database name: " DB 12 | echo 13 | read -p "Enter new username: " USER 14 | echo 15 | read -s -p "Enter password for this user: " PW 16 | echo 17 | # 18 | QUERY="CREATE DATABASE $DB;GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON $DB.* TO '$USER'@'localhost' IDENTIFIED BY '$PW';" 19 | mysql -u root -p$MYSQLPW -e "$QUERY" 20 | # 21 | echo "Done creating database $DB and granting access to $USER with password $PW" 22 | # 23 | 24 | -------------------------------------------------------------------------------- /admin-scripts/rm-site.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ================================================================== # 3 | # Shell script to remove a site (virtual host) 4 | # ================================================================== # 5 | # Parts copyright (c) 2012 Matt Thomas http://betweenbrain.com 6 | # This script is licensed under GNU GPL version 2.0 or above 7 | # ================================================================== # 8 | # 9 | read -p "Enter site to remove: " DOMAIN 10 | echo 11 | read -p "Enter user under which site exists: " USER 12 | echo 13 | echo 14 | echo 15 | echo "Removing directories for $DOMAIN in $USER's home directory" 16 | echo "--------------------------------------------------------------" 17 | # 18 | rm -r /home/$USER/public_html/$DOMAIN/ 19 | # 20 | echo 21 | echo 22 | echo 23 | echo "Removing VirtualHost for $DOMAIN" 24 | echo "--------------------------------------------------------------" 25 | # 26 | rm /etc/apache2/sites-available/$DOMAIN 27 | # 28 | echo 29 | echo 30 | echo 31 | echo "Removing fcgi wrapper for $DOMAIN, making it executable and setting owner" 32 | echo "--------------------------------------------------------------" 33 | # 34 | rm -r /var/www/php-fcgi-scripts/$DOMAIN/ 35 | # 36 | echo 37 | echo 38 | echo 39 | echo "Removing logrotate conf for $DOMAIN" 40 | echo "--------------------------------------------------------------" 41 | # 42 | rm -r /etc/logrotate.d/$DOMAIN 43 | # 44 | echo 45 | echo 46 | echo 47 | echo "Disabling site $DOMAIN, restarting apache" 48 | echo "--------------------------------------------------------------" 49 | # 50 | a2dissite $DOMAIN 51 | /etc/init.d/apache2 restart 52 | # 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Initial server setup 2 | ==================== 3 | 4 | A hand-rolled bash shell script to help you get up and running quickly with an Ubuntu 10.04 web server (Apache2 MPM Worker, MySQL, PHP5, suexec, fcgid). 5 | 6 | Please note: This is not intended to be a complete and comprehensive solution, but a starting point for your custom server. Tweak, modify and adjust as needed and desired. 7 | 8 | Basic security and essential packages are included. For security and performance reasons, no GUI solutions have been included. 9 | 10 | Features 11 | ----------------- 12 | This script does a bunch of things. The general run down is that it: 13 | 14 | * Updates your server and configures a number of general settings, such as your hostname, server IP address, timezone ...etc. 15 | * Securely configures SSH to listen on a custom port, while restricted to a single IP address, disables root SSH login, disables password access, and grants your new admin user (also a sudoer) SSH access via an SSH key. 16 | * Configures IPTables so that you server only accepts and sends data on ports 80, 443 and your custom port for SSH. Also allows sending on port 25 for sendmail/postifx. 17 | * Adds a basic DoS rule to IPTables, with logging. 18 | * Two scripts are added so that IPTables rules are saved and re-loaded when rebooting. 19 | * Installs and configures Apache2 (MPM Worker), MySQL, PHP5, suExec, fcgid, as well as creates and enables a new site under your admin user's account. 20 | * Installs and configures mod_evasive, fail2ban, and mod_security. Your admin user's IP address is white-listed from these security services and a mod_security filter is added to fail2ban. OWASP rules for mod_security v2.2.3 are fetched, configured, and a select set of rules, beyond the base rules, are loaded. 21 | NOTE: The OWASP rules are configured for DetectionOnly by default. You will need to change that to On when you are comfortable that they are not too many false positives. 22 | ANOTHER NOTE: As Ubuntu 10.04 uses mod_security 2.5.11-1, backwards compatibility workarounds are implemented. Read the script and see them for yourself ;) 23 | 24 | Getting started 25 | ---------------- 26 | 27 | 1. Before you do anything else, thoroughly review [build.sh](https://github.com/betweenbrain/ubuntu-web-server-build-script/blob/master/build.sh). You need to understand what it is doing. 28 | 2. Then, fire up your VM or VPS with a fresh install of Ubuntu 10.04, connect via SSH and become the Root user. 29 | 3. Upload [build.sh](https://github.com/betweenbrain/ubuntu-web-server-build-script/blob/master/build.sh) to your server -OR- create a new shell script via `$ nano build.sh` and copy/paste the contents of [build.sh](https://github.com/betweenbrain/ubuntu-web-server-build-script/blob/master/build.sh) into it. 30 | 4. Make your script executable `$ chmod +x build.sh` 31 | 5. Let 'er rip! `$ ./build.sh` and follow the on-screen prompts. 32 | 33 | When running this script, please keep an eye on things (they tend to happen fast) and keep an eye out for errors. 34 | If you observe any erros while executing this script, please [create an issue report](https://github.com/betweenbrain/ubuntu-web-server-build-script/issues?sort=created&direction=desc&state=open). 35 | 36 | Need a VPS? Get one from [Linode](http://www.linode.com/?r=e0368c8dce7aa292de419c36ae0078f64d6d4233), they rock! 37 | 38 | What's Next? 39 | ------------ 40 | Here are a few ideas: 41 | 42 | * Grab a copy of mysqltuner.pl and tweak your mysql install `wget http://mysqltuner.pl/mysqltuner.pl` run with `perl mysqltuner.pl` and follow the recommendations. Some may include: 43 | * Disable innob: `sed -i "s/ssl-key=\/etc\/mysql\/server-key.pem/ssl-key=\/etc\/mysql\/server-key.pem\n\nskip-innodb\n/g" /etc/mysql/my.cnf` 44 | * Limit MySQL queries: `sed -i "s/#max_connections/max_connections/g" /etc/mysql/my.cnf` 45 | * Enable slow query logging: `sed -i "s/#log_slow_queries/log_slow_queries/g" /etc/mysql/my.cnf`
46 | `sed -i "s/#long_query_time/long_query_time/g" /etc/mysql/my.cnf` 47 | * Set query cache type: `sed -i "s/query_cache_size = 16M/query_cache_size = 16M\nquery_cache_type = 1\n/g" /etc/mysql/my.cnf` 48 | * Enable table cache: `sed -i "s/#table_cache/table_cache/g" /etc/mysql/my.cnf` 49 | 50 | * Keep an eye on your logs and adjust mod_security / fail2ban accordingly 51 | 52 | * Keep things up to date. For example `sudo aptitude safe-upgrade` 53 | 54 | * Add a new database, with a corresponding user, with [add-db.sh](https://github.com/betweenbrain/ubuntu-web-server-build-script/blob/master/admin-scripts/add-db.sh) 55 | 56 | * Add email aliases to postfix: 57 | * `sudo nano /etc/postfix/virtual` 58 | * Add: `alias email@foo.bar` 59 | * `sudo postmap /etc/postfix/virtual` 60 | * `sudo service postfix reload` 61 | 62 | * Make sure that you own your bash history file `sudo chown you:you ~/.bash_history` 63 | 64 | * Install and configure OSSEC 65 | - sources http://ubuntuforums.org/showthread.php?t=213445 | http://ossec.net/ossec-docs/OSSEC-book-Ch02_SA240.pdf | http://devio.us/~ddp/ossec/docs/manual/installation/ 66 | * `sudo apt-get install build-essential` 67 | * `wget http://www.ossec.net/files/ossec-hids-latest.tar.gz` 68 | * `wget http://www.ossec.net/files/ossec-hids-2.6_checksum.txt` <= if latest is version 2.6, see http://www.ossec.net/main/downloads 69 | * `cat ossec-hids-2.6_checksum.txt` 70 | * `md5sum ossec-hids-latest.tar.gz` 71 | * `sha1sum ossec-hids-latest.tar.gz` 72 | * `tar -zxvf ossec-hids-*.tar.gz` 73 | * `cd ossec-hids-*` 74 | * `sudo ./install.sh` 75 | 76 | * OSSEC documentation: http://www.ossec.net/main/manual 77 | * conf file at /var/ossec/etc/ossec.conf 78 | 79 | Warranty, guarantees, culpability...etc. 80 | ---------------- 81 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 82 | 83 | Use at your own risk, I do :) 84 | 85 | Parts copyright 86 | ----------------- 87 | Unless otherwise stated, this software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 88 | 89 | All attempts have been made to identify third party sources, copyrights, and works within in the script. If I missed something, please let me know and I'll fix it. 90 | 91 | -------------------------------------------------------------------------------- /admin-scripts/add-site.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ================================================================== # 3 | # Shell script to add a new site (virtual host) 4 | # ================================================================== # 5 | # Parts copyright (c) 2012 Matt Thomas http://betweenbrain.com 6 | # This script is licensed under GNU GPL version 2.0 or above 7 | # ================================================================== # 8 | # 9 | read -p "Enter new site domain: " DOMAIN 10 | echo 11 | read -p "Enter user under which new site will run under: " USER 12 | echo 13 | echo 14 | echo 15 | echo "Creating directories for $DOMAIN in $USER's home directory" 16 | echo "--------------------------------------------------------------" 17 | # 18 | mkdir -p /home/$USER/public_html/$DOMAIN/{cgi-bin,log,log/old,www} 19 | echo "$DOMAIN works!'; ?>" > /home/$USER/public_html/$DOMAIN/www/index.php 20 | # 21 | echo 22 | echo 23 | echo 24 | echo "Setting correct ownership and permissions for $DOMAIN" 25 | echo "--------------------------------------------------------------" 26 | # 27 | chown -R $USER:$USER /home/$USER/public_html 28 | find /home/$USER/public_html/$DOMAIN/ -type d -exec chmod 755 {} \; 29 | find /home/$USER/public_html/$DOMAIN/ -type f -exec chmod 644 {} \; 30 | # 31 | echo 32 | echo 33 | echo 34 | echo "Creating VirtualHost for $DOMAIN" 35 | # http://www.howtoforge.com/how-to-set-up-apache2-with-mod_fcgid-and-php5-on-ubuntu-8.10 36 | echo "--------------------------------------------------------------" 37 | # 38 | echo " 39 | DocumentRoot /home/$USER/public_html/$DOMAIN/www 40 | 41 | ServerName $DOMAIN 42 | ServerAlias www.$DOMAIN 43 | ServerAdmin webmaster@$DOMAIN 44 | ServerSignature Off 45 | 46 | LogLevel warn 47 | ErrorLog /home/$USER/public_html/$DOMAIN/log/error.log 48 | CustomLog /home/$USER/public_html/$DOMAIN/log/access.log combined 49 | 50 | 51 | SuexecUserGroup $USER $USER 52 | 53 | Options FollowSymLinks +ExecCGI 54 | AddHandler fcgid-script .php 55 | FCGIWrapper /var/www/php-fcgi-scripts/$DOMAIN/php-wrapper .php 56 | AllowOverride All 57 | Order allow,deny 58 | Allow from all 59 | DirectoryIndex index.php index.html 60 | 61 | 62 | 63 | 64 | 65 | 66 | DocumentRoot /home/$USER/public_html/$DOMAIN/www 67 | 68 | ServerName $DOMAIN 69 | ServerAlias www.$DOMAIN 70 | ServerAdmin webmaster@$DOMAIN 71 | ServerSignature Off 72 | 73 | LogLevel warn 74 | ErrorLog /home/$USER/public_html/$DOMAIN/log/ssl_error.log 75 | CustomLog /home/$USER/public_html/$DOMAIN/log/ssl_access.log combined 76 | 77 | # See /etc/apache2/sites-available/default-ssl 78 | 79 | SSLEngine on 80 | 81 | SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem 82 | SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key 83 | 84 | 85 | SSLOptions +StdEnvVars 86 | 87 | 88 | SSLOptions +StdEnvVars 89 | 90 | 91 | BrowserMatch \"MSIE [2-6]\" \\ 92 | nokeepalive ssl-unclean-shutdown \\ 93 | downgrade-1.0 force-response-1.0 94 | # MSIE 7 and newer should be able to use keepalive 95 | BrowserMatch \"MSIE [17-9]\" ssl-unclean-shutdown 96 | 97 | 98 | SuexecUserGroup $USER $USER 99 | 100 | Options FollowSymLinks +ExecCGI 101 | AddHandler fcgid-script .php 102 | FCGIWrapper /var/www/php-fcgi-scripts/$DOMAIN/php-wrapper .php 103 | AllowOverride All 104 | Order allow,deny 105 | Allow from all 106 | DirectoryIndex index.php index.html 107 | 108 | 109 | 110 | 111 | 112 | " > /etc/apache2/sites-available/$DOMAIN 113 | # 114 | echo 115 | echo 116 | echo 117 | echo "Creating fcgi wrapper for $DOMAIN, making it executable and setting owner" 118 | # http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html 119 | echo "--------------------------------------------------------------" 120 | # 121 | mkdir /var/www/php-fcgi-scripts/ 122 | mkdir /var/www/php-fcgi-scripts/$DOMAIN/ 123 | # 124 | echo "#!/bin/sh 125 | export PHPRC=/etc/php5/cgi/ 126 | export PHP_FCGI_MAX_REQUESTS=1000 127 | export PHP_FCGI_CHILDREN=0 128 | exec /usr/lib/cgi-bin/php 129 | " > /var/www/php-fcgi-scripts/$DOMAIN/php-wrapper 130 | # 131 | chmod 755 /var/www/php-fcgi-scripts/$DOMAIN/php-wrapper 132 | # 133 | chown -R $USER:$USER /var/www/php-fcgi-scripts/$DOMAIN 134 | # 135 | echo 136 | echo 137 | echo 138 | echo "Adding logrotate conf for $DOMAIN" 139 | echo "--------------------------------------------------------------" 140 | # 141 | echo "/home/$USER/public_html/$DOMAIN/log/*.log { 142 | weekly 143 | missingok 144 | rotate 52 145 | compress 146 | delaycompress 147 | notifempty 148 | create 640 $USER $USER 149 | olddir /home/$USER/public_html/$DOMAIN/log/old/ 150 | } 151 | " > /etc/logrotate.d/$DOMAIN 152 | # 153 | echo 154 | echo 155 | echo 156 | echo "Adding mod_security monitoring to fail2ban" 157 | # based on http://www.fail2ban.org/wiki/index.php/HOWTO_fail2ban_with_ModSecurity2.5 158 | echo "---------------------------------------------------------------" 159 | # 160 | echo " 161 | [modsecurity-$DOMAIN] 162 | 163 | enabled = true 164 | filter = modsecurity 165 | action = iptables-multiport[name=ModSecurity, port=\"http,https\"] 166 | sendmail-buffered[name=ModSecurity, lines=10, dest=webmaster@$DOMAIN] 167 | logpath = /home/$USER/public_html/$DOMAIN/log/*error.log 168 | bantime = 600 169 | maxretry = 3 170 | " >> /etc/fail2ban/jail.local 171 | # 172 | echo 173 | echo 174 | echo 175 | echo "Installing and configuring logwatch for log monitoring" 176 | # https://help.ubuntu.com/community/Logwatch 177 | echo "--------------------------------------------------------------" 178 | # 179 | aptitude -y install logwatch 180 | mkdir /var/cache/logwatch 181 | cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/ 182 | # 183 | sed -i "s/MailTo = root/MailTo = $ADMINEMAIL/g" /etc/logwatch/conf/logwatch.conf 184 | sed -i "s/Detail = Low/Detail = High/g" /etc/logwatch/conf/logwatch.conf 185 | sed -i "s/Format = text/Format = html/g" /etc/logwatch/conf/logwatch.conf 186 | # 187 | cp /usr/share/logwatch/default.conf/logfiles/http.conf to /etc/logwatch/conf/logfiles 188 | # 189 | echo " 190 | # Log files for $DOMAIN 191 | LogFile = /home/$USER/public_html/$DOMAIN/log/access.log 192 | LogFile = /home/$USER/public_html/$DOMAIN/log/error.log 193 | LogFile = /home/$USER/public_html/$DOMAIN/log/ssl_error.log 194 | LogFile = /home/$USER/public_html/$DOMAIN/log/ssl_access.log 195 | " >> /etc/logwatch/conf/logfiles/http.conf 196 | # 197 | echo 198 | echo 199 | echo 200 | echo "Enabling site $DOMAIN, restarting apache" 201 | echo "--------------------------------------------------------------" 202 | # 203 | a2ensite $DOMAIN 204 | /etc/init.d/apache2 graceful 205 | # 206 | 207 | --------------------------------------------------------------------------------