DB-유

Apache Virtual Hosts on Ubuntu 16.04

· linux, apache, ubuntu

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.conf containing ServerName 203.0.113.40, then sudo a2enconf servername and reload.
  • Both hostnames show the same site. Usually a typo in ServerName, or the second .conf was never enabled. apache2ctl -S shows what Apache thinks it is serving.
  • Forbidden. You don't have permission to access / on this server. Either the <Directory> block is missing Require all granted (Apache 2.4 syntax; the old Allow from all no longer works), or a directory in the path lacks execute permission for www-data.
  • .htaccess rules are ignored. AllowOverride is still None, or mod_rewrite is not enabled. Check with apache2ctl -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.