Implementing SSL/TLS on Apache is crucial for securing web communications. This guide will walk you through setting up a properly configured, secure Apache server with SSL/TLS on Alpine Linux, including certificate management and security hardening.
Table of Contents
- Prerequisites
- Understanding SSL/TLS
- Installing Apache and SSL Module
- Generating SSL Certificates
- Configuring Apache for SSL
- Security Hardening
- Let’s Encrypt Integration
- Virtual Hosts with SSL
- HTTP to HTTPS Redirection
- Performance Optimization
- Certificate Management
- Monitoring and Testing
- Troubleshooting
- Best Practices
- Conclusion
Prerequisites
Before starting, ensure you have:
- Alpine Linux with root access
- Domain name pointing to your server
- Basic understanding of Apache configuration
- Port 80 and 443 open in firewall
- At least 512MB RAM
- Valid email for certificate registration
Understanding SSL/TLS
SSL/TLS Components
# Check OpenSSL version
openssl version -a
# List available ciphers
openssl ciphers -v
Key concepts:
- Certificate: Proves server identity
- Private Key: Secret key for encryption
- Certificate Authority: Validates certificates
- Cipher Suite: Encryption algorithms
Installing Apache and SSL Module
Step 1: Install Apache
# Update package repository
apk update
# Install Apache
apk add apache2
# Install SSL/TLS module
apk add apache2-ssl
# Install OpenSSL tools
apk add openssl openssl-dev
# Enable Apache service
rc-update add apache2 default
# Start Apache
rc-service apache2 start
Step 2: Enable SSL Module
# Load SSL module
sed -i 's/#LoadModule ssl_module/LoadModule ssl_module/' /etc/apache2/httpd.conf
sed -i 's/#LoadModule socache_shmcb_module/LoadModule socache_shmcb_module/' /etc/apache2/httpd.conf
# Include SSL configuration
echo "Include /etc/apache2/conf.d/ssl.conf" >> /etc/apache2/httpd.conf
# Test configuration
apachectl configtest
Generating SSL Certificates
Step 1: Create Self-Signed Certificate (Development)
# Create certificate directory
mkdir -p /etc/apache2/ssl
cd /etc/apache2/ssl
# Generate private key
openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:4096
# Generate certificate signing request
openssl req -new -key server.key -out server.csr -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"
# Generate self-signed certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# Set proper permissions
chmod 600 server.key
chmod 644 server.crt
Step 2: Generate Strong Diffie-Hellman Parameters
# Generate DH parameters (this takes time)
openssl dhparam -out /etc/apache2/ssl/dhparam.pem 4096
# Set permissions
chmod 644 /etc/apache2/ssl/dhparam.pem
Configuring Apache for SSL
Step 1: Create SSL Configuration
# Create SSL virtual host configuration
cat > /etc/apache2/conf.d/ssl-site.conf << 'EOF'
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/localhost/htdocs
# Enable SSL
SSLEngine on
# Certificate files
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
# SSL Protocol Support
SSLProtocol -all +TLSv1.2 +TLSv1.3
# SSL Cipher Suite
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# Honor server cipher order
SSLHonorCipherOrder on
# SSL Compression
SSLCompression off
# OCSP Stapling
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
# SSL Session Cache
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
# Security headers
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "no-referrer-when-downgrade"
# Logging
ErrorLog /var/log/apache2/ssl_error.log
CustomLog /var/log/apache2/ssl_access.log combined
</VirtualHost>
# OCSP Stapling Cache
SSLStaplingCache shmcb:/var/run/ocsp(128000)
EOF
Step 2: Configure SSL Parameters
# Create global SSL configuration
cat > /etc/apache2/conf.d/ssl.conf << 'EOF'
# SSL/TLS Strong Encryption Configuration
# Pseudo Random Number Generator (PRNG)
SSLRandomSeed startup builtin
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect builtin
SSLRandomSeed connect file:/dev/urandom 512
# Enable session cache
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
# Mutex for SSL
Mutex default
# Pass phrase dialog
SSLPassPhraseDialog builtin
# Inter-process SSL session cache
SSLSessionCache shmcb:/var/run/ssl_scache(512000)
SSLSessionCacheTimeout 300
# SSL Crypto Device
SSLCryptoDevice builtin
EOF
Security Hardening
Step 1: Disable Weak Protocols and Ciphers
# Update SSL configuration for security
cat > /etc/apache2/conf.d/ssl-hardening.conf << 'EOF'
# Disable SSL v2 and v3
SSLProtocol -all +TLSv1.2 +TLSv1.3
# Modern cipher suite (Mozilla Intermediate)
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# Prefer server cipher order
SSLHonorCipherOrder on
# Disable compression (CRIME attack)
SSLCompression off
# OCSP Stapling
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
# Session tickets off (for Perfect Forward Secrecy)
SSLSessionTickets off
EOF
Step 2: Implement Security Headers
# Enable headers module
sed -i 's/#LoadModule headers_module/LoadModule headers_module/' /etc/apache2/httpd.conf
# Create security headers configuration
cat > /etc/apache2/conf.d/security-headers.conf << 'EOF'
# Security Headers Configuration
# HSTS (2 years)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Prevent clickjacking
Header always set X-Frame-Options "DENY"
# Prevent MIME type sniffing
Header always set X-Content-Type-Options "nosniff"
# XSS Protection
Header always set X-XSS-Protection "1; mode=block"
# Referrer Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Content Security Policy
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
# Remove server version
ServerTokens Prod
ServerSignature Off
EOF
Let’s Encrypt Integration
Step 1: Install Certbot
# Install certbot and Apache plugin
apk add certbot certbot-apache
# Create webroot directory
mkdir -p /var/www/certbot
Step 2: Obtain Let’s Encrypt Certificate
# Stop Apache temporarily
rc-service apache2 stop
# Obtain certificate (standalone mode)
certbot certonly --standalone \
--email [email protected] \
--agree-tos \
--no-eff-email \
-d example.com \
-d www.example.com
# Start Apache
rc-service apache2 start
# For webroot mode (Apache running)
certbot certonly --webroot \
-w /var/www/localhost/htdocs \
-d example.com \
-d www.example.com
Step 3: Configure Apache with Let’s Encrypt
# Update SSL configuration for Let's Encrypt
cat > /etc/apache2/conf.d/letsencrypt-site.conf << 'EOF'
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/localhost/htdocs
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# Include security configuration
Include /etc/apache2/conf.d/ssl-hardening.conf
Include /etc/apache2/conf.d/security-headers.conf
# Logging
ErrorLog /var/log/apache2/ssl_error.log
CustomLog /var/log/apache2/ssl_access.log combined
</VirtualHost>
EOF
Step 4: Auto-renewal Setup
# Create renewal script
cat > /etc/periodic/daily/certbot-renew << 'EOF'
#!/bin/sh
# Renew Let's Encrypt certificates
/usr/bin/certbot renew --quiet --no-self-upgrade --post-hook "rc-service apache2 reload"
EOF
chmod +x /etc/periodic/daily/certbot-renew
# Test renewal
certbot renew --dry-run
Virtual Hosts with SSL
Multiple SSL Sites
# Create multiple SSL virtual hosts
cat > /etc/apache2/conf.d/multi-ssl-sites.conf << 'EOF'
# Site 1
<VirtualHost *:443>
ServerName site1.example.com
DocumentRoot /var/www/site1
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/site1.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site1.example.com/privkey.pem
Include /etc/apache2/conf.d/ssl-hardening.conf
</VirtualHost>
# Site 2
<VirtualHost *:443>
ServerName site2.example.com
DocumentRoot /var/www/site2
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/site2.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site2.example.com/privkey.pem
Include /etc/apache2/conf.d/ssl-hardening.conf
</VirtualHost>
EOF
SNI (Server Name Indication) Configuration
# Enable SNI
cat >> /etc/apache2/conf.d/ssl.conf << 'EOF'
# SNI Configuration
SSLStrictSNIVHostCheck off
EOF
HTTP to HTTPS Redirection
Step 1: Configure Redirect
# Create HTTP to HTTPS redirect
cat > /etc/apache2/conf.d/http-redirect.conf << 'EOF'
# Redirect all HTTP to HTTPS
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# Redirect to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
# Alternative method
# Redirect permanent / https://example.com/
</VirtualHost>
EOF
# Enable rewrite module
sed -i 's/#LoadModule rewrite_module/LoadModule rewrite_module/' /etc/apache2/httpd.conf
Step 2: HSTS Preload
# Configure HSTS preload
cat > /etc/apache2/conf.d/hsts-preload.conf << 'EOF'
# HSTS Preload Configuration
<IfModule mod_headers.c>
# Only on HTTPS connections
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" env=HTTPS
</IfModule>
EOF
Performance Optimization
Step 1: SSL Session Cache
# Optimize SSL session cache
cat > /etc/apache2/conf.d/ssl-performance.conf << 'EOF'
# SSL Performance Optimization
# Session cache
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 600
# OCSP stapling cache
SSLStaplingCache shmcb:/var/run/ocsp(128000)
SSLStaplingStandardCacheTimeout 3600
SSLStaplingErrorCacheTimeout 600
# Keep-alive settings
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
# Enable HTTP/2
Protocols h2 http/1.1
EOF
# Enable HTTP/2 module
apk add apache2-http2
sed -i 's/#LoadModule http2_module/LoadModule http2_module/' /etc/apache2/httpd.conf
Step 2: Cipher Optimization
# Benchmark cipher performance
openssl speed -evp aes-128-gcm aes-256-gcm chacha20-poly1305
# Configure optimal cipher order based on hardware
cat > /etc/apache2/conf.d/cipher-optimization.conf << 'EOF'
# Hardware-optimized cipher suite
# Prefer AES-NI if available
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
EOF
Certificate Management
Step 1: Certificate Monitoring
# Create certificate expiry check script
cat > /usr/local/bin/check-ssl-expiry << 'EOF'
#!/bin/sh
# Check SSL certificate expiry
DOMAIN=${1:-example.com}
PORT=${2:-443}
echo "Checking SSL certificate for $DOMAIN:$PORT"
# Get certificate expiry
EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:$PORT" 2>/dev/null | openssl x509 -noout -dates | grep notAfter | cut -d= -f2)
if [ -n "$EXPIRY" ]; then
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
echo "Certificate expires: $EXPIRY"
echo "Days remaining: $DAYS_LEFT"
if [ $DAYS_LEFT -lt 30 ]; then
echo "WARNING: Certificate expires in less than 30 days!"
fi
else
echo "ERROR: Could not retrieve certificate"
fi
EOF
chmod +x /usr/local/bin/check-ssl-expiry
Step 2: Certificate Backup
# Create certificate backup script
cat > /usr/local/bin/backup-ssl-certs << 'EOF'
#!/bin/sh
# Backup SSL certificates
BACKUP_DIR="/var/backups/ssl"
DATE=$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
# Backup Let's Encrypt certificates
if [ -d /etc/letsencrypt ]; then
tar -czf "$BACKUP_DIR/letsencrypt-$DATE.tar.gz" /etc/letsencrypt
fi
# Backup Apache SSL certificates
if [ -d /etc/apache2/ssl ]; then
tar -czf "$BACKUP_DIR/apache-ssl-$DATE.tar.gz" /etc/apache2/ssl
fi
# Remove old backups (keep last 30 days)
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete
echo "SSL certificate backup completed"
EOF
chmod +x /usr/local/bin/backup-ssl-certs
# Add to cron
echo "0 2 * * * /usr/local/bin/backup-ssl-certs" | crontab -
Monitoring and Testing
Step 1: SSL Testing Tools
# Install SSL testing tools
apk add nmap testssl.sh
# Create SSL test script
cat > /usr/local/bin/test-ssl-config << 'EOF'
#!/bin/sh
# Test SSL configuration
DOMAIN=${1:-localhost}
echo "Testing SSL configuration for $DOMAIN"
echo "================================"
# Test with OpenSSL
echo -e "\n1. OpenSSL connection test:"
echo | openssl s_client -connect "$DOMAIN:443" -servername "$DOMAIN" 2>/dev/null | grep "Verify return code"
# Test protocols
echo -e "\n2. Protocol support:"
for proto in ssl2 ssl3 tls1 tls1_1 tls1_2 tls1_3; do
echo -n "Testing $proto: "
if echo | openssl s_client -connect "$DOMAIN:443" -servername "$DOMAIN" -$proto 2>/dev/null | grep -q "CONNECTED"; then
echo "SUPPORTED"
else
echo "NOT SUPPORTED"
fi
done
# Test ciphers
echo -e "\n3. Cipher strength:"
nmap --script ssl-enum-ciphers -p 443 "$DOMAIN" | grep -A 5 "least strength"
# Test headers
echo -e "\n4. Security headers:"
curl -s -I "https://$DOMAIN" | grep -E "(Strict-Transport-Security|X-Frame-Options|X-Content-Type-Options|X-XSS-Protection)"
EOF
chmod +x /usr/local/bin/test-ssl-config
Step 2: Monitoring Integration
# Create Nagios/Icinga check script
cat > /usr/local/bin/check_ssl_cert << 'EOF'
#!/bin/sh
# Nagios plugin for SSL certificate monitoring
DOMAIN=$1
WARNING_DAYS=${2:-30}
CRITICAL_DAYS=${3:-7}
if [ -z "$DOMAIN" ]; then
echo "UNKNOWN: No domain specified"
exit 3
fi
# Get days until expiry
EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | openssl x509 -noout -dates | grep notAfter | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt $CRITICAL_DAYS ]; then
echo "CRITICAL: Certificate expires in $DAYS_LEFT days"
exit 2
elif [ $DAYS_LEFT -lt $WARNING_DAYS ]; then
echo "WARNING: Certificate expires in $DAYS_LEFT days"
exit 1
else
echo "OK: Certificate valid for $DAYS_LEFT days"
exit 0
fi
EOF
chmod +x /usr/local/bin/check_ssl_cert
Troubleshooting
Common Issues
- Certificate chain issues:
# Verify certificate chain
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/apache2/ssl/server.crt
# Check certificate details
openssl x509 -in /etc/apache2/ssl/server.crt -text -noout
- SSL handshake failures:
# Debug SSL handshake
openssl s_client -connect localhost:443 -debug
# Check Apache SSL error log
tail -f /var/log/apache2/ssl_error.log
- Mixed content warnings:
# Find non-HTTPS resources
grep -r "http://" /var/www/localhost/htdocs/ | grep -v "https://"
# Update to protocol-relative URLs
# Change: http://example.com/resource
# To: //example.com/resource
Debug Mode
# Enable SSL debug logging
cat >> /etc/apache2/conf.d/ssl.conf << 'EOF'
# SSL Debug Logging
LogLevel ssl:debug
EOF
# Restart Apache
rc-service apache2 restart
# Monitor debug log
tail -f /var/log/apache2/error.log | grep SSL
Best Practices
Security Checklist
# Create security audit script
cat > /usr/local/bin/ssl-security-audit << 'EOF'
#!/bin/sh
# SSL Security Audit
echo "Apache SSL Security Audit"
echo "========================"
# Check SSL protocols
echo -e "\n[+] Checking SSL protocols..."
grep -h "SSLProtocol" /etc/apache2/conf.d/*.conf
# Check cipher suites
echo -e "\n[+] Checking cipher suites..."
grep -h "SSLCipherSuite" /etc/apache2/conf.d/*.conf
# Check security headers
echo -e "\n[+] Checking security headers..."
grep -h "Header.*Strict-Transport-Security" /etc/apache2/conf.d/*.conf
# Check certificate permissions
echo -e "\n[+] Checking certificate permissions..."
find /etc/apache2/ssl -name "*.key" -exec ls -l {} \;
# Check OCSP stapling
echo -e "\n[+] Checking OCSP stapling..."
grep -h "SSLUseStapling" /etc/apache2/conf.d/*.conf
echo -e "\n[+] Audit complete"
EOF
chmod +x /usr/local/bin/ssl-security-audit
Maintenance Tasks
# Create maintenance script
cat > /etc/periodic/weekly/ssl-maintenance << 'EOF'
#!/bin/sh
# Weekly SSL maintenance
# Check certificate expiry
/usr/local/bin/check-ssl-expiry
# Backup certificates
/usr/local/bin/backup-ssl-certs
# Run security audit
/usr/local/bin/ssl-security-audit > /var/log/ssl-audit.log
# Test SSL configuration
/usr/local/bin/test-ssl-config > /var/log/ssl-test.log
EOF
chmod +x /etc/periodic/weekly/ssl-maintenance
Conclusion
You’ve successfully configured Apache with SSL/TLS on Alpine Linux, implementing industry-standard security practices. Your server now provides encrypted communications with strong cipher suites, security headers, and automated certificate management. Regular monitoring and maintenance will ensure your SSL configuration remains secure and performant.
Remember to stay updated with the latest security recommendations, regularly test your SSL configuration, and keep your certificates renewed. With this setup, your Apache server is ready for production use with enterprise-grade security.