Apache Virtual Hosts SSL Overview
Setting up SSL for Apache virtual hosts on your Ubuntu VPS requires coordinating domain configuration, certificate management, and security headers. This tutorial walks through securing multiple sites with Let's Encrypt certificates while maintaining proper isolation between virtual hosts.
You'll configure SSL for each virtual host individually. You'll automate certificate renewal. You'll implement security headers that protect your sites from common vulnerabilities.
Prerequisites and System Requirements
Your Ubuntu VPS needs Apache 2.4 or later with SSL module enabled. Verify your setup before starting:
apache2ctl -v
sudo a2enmod ssl
sudo a2enmod headers
sudo systemctl restart apache2
Each domain requires DNS A records pointing to your VPS IP address. Let's Encrypt validates domain ownership during certificate issuance. DNS propagation must complete before proceeding.
Install the Certbot client for Let's Encrypt certificate management:
sudo apt update
sudo apt install certbot python3-certbot-apache
For hosting providers managing multiple client sites, Hostperl VPS hosting provides the flexibility and control needed for complex Apache configurations.
Configure Base Virtual Host Structure
Create organized directory structure for your virtual hosts:
sudo mkdir -p /var/www/example.com/public_html
sudo mkdir -p /var/www/testsite.com/public_html
sudo chown -R www-data:www-data /var/www/
Set up the primary virtual host configuration in /etc/apache2/sites-available/example.com.conf:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
<Directory /var/www/example.com/public_html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Enable the site and test your configuration:
sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Repeat this process for each domain you plan to secure with SSL.
Generate Let's Encrypt SSL Certificates
Obtain SSL certificates for your first virtual host:
sudo certbot --apache -d example.com -d www.example.com
Certbot automatically modifies your Apache configuration to include SSL settings. The tool creates a new virtual host block listening on port 443. It redirects HTTP traffic to HTTPS.
For multiple domains, run separate Certbot commands:
sudo certbot --apache -d testsite.com -d www.testsite.com
sudo certbot --apache -d clientsite.com -d www.clientsite.com
This approach maintains separate certificates for each domain. It improves security isolation and management flexibility.
Verify certificate installation by checking the modified configuration file:
sudo cat /etc/apache2/sites-available/example.com-le-ssl.conf
Customize Virtual Host SSL Configuration
Edit the SSL virtual host to add security headers and optimize performance. Open /etc/apache2/sites-available/example.com-le-ssl.conf:
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
# Security Headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Logging
ErrorLog ${APACHE_LOG_DIR}/example.com_ssl_error.log
CustomLog ${APACHE_LOG_DIR}/example.com_ssl_access.log combined
<Directory /var/www/example.com/public_html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Test the configuration and reload Apache:
sudo apache2ctl configtest
sudo systemctl reload apache2
For more detailed guidance on setting up Apache virtual hosts, check our comprehensive multi-site tutorial.
Implement Automatic Certificate Renewal
Let's Encrypt certificates expire after 90 days. Set up automatic renewal to prevent service interruptions:
sudo crontab -e
Add this line to run renewal checks twice daily:
0 2,14 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload apache2"
Test the renewal process manually:
sudo certbot renew --dry-run
This command simulates renewal without making changes. Successful output confirms your renewal setup works correctly.
Monitor renewal logs in /var/log/letsencrypt/letsencrypt.log to catch any issues early.
Configure SSL Security Settings
Enhance SSL security by customizing /etc/letsencrypt/options-ssl-apache.conf:
# Modern configuration
SSLEngine on
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder off
SSLSessionTickets off
Add OCSP stapling for improved performance:
SSLUseStapling On
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
Test SSL configuration strength using online tools like SSL Labs' server test. Aim for an A+ rating by implementing all recommended security measures.
Handle Mixed Content and Redirects
Ensure all HTTP traffic redirects to HTTPS. Certbot usually adds redirect rules, but verify they're working:
curl -I http://example.com
Look for a 301 redirect to the HTTPS version. If missing, add redirect rules to your HTTP virtual host:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
For applications with mixed content issues, add Content Security Policy headers:
Header always set Content-Security-Policy "upgrade-insecure-requests;"
This header instructs browsers to automatically upgrade HTTP requests to HTTPS.
Monitor SSL Certificate Status
Create a monitoring script to check certificate expiration dates:
#!/bin/bash
# ssl-check.sh
for domain in example.com testsite.com clientsite.com; do
expiry=$(echo | openssl s_client -servername $domain -connect $domain:443 2>/dev/null | openssl x509 -noout -dates | grep notAfter | cut -d= -f2)
echo "$domain expires: $expiry"
done
Run this script weekly to verify all certificates remain valid. For comprehensive VPS server monitoring, consider implementing automated health checks.
Set up log rotation for SSL-specific logs to prevent disk space issues:
sudo nano /etc/logrotate.d/apache2-ssl
/var/log/apache2/*ssl*.log {
weekly
missingok
rotate 4
compress
delaycompress
notifempty
postrotate
/bin/systemctl reload apache2 > /dev/null 2>&1 || true
endscript
}
Frequently Asked Questions
Can I use wildcard certificates for Apache virtual hosts SSL?
Yes, wildcard certificates work with virtual hosts. They require DNS validation instead of HTTP validation. Use certbot --apache --preferred-challenges dns -d *.example.com and manually add DNS TXT records during the process.
What happens if SSL certificate renewal fails?
Failed renewals typically result from DNS changes, firewall issues, or Apache configuration problems. Check /var/log/letsencrypt/letsencrypt.log for specific error messages. Verify domain accessibility before re-running renewal.
How do I add SSL to an existing virtual host?
Run sudo certbot --apache -d yourdomain.com on any existing HTTP virtual host. Certbot automatically creates the SSL version and configures redirects without disrupting the existing site.
Should each virtual host have separate SSL certificates?
Separate certificates provide better security isolation and management flexibility. However, you can use Subject Alternative Name (SAN) certificates for multiple related domains if preferred.
How do I troubleshoot mixed content warnings?
Use browser developer tools to identify HTTP resources on HTTPS pages. Update hardcoded HTTP links in your application code. Or implement Content Security Policy headers to automatically upgrade insecure requests.

