Apache Virtual Hosts on Ubuntu 16.04
I used to edit one giant 000-default.conf for every site on a server, and it always ended in a broken config and an unhappy reload. Now each site gets its own file and its own logs. Here's how I set up two name-based virtual hosts on Ubuntu 16.04 (Apache 2.4.18). Same layout works for a single site too.
You need sudo, and two hostnames pointing at the server, or hosts file entries on your workstation. I'll use site1.example.com and site2.example.com.
Install Apache
sudo apt-get update
sudo apt-get install -y apache2
sudo ufw allow 'Apache Full'
Check that the default page is served: curl -I http://203.0.113.40 should return HTTP/1.1 200 OK and Server: Apache/2.4.18 (Ubuntu).
Document roots
Ubuntu's default DocumentRoot is /var/www/html. I put each site in its own directory next to it, owned by my deploy user so I can upload without sudo. Apache only needs read access.
sudo mkdir -p /var/www/site1.example.com/public_html
sudo mkdir -p /var/www/site2.example.com/public_html
sudo chown -R $USER:$USER /var/www/site1.example.com /var/www/site2.example.com
sudo chmod -R 755 /var/www
Add a placeholder page to each so you can tell them apart:
echo '<h1>site1 works</h1>' > /var/www/site1.example.com/public_html/index.html
echo '<h1>site2 works</h1>' > /var/www/site2.example.com/public_html/index.html
One virtual host file per site
Ubuntu keeps available sites in /etc/apache2/sites-available/ and symlinks the active ones into /etc/apache2/sites-enabled/. Start from the shipped default and adjust:
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/site1.example.com.conf
sudo nano /etc/apache2/sites-available/site1.example.com.conf
Make it look like this:
<VirtualHost *:80>
ServerName site1.example.com
ServerAlias www.site1.example.com
ServerAdmin webmaster@example.com
DocumentRoot /var/www/site1.example.com/public_html
<Directory /var/www/site1.example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/site1.example.com-error.log
CustomLog ${APACHE_LOG_DIR}/site1.example.com-access.log combined
</VirtualHost>
Repeat for site2.example.com.conf, changing the names and paths. AllowOverride All lets .htaccess files work, which most PHP applications expect; I leave it at None when a site doesn't need .htaccess, since it's slightly faster and one less thing to debug.
Enable and reload
sudo a2ensite site1.example.com.conf
sudo a2ensite site2.example.com.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
a2ensite just creates the symlink in sites-enabled. I never reload without configtest printing Syntax OK first.
If you want clean URLs for applications such as WordPress, enable mod_rewrite as well:
sudo a2enmod rewrite
sudo systemctl restart apache2
Point the names at the server
For a public site, create A records for site1.example.com and site2.example.com. For local testing, add lines to /etc/hosts on your workstation (or C:\Windows\System32\drivers\etc\hosts on Windows):
203.0.113.40 site1.example.com
203.0.113.40 site2.example.com
Testing
curl -H 'Host: site1.example.com' http://203.0.113.40/
curl -H 'Host: site2.example.com' http://203.0.113.40/
Each should return its own placeholder. To see how Apache resolved the virtual hosts and which one is the default (the first loaded alphabetically), run:
sudo apache2ctl -S
The output lists each port 80 namevhost with the file and line it came from.
Common annoyances
AH00558: apache2: Could not reliably determine the server's fully qualified domain name. Harmless, but noisy. Create/etc/apache2/conf-available/servername.confcontainingServerName 203.0.113.40, thensudo a2enconf servernameand reload.- Both hostnames show the same site. Usually a typo in
ServerName, or the second.confwas never enabled.apache2ctl -Sshows what Apache thinks it is serving. Forbidden. You don't have permission to access / on this server.Either the<Directory>block is missingRequire all granted(Apache 2.4 syntax; the oldAllow from allno longer works), or a directory in the path lacks execute permission forwww-data..htaccessrules are ignored.AllowOverrideis stillNone, ormod_rewriteis not enabled. Check withapache2ctl -M | grep rewrite.
Adding a third or tenth site is copy, edit three lines, a2ensite. TLS later is just another <VirtualHost *:443> block in the same file.