Secure shared web hosting on Ubuntu Server, part 2
Continuing from part 1, here are the nuts and bolts:
Ubuntu 8.10 Server
For each domain, create a virtual host config like /etc/apache2/sites-available/example.com:
ServerAdmin webmaster@example.com
ServerName example.com
ServerAlias www.example.com
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
<Proxy *>
Allow from all
</Proxy>
ErrorLog /var/www/example.com/logs/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/www/example.com/logs/access.log combined
</VirtualHost>
This will be used by the Apache proxy, which is the normal system apache2 running as the default “www-data” user. This proxy handles name-based virtual hosts, and proxies the requests to a second process, running at localhost on port 8080.
Note that the logs are configured here and not in the user’s Apache process, for two reasons:
- keep logs pristine in the event of a break-in on a user site (for example via a buggy or malicious PHP script)
- single system-wide log file analysis process instead of per-user
Next, create a user account for each domain:
root@theo:~# cd /var/www/example.com/
root@theo:/var/www/example.com# useradd -d `pwd`/htdocs example.com
root@theo:/var/www/example.com# mkdir htdocs logs conf
root@theo:/var/www/example.com# chown www-data:www-data logs
root@theo:/var/www/example.com# chown example.com:example.com htdocs/
Create the following in /var/www/example.com/conf/apache2.conf:
RequestHeader set Host example.com
LockFile /var/www/example.com/conf/accept.lock
PidFile /conf/apache2.pid
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
User example.com
Group example.com
AccessFileName .htaccess
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
DefaultType text/plain
HostnameLookups Off
ErrorLog /var/www/example.com/conf/error.log
LogLevel warn
LoadFile /lib/libnss_dns.so.2
LoadModule chroot_module /usr/lib/apache2/modules/mod_chroot.so
Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
Listen 8080
DocumentRoot /htdocs
ChrootDir /var/www/example.com/
Start up the user Apache process:
Everything should now work, but you may notice some problems with PHP or CGI scripts. Generally this means that you will need to make parts of the system available in the chroot; however making copies takes up a lot of space and can quickly get out of date, which is a security risk.
One workaround is to provide needed directories using the “mount -o bind” option, which will remount an existing, mounted part of the file hierarchy somewhere else. For example, this will provide all of “/usr” inside the chroot:
root@theo:~# mount -o bind,ro /usr /var/www/example.com/usr
PHP sessions require /tmp to exist inside the chroot; there is no benefit to sharing this one, an empty directory is fine.
That’s pretty much it! Testing, getting startup right etc. is left as an exercise for the reader, since we’re venturing a bit out of the standard Ubuntu Apache setup. Entries in /etc/fstab and creating an init script to handle user Apache processes is probably the best way to go.
In part 3 we’ll cover take a more general look at the pros and cons to this setup, as well as possible future directions.
UPDATE link to secure shared hosting on ubuntu server part 3
EDIT 2009-Oct-03 2:25 PM Pacific – create dir before cding into it; add read-only (ro) option to usr mount; override “host” header in user Apache process
EDIT 2009-Oct-05 4:41 PM Pacific – load resolver library and install caching proxy dns server, needed by popular wordpress anti-spam plugin Akismet
October 8th, 2009 at 4:16 pm
[...] « Secure shared web hosting on Ubuntu Server, part 2 centralized logging with syslog-ng [...]
March 18th, 2010 at 2:03 pm
[...] one of my earlier posts about web hosting with Ubuntu Server, I left the startup script for the user-owned Apache instances [...]
April 9th, 2010 at 8:31 pm
[...] « AnyHosting launched! Secure shared web hosting on Ubuntu Server, part 2 [...]