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 numbersKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free