Back to tutorials
Tutorial

Linux VPS nginx SSL Configuration Tutorial: Complete HTTPS Setup with Let's Encrypt and Security Headers for 2026

Master nginx SSL configuration on Linux VPS with Let's Encrypt automation, security headers, and performance tuning. Complete HTTPS setup guide.

By Anurag Singh
Updated on Apr 30, 2026
Category: Tutorial
Share article
Linux VPS nginx SSL Configuration Tutorial: Complete HTTPS Setup with Let's Encrypt and Security Headers for 2026

Prerequisites and SSL Certificate Planning

You'll need a Linux VPS running Ubuntu 20.04+, Debian 11+, or Rocky Linux 9 with nginx installed. Your domain should point to the server's IP address.

SSL certificates encrypt traffic between browsers and your server. They also validate your site's identity. Let's Encrypt provides free auto-renewing certificates—the practical choice for most VPS setups.

Check your current nginx version:

nginx -v
sudo nginx -t

Modern nginx versions include decent SSL defaults. We'll configure everything explicitly for better security and performance.

Installing Certbot and Obtaining SSL Certificates

Certbot handles Let's Encrypt certificate requests and renewals automatically. Install it through your package manager:

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx

# Rocky Linux/RHEL
sudo dnf install certbot python3-certbot-nginx

Before requesting certificates, verify your domain resolves correctly. Make sure nginx serves content on port 80.

Create a basic server block if needed:

sudo nano /etc/nginx/sites-available/example.com

Add this minimal configuration:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html;
}

Enable the site and reload nginx:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Now request your SSL certificate:

sudo certbot --nginx -d example.com -d www.example.com

Certbot modifies your nginx configuration automatically. We'll optimize it further.

Optimizing nginx SSL Configuration

The default certbot setup works but lacks performance optimizations.

Edit your nginx server block for better results:

sudo nano /etc/nginx/sites-available/example.com

Replace the SSL section with this optimized configuration:

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html index.php;

    # SSL Certificate paths
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL Security Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # SSL Performance
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozTLS:10m;
    ssl_session_tickets off;
    
    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    resolver 1.1.1.1 1.0.0.1 valid=300s;
    resolver_timeout 5s;
}

This configuration enables TLS 1.3 and optimizes cipher selection. It also enables OCSP stapling for faster certificate validation.

Adding Security Headers

Security headers protect against common web vulnerabilities.

Add these inside your server block:

# Security Headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;

The HSTS header forces browsers to use HTTPS for future visits. The CSP header prevents XSS attacks by controlling resource loading.

WordPress or PHP applications might need a more permissive CSP policy:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;

Configuring HTTP to HTTPS Redirects

All HTTP traffic should redirect to HTTPS automatically.

Add this server block above your main HTTPS configuration:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

Handling redirects at the nginx level reduces server processing overhead. This works better than application-level redirects.

Test your redirect:

curl -I http://example.com
# Should return 301 and Location: https://example.com

SSL Performance Tuning

SSL handshakes consume CPU resources. These optimizations reduce overhead.

Enable SSL session resumption by adding to your nginx.conf main context:

sudo nano /etc/nginx/nginx.conf

Add inside the http block:

http {
    # SSL Performance
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # Enable keepalive connections
    keepalive_timeout 70;
    keepalive_requests 1000;
}

Configure nginx worker processes to match your VPS CPU cores:

worker_processes auto;
worker_connections 1024;

This setup handles more concurrent SSL connections efficiently.

HostMyCode VPS hosting provides optimized server configurations for nginx SSL workloads with multiple CPU cores and fast NVMe storage.

Automating SSL Certificate Renewals

Let's Encrypt certificates expire every 90 days. Certbot installs a systemd timer for automatic renewals—verify it works:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

If the dry run succeeds, your renewals are configured correctly.

Check upcoming renewals:

sudo certbot certificates

For custom renewal hooks, create a script:

sudo nano /etc/letsencrypt/renewal-hooks/post/nginx-reload

Add:

#!/bin/bash
nginx -t && systemctl reload nginx

Make it executable:

sudo chmod +x /etc/letsencrypt/renewal-hooks/post/nginx-reload

Testing SSL Configuration

Verify your configuration works correctly:

sudo nginx -t
sudo systemctl reload nginx

Test SSL functionality:

# Check certificate details
openssl s_client -connect example.com:443 -servername example.com

# Verify HTTP/2 support
curl -I --http2 https://example.com

Use these SSL testing tools to validate your setup:

  • SSL Labs SSL Test (ssllabs.com/ssltest/)
  • Mozilla Observatory (observatory.mozilla.org)
  • Security Headers (securityheaders.com)

A proper nginx SSL configuration should score A+ on SSL Labs with all security headers present.

Troubleshooting Common SSL Issues

Mixed content errors occur when HTTPS pages load HTTP resources. Check your application for hardcoded HTTP URLs. Update them to HTTPS or use protocol-relative URLs.

Certificate chain issues cause browser warnings. Verify you're using fullchain.pem, not cert.pem:

sudo certbot certificates
# Should show fullchain.pem path

Port 443 accessibility issues prevent SSL connections.

Check your VPS firewall:

# UFW users
sudo ufw allow 443

# firewalld users
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

SSL handshake failures often result from cipher mismatches. The configuration above uses modern, compatible ciphers that work with all current browsers.

Advanced nginx SSL Features

For high-traffic sites, enable SSL session tickets for better performance:

ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;

Generate the session ticket key:

sudo mkdir -p /etc/nginx/ssl
sudo openssl rand 48 > /etc/nginx/ssl/ticket.key
sudo chmod 600 /etc/nginx/ssl/ticket.key

HTTP/2 push can preload critical resources.

Add push directives for CSS and JavaScript:

location = / {
    http2_push /css/main.css;
    http2_push /js/app.js;
}

Certificate pinning adds extra security but requires careful management:

add_header Public-Key-Pins 'pin-sha256="base64+primary+key"; pin-sha256="base64+backup+key"; max-age=2592000; includeSubDomains' always;

Only implement HPKP if you understand the risks. Make sure you have backup certificates ready.

Ready to implement nginx SSL configuration on a production VPS? HostMyCode managed VPS hosting provides pre-configured nginx servers with SSL-ready environments and expert support for complex configurations.

Frequently Asked Questions

How often do Let's Encrypt certificates need renewal?

Let's Encrypt certificates expire every 90 days. Certbot renews them automatically when they have 30 days or less remaining. The systemd timer runs twice daily to check for renewals.

Can I use wildcard SSL certificates with nginx?

Yes, obtain wildcard certificates using DNS challenge: sudo certbot certonly --manual --preferred-challenges=dns -d *.example.com. You'll need to add DNS TXT records as instructed.

Why is my SSL Labs score not A+?

Common issues include missing HSTS headers, weak ciphers, or certificate chain problems. Follow the security headers section above. Make sure you're using fullchain.pem for the certificate file.

How do I handle multiple domains on one VPS?

Create separate server blocks for each domain. Each needs its own SSL certificate. Use SNI (Server Name Indication) to serve the correct certificate: sudo certbot --nginx -d domain1.com -d domain2.com.

What's the difference between cert.pem and fullchain.pem?

cert.pem contains only your domain certificate. fullchain.pem includes your certificate plus the intermediate certificate chain. Always use fullchain.pem to avoid browser warnings.

Linux VPS nginx SSL Configuration Tutorial: Complete HTTPS Setup with Let's Encrypt and Security Headers for 2026 | HostMyCode