Apache
02 / 07

Virtual Hosts & SSL

Virtual Hosts & SSL

Virtual hosts let a single Apache server serve multiple domains. SSL/TLS via mod_ssl enables HTTPS. Combining both is the standard setup for any production server.

Name-Based Virtual Hosts

# /etc/apache2/sites-available/example.com.conf

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/public
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

    <Directory /var/www/example.com/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

# Enable the site and reload
sudo a2ensite example.com.conf
sudo systemctl reload apache2

# Disable a site
sudo a2dissite 000-default.conf

# The default catch-all vhost (first match wins by filename order)
# Sites are loaded alphabetically — prefix with numbers to control order:
# 000-default.conf, 010-example.com.conf, 020-api.example.com.conf

# IP-based virtual host (different IPs, same server)
<VirtualHost 192.168.1.10:80>
    ServerName site-a.example.com
    DocumentRoot /var/www/site-a
</VirtualHost>

<VirtualHost 192.168.1.11:80>
    ServerName site-b.example.com
    DocumentRoot /var/www/site-b
</VirtualHost>

SSL/TLS with mod_ssl

# Enable mod_ssl (Ubuntu/Debian)
sudo a2enmod ssl
sudo systemctl restart apache2

# Obtain a free certificate via Certbot (Let's Encrypt)
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d example.com -d www.example.com
# Certbot will create and configure the SSL vhost automatically

# Manual SSL VirtualHost at port 443
<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example.com/public

    SSLEngine on
    SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem

    # Modern TLS settings (Mozilla Intermediate compatibility)
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder     off
    SSLSessionTickets       off

    # HSTS — tell browsers to always use HTTPS
    Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>

# HTTP → HTTPS redirect
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine on
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

HTTP/2 & Certificate Renewal

# Enable HTTP/2 (requires event or worker MPM, not prefork)
sudo a2enmod http2
# Add to global config or per-vhost
Protocols h2 http/1.1

# Verify HTTP/2 is active
curl -I --http2 https://example.com
# Look for: HTTP/2 200

# Auto-renew Let's Encrypt certs (Certbot sets up a systemd timer)
sudo systemctl status certbot.timer
# Manual renew dry run
sudo certbot renew --dry-run
# Force renew
sudo certbot renew --force-renewal -d example.com

# Test SSL configuration online
# Run: openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -dates
# Shows certificate valid dates

# Check which sites are enabled
ls /etc/apache2/sites-enabled/
apachectl -S   # Full parsed virtual host summary with config file + line numbers

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free