Let me show you how to set up SSL/TLS certificates with Nginx on Alpine Linux! This will secure your website with HTTPS, protecting your visitorsโ data. Think of it as adding a lock to your websiteโs front door!
๐ค What is SSL/TLS?
SSL/TLS creates an encrypted connection between your website and visitors. Itโs like a secure tunnel that protects data as it travels. When you see the padlock icon in your browser, thatโs SSL/TLS at work! It keeps passwords, credit cards, and personal info safe from hackers.
Why use SSL/TLS?
- Encrypt sensitive data
- Build visitor trust
- Improve SEO rankings
- Enable modern features
- Meet security requirements
๐ฏ What You Need
Before starting, youโll need:
- Alpine Linux installed
- Nginx web server running
- Domain name (optional)
- Root access
- About 20 minutes
๐ Step 1: Install Required Tools
First, letโs get everything we need:
# Update packages
apk update
# Install Nginx if not already installed
apk add nginx
# Install OpenSSL for certificates
apk add openssl
# Install Certbot for Let's Encrypt
apk add certbot certbot-nginx
# Start Nginx
rc-service nginx start
rc-update add nginx
# Check Nginx is running
nginx -t
ps aux | grep nginx
๐ Step 2: Create Self-Signed Certificate
Letโs start with a self-signed certificate for testing:
# Create certificate directory
mkdir -p /etc/nginx/ssl
cd /etc/nginx/ssl
# Generate private key
openssl genrsa -out server.key 2048
# Create certificate signing request
openssl req -new -key server.key -out server.csr \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
# Generate self-signed certificate
openssl x509 -req -days 365 -in server.csr \
-signkey server.key -out server.crt
# Create Diffie-Hellman parameters
openssl dhparam -out dhparam.pem 2048
# Set permissions
chmod 600 server.key
chmod 644 server.crt dhparam.pem
# List certificates
ls -la /etc/nginx/ssl/
๐ Step 3: Configure Nginx for SSL
Now configure Nginx to use SSL:
# Backup original config
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
# Create SSL server block
cat > /etc/nginx/conf.d/ssl-site.conf << 'EOF'
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name localhost;
# SSL Certificate files
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# SSL Configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Diffie-Hellman parameters
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Document root
root /var/www/localhost/htdocs;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
# Logging
access_log /var/log/nginx/ssl-access.log;
error_log /var/log/nginx/ssl-error.log;
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name localhost;
return 301 https://$server_name$request_uri;
}
EOF
# Test configuration
nginx -t
# Reload Nginx
rc-service nginx reload
๐ Step 4: Get Letโs Encrypt Certificate
For a real domain, use Letโs Encrypt:
# Stop Nginx temporarily
rc-service nginx stop
# Get certificate (replace example.com with your domain)
certbot certonly --standalone -d example.com -d www.example.com \
--agree-tos --non-interactive --email [email protected]
# Start Nginx
rc-service nginx start
# Update Nginx config for Let's Encrypt
cat > /etc/nginx/conf.d/letsencrypt-site.conf << 'EOF'
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# Let's Encrypt certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Strong SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
EOF
# Set up auto-renewal
echo "0 0,12 * * * root certbot renew --quiet --post-hook 'rc-service nginx reload'" \
>> /etc/crontab
๐ Step 5: Test SSL Configuration
Verify everything works:
# Test with curl
curl -I https://localhost -k
# Check certificate details
openssl s_client -connect localhost:443 -servername localhost
# Test SSL protocols
openssl s_client -connect localhost:443 -tls1_2
openssl s_client -connect localhost:443 -tls1_3
# Check certificate expiration
echo | openssl s_client -connect localhost:443 2>/dev/null | \
openssl x509 -noout -dates
# Test cipher suites
openssl s_client -connect localhost:443 -cipher 'ECDHE-RSA-AES256-GCM-SHA384'
# Check HTTP/2 support
curl -I --http2 https://localhost -k | grep HTTP
๐ Step 6: Advanced SSL Settings
Optimize your SSL configuration:
# Enable OCSP stapling for self-signed
cat >> /etc/nginx/conf.d/ssl-site.conf << 'EOF'
# OCSP Stapling (if using CA-signed cert)
# ssl_stapling on;
# ssl_stapling_verify on;
# resolver 8.8.8.8 8.8.4.4 valid=300s;
# resolver_timeout 5s;
EOF
# Create custom error pages
mkdir -p /var/www/errors
cat > /var/www/errors/502.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>502 Bad Gateway</title>
<style>
body { font-family: Arial; text-align: center; padding: 50px; }
h1 { color: #e74c3c; }
</style>
</head>
<body>
<h1>502 Bad Gateway</h1>
<p>The server is temporarily unable to service your request.</p>
</body>
</html>
EOF
# Add error page to config
echo "error_page 502 /errors/502.html;" >> /etc/nginx/conf.d/ssl-site.conf
echo "location /errors/ { internal; root /var/www; }" >> /etc/nginx/conf.d/ssl-site.conf
๐ Step 7: Monitor SSL Status
Create monitoring tools:
# SSL certificate checker script
cat > /usr/local/bin/check-ssl.sh << 'EOF'
#!/bin/sh
# Check SSL Certificate Status
DOMAIN="${1:-localhost}"
PORT="${2:-443}"
echo "๐ SSL Certificate Check for $DOMAIN:$PORT"
echo "======================================"
# Get certificate info
CERT_INFO=$(echo | openssl s_client -connect $DOMAIN:$PORT -servername $DOMAIN 2>/dev/null)
if [ $? -eq 0 ]; then
# Extract certificate
echo "$CERT_INFO" | openssl x509 -noout -text > /tmp/cert.txt
# Show issuer
echo "๐ Issuer:"
grep "Issuer:" /tmp/cert.txt | sed 's/^[ \t]*/ /'
# Show subject
echo "๐ Subject:"
grep "Subject:" /tmp/cert.txt | sed 's/^[ \t]*/ /'
# Show validity
echo "๐ Validity:"
echo "$CERT_INFO" | openssl x509 -noout -dates | sed 's/^/ /'
# Check expiration
EXPIRE_DATE=$(echo "$CERT_INFO" | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRE_EPOCH=$(date -d "$EXPIRE_DATE" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$EXPIRE_DATE" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRE_EPOCH - $CURRENT_EPOCH) / 86400 ))
echo "๐ Days until expiration: $DAYS_LEFT"
if [ $DAYS_LEFT -lt 30 ]; then
echo "โ ๏ธ WARNING: Certificate expires soon!"
else
echo "โ
Certificate is valid"
fi
# Check protocols
echo ""
echo "๐ Supported protocols:"
for proto in tls1 tls1_1 tls1_2 tls1_3; do
if echo | openssl s_client -connect $DOMAIN:$PORT -servername $DOMAIN -$proto 2>/dev/null | grep -q "Cipher is"; then
echo " โ
${proto^^} supported"
else
echo " โ ${proto^^} not supported"
fi
done
rm -f /tmp/cert.txt
else
echo "โ Could not connect to $DOMAIN:$PORT"
fi
EOF
chmod +x /usr/local/bin/check-ssl.sh
# Test it
check-ssl.sh localhost
๐ฎ Practice Exercise
Try different SSL configurations:
- Create multiple sites with SSL
- Test different cipher suites
- Monitor certificate expiration
- Set up SSL for subdomains
# Create test subdomain config
cat > /etc/nginx/conf.d/subdomain-ssl.conf << 'EOF'
server {
listen 443 ssl http2;
server_name sub.localhost;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
root /var/www/subdomain;
index index.html;
}
EOF
# Create subdomain directory
mkdir -p /var/www/subdomain
echo "<h1>Secure Subdomain</h1>" > /var/www/subdomain/index.html
# Reload and test
nginx -t && rc-service nginx reload
๐จ Troubleshooting Common Issues
Certificate Not Trusted
Fix trust issues:
# For self-signed certificates
# Browsers will show warning - this is normal
# Add to local trust store (for testing)
cp /etc/nginx/ssl/server.crt /usr/local/share/ca-certificates/
update-ca-certificates
# Check certificate chain
openssl verify -CAfile /etc/nginx/ssl/server.crt /etc/nginx/ssl/server.crt
Mixed Content Warnings
Fix HTTP resources on HTTPS pages:
# Find mixed content in files
grep -r "http://" /var/www/ | grep -v "https://"
# Update all HTTP links to HTTPS
find /var/www -type f -name "*.html" -exec \
sed -i 's|http://|https://|g' {} \;
SSL Handshake Failed
Debug SSL handshake:
# Enable debug logging
sed -i 's/error_log.*;/error_log \/var\/log\/nginx\/error.log debug;/' \
/etc/nginx/nginx.conf
# Reload and check logs
rc-service nginx reload
tail -f /var/log/nginx/error.log
# Test with verbose output
curl -v https://localhost -k
๐ก Pro Tips
Tip 1: SSL Performance
Optimize SSL performance:
# Enable session cache
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
# Enable keepalive
keepalive_timeout 70;
keepalive_requests 100;
Tip 2: Security Headers
Add comprehensive security headers:
# Security headers snippet
cat > /etc/nginx/snippets/security-headers.conf << 'EOF'
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
EOF
# Include in server blocks
# include /etc/nginx/snippets/security-headers.conf;
Tip 3: Multi-Domain Certificates
Handle multiple domains:
# Get multi-domain certificate
certbot certonly --standalone \
-d example.com \
-d www.example.com \
-d api.example.com \
-d app.example.com
# Or use wildcard
certbot certonly --standalone \
-d "*.example.com" \
-d example.com \
--preferred-challenges dns
โ Best Practices
-
Use strong ciphers
- TLS 1.2 minimum
- Disable weak ciphers
- Regular updates
-
Certificate management
# Monthly check script 0 0 1 * * /usr/local/bin/check-ssl.sh
-
Monitor expiration
# Alert before expiry certbot renew --dry-run
-
Backup certificates
# Backup SSL files tar -czf ssl-backup-$(date +%Y%m%d).tar.gz /etc/nginx/ssl/
-
Test regularly
# Use SSL Labs test # ssllabs.com/ssltest/
๐ What You Learned
Great job! You can now:
- โ Generate SSL certificates
- โ Configure Nginx for HTTPS
- โ Set up Letโs Encrypt
- โ Optimize SSL settings
- โ Monitor certificate status
Your websites are now secure!
๐ฏ Whatโs Next?
Now that you have SSL/TLS, explore:
- HTTP/2 and HTTP/3 setup
- SSL certificate automation
- Web Application Firewall
- Advanced security headers
Keep securing the web! ๐