├── .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 |
--------------------------------------------------------------------------------