yum upgrades for production use, this is the repository for you.
Active subscription is required.
📅 Updated: January 27, 2026 (Originally published: January 19, 2023)
Setting up free SSL for NGINX with Let’s Encrypt is straightforward when you use DNS validation. This method allows you to obtain trusted SSL certificates without any downtime. Moreover, automatic renewal ensures your certificates never expire. In this comprehensive guide, you will learn how to configure Let’s Encrypt NGINX SSL from scratch.
Why Choose Let’s Encrypt for Your Free SSL Certificate?
Let’s Encrypt is a nonprofit Certificate Authority run by the Internet Security Research Group (ISRG). It has issued billions of certificates since its launch in 2015. Major browsers and operating systems trust Let’s Encrypt certificates completely. Therefore, your visitors will see the padlock icon just like with expensive commercial certificates.
The main advantages of using free SSL for NGINX with Let’s Encrypt include:
- Zero cost: All certificates are completely free
- Automation: Certificates can be renewed automatically
- Industry standard: Uses the same cryptographic standards as paid certificates
- Wide support: Trusted by all major browsers and devices
- Fast issuance: Get your certificate in seconds, not days
However, Let’s Encrypt certificates are valid for only 90 days. This might seem like a disadvantage at first. In practice, automatic renewal makes this a non-issue. The short validity period actually improves security by limiting the exposure window if a private key is compromised.
DNS Validation vs HTTP Validation: Which Should You Use?
When you request a free SSL for NGINX from Let’s Encrypt, you must prove domain ownership. There are two main methods: HTTP validation and DNS validation.
HTTP Validation (HTTP-01 Challenge)
HTTP validation requires your web server to serve a specific file. The Let’s Encrypt servers will request this file over HTTP on port 80. This method has several limitations:
- Your web server must be running and accessible from the internet
- Port 80 must be open and not blocked by a firewall
- You cannot obtain wildcard certificates
- Some server configurations may interfere with the challenge
DNS Validation (DNS-01 Challenge)
DNS validation uses a TXT record in your domain’s DNS zone. This approach offers significant advantages:
- No downtime required: You don’t need to stop your web server
- Wildcard certificates: You can secure unlimited subdomains with one certificate
- Works behind firewalls: Your server doesn’t need to be publicly accessible
- Simpler for complex setups: Perfect for load balancers and CDN configurations
For these reasons, DNS validation is the recommended approach. This guide focuses on DNS validation using Cloudflare as the DNS provider.
Prerequisites
Before you begin setting up free SSL for NGINX, ensure you have the following:
- A server running Rocky Linux, AlmaLinux, RHEL, or CentOS
- NGINX installed and working
- A domain name pointed to your server
- Your domain’s DNS managed by Cloudflare
- Root or sudo access to your server
If you’re not using Cloudflare for DNS, certbot supports many other providers. These include Amazon Route 53, Google Cloud DNS, DigitalOcean, and more.
Step 1: Install Certbot
Certbot is the official Let’s Encrypt client. It handles certificate requests, validation, and installation. First, install the EPEL repository if you haven’t already:
sudo dnf install -y epel-release
Next, install the certbot package:
sudo dnf install -y certbot
Verify the installation by checking the version:
certbot --version
You should see output similar to certbot 4.2.0 or higher.
Step 2: Install the DNS Validation Plugin
For DNS-based validation with Cloudflare, you need the Cloudflare plugin for certbot. Install it with:
sudo dnf install -y python3-certbot-dns-cloudflare
This plugin communicates with the Cloudflare API to create and delete the TXT records needed for validation. The entire process happens automatically without manual intervention.
Step 3: Configure Cloudflare API Credentials
The certbot Cloudflare plugin needs API credentials to modify your DNS records. The recommended approach is to use an API token with minimal permissions.
Creating a Cloudflare API Token
Follow these steps to create a properly scoped API token:
- Log in to your Cloudflare account
- Navigate to the API Tokens page
- Click “Create Token”
- Select “Edit zone DNS” and click “Use template”
- Under “Zone Resources”, select the specific zones you need certificates for
- Click “Continue to summary” and then “Create Token”
- Copy the token immediately – it won’t be shown again
Storing the Credentials
Create a credentials file that certbot will use:
sudo mkdir -p /root/.secrets
sudo touch /root/.secrets/cloudflare.ini
sudo chmod 600 /root/.secrets/cloudflare.ini
Edit the file and add your API token:
# Cloudflare API token used by Certbot
dns_cloudflare_api_token = YOUR_API_TOKEN_HERE
Replace YOUR_API_TOKEN_HERE with the token you copied from Cloudflare. The chmod command ensures only root can read this file.
Step 4: Generate Your SSL Certificate
Now you can request your free SSL certificate for NGINX. Run the following command as root:
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos \
--non-interactive \
--deploy-hook 'systemctl reload nginx'
Let’s break down what each option does:
certonly: Only obtain the certificate, don’t install it automatically--dns-cloudflare: Use the Cloudflare DNS plugin for validation--dns-cloudflare-credentials: Path to your API credentials file-d example.com -d www.example.com: Domain names to include in the certificate--email: Your email address for important notifications--agree-tos: Accept the Let’s Encrypt terms of service--non-interactive: Run without prompting for user input--deploy-hook: Command to run after successful renewal
The deploy hook is crucial. It tells NGINX to reload its configuration after each renewal. This ensures your server always uses the latest certificate.
After successful validation, certbot will display the certificate locations:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
Step 5: Configure NGINX with SSL
With your free SSL certificate ready, you can now configure NGINX. If you’re hosting multiple domains, see our guide on NGINX virtual hosts for proper server block organization. Create or edit your server block configuration:
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
http2 on;
server_name example.com www.example.com;
# SSL Certificate
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# TLS 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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
resolver_timeout 5s;
# Session Configuration
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Security Headers
add_header Strict-Transport-Security "max-age=63072000" always;
server_tokens off;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
This configuration includes several important security features. For advanced TLS hardening techniques and achieving an A+ SSL Labs rating, see our detailed NGINX TLS 1.3 hardening guide.
TLS Protocol and Cipher Configuration
The ssl_protocols directive enables only TLSv1.2 and TLSv1.3. Older protocols like TLSv1.0 and TLSv1.1 have known vulnerabilities. Modern browsers don’t need these deprecated protocols.
The cipher suite in ssl_ciphers prioritizes AEAD ciphers like AES-GCM and ChaCha20-Poly1305. These provide authenticated encryption and resist various cryptographic attacks. The ssl_prefer_server_ciphers directive ensures the server chooses the cipher, not the client. This prevents downgrade attacks where a malicious client requests a weaker cipher.
Session Cache and Tickets
The ssl_session_cache creates a shared memory zone for storing TLS session data. This allows session resumption, which significantly speeds up repeated connections. A 10MB cache can store approximately 40,000 sessions.
The ssl_session_timeout sets how long sessions remain valid. A 24-hour timeout balances security and performance. Setting ssl_session_tickets off disables session tickets. While tickets enable session resumption across server restarts, they can compromise forward secrecy if the ticket key is compromised.
HSTS (HTTP Strict Transport Security)
The Strict-Transport-Security header tells browsers to only use HTTPS for your domain. Once a browser receives this header, it will refuse HTTP connections for the specified duration. The max-age=63072000 value equals two years in seconds.
Understanding OCSP Stapling
OCSP stapling is a performance and privacy optimization for certificate revocation checking. Understanding it helps you configure free SSL for NGINX optimally.
The Problem with Traditional OCSP
When a browser receives your SSL certificate, it needs to verify the certificate hasn’t been revoked. Traditionally, browsers would contact the Certificate Authority’s OCSP server directly. This approach has several problems:
- It adds latency to every new connection
- It can fail if the OCSP server is slow or unreachable
- It leaks information about which sites users visit to the CA
How OCSP Stapling Works
With OCSP stapling, NGINX periodically fetches the OCSP response from the CA. It then “staples” this response to the TLS handshake. The browser receives the revocation status directly from your server. This eliminates the need for a separate OCSP lookup.
Looking at the NGINX source code reveals how this works internally. The ngx_ssl_stapling_t structure stores the stapled response along with validity and refresh times. NGINX automatically updates the staple before it expires.
Configuring OCSP Stapling
The configuration requires three directives:
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
For the resolver, you should use a local DNS resolver when possible. External resolvers like 1.1.1.1 or 8.8.8.8 can expose you to DNS spoofing attacks. The ssl_trusted_certificate directive provides the CA certificate chain needed to verify the OCSP response:
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
Step 6: HTTP to HTTPS Redirect
You should redirect all HTTP traffic to HTTPS. This ensures visitors always use the encrypted connection. Add a separate server block for port 80:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
The 301 status code indicates a permanent redirect. Search engines will update their indexes to use the HTTPS URL.
Step 7: Apply and Test Your Configuration
Before applying the changes, test your NGINX configuration for syntax errors:
sudo nginx -t
You should see output like:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
If there are no errors, apply the configuration:
sudo systemctl reload nginx
Using reload instead of restart keeps existing connections alive. This provides zero-downtime deployment.
Verify Your SSL Configuration
Test your certificate with curl:
curl -vI https://example.com 2>&1 | grep -A5 "SSL connection"
For comprehensive testing, use SSL Labs to verify your free SSL NGINX configuration achieves an A+ rating.
Step 8: Enable Automatic Renewal
Let’s Encrypt certificates expire after 90 days. Certbot includes a systemd timer for automatic renewal. Enable and start it:
sudo systemctl enable certbot-renew.timer
sudo systemctl start certbot-renew.timer
Verify the timer is active:
systemctl list-timers certbot-renew.timer
You should see the next scheduled renewal time. The timer runs twice daily and renews certificates that expire within 30 days.
Testing Renewal
You can test the renewal process without actually renewing:
sudo certbot renew --dry-run
This simulates the renewal and shows any potential problems. If the dry run succeeds, automatic renewal will work correctly.
Obtaining Wildcard Certificates
Wildcard certificates secure all subdomains of a domain with a single certificate. They’re useful when you have many subdomains or frequently add new ones.
To obtain a wildcard certificate, use the *. prefix:
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com \
-d "*.example.com" \
--email admin@example.com \
--agree-tos \
--non-interactive \
--deploy-hook 'systemctl reload nginx'
Note the quotes around *.example.com. They prevent the shell from interpreting the asterisk. This single certificate will secure example.com, www.example.com, api.example.com, and any other subdomain.
Wildcard certificates require DNS validation. HTTP validation cannot verify control of all possible subdomains.
Troubleshooting Common Issues
DNS Propagation Delays
If certificate issuance fails with a DNS error, the TXT record may not have propagated yet. Increase the propagation wait time:
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d example.com
Permission Errors
If certbot can’t write to the credentials file or certificate directories, check the permissions:
sudo ls -la /root/.secrets/cloudflare.ini
sudo ls -la /etc/letsencrypt/
The credentials file should be readable only by root (mode 600).
Rate Limits
Let’s Encrypt imposes rate limits to prevent abuse. For testing, use the staging environment:
certbot certonly --staging --dns-cloudflare ...
Staging certificates won’t be trusted by browsers, but they don’t count against rate limits.
OCSP Stapling Not Working
To verify OCSP stapling is active:
echo | openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A 17 "OCSP response"
If you see “no response sent”, check that the resolver is working and the ssl_trusted_certificate path is correct.
Security Best Practices
Beyond basic free SSL for NGINX configuration, consider these additional security measures.
Use a Local DNS Resolver
External DNS resolvers can be spoofed. Install a local resolver for OCSP and other DNS lookups:
sudo dnf install -y dnsmasq
sudo systemctl enable --now dnsmasq
Then configure NGINX to use it:
resolver 127.0.0.1 [::1] valid=300s;
Validate Your Configuration with Gixy
Gixy is a security analyzer for NGINX configurations. It detects common misconfigurations and vulnerabilities:
sudo dnf install -y gixy
gixy /etc/nginx/nginx.conf
Gixy will report issues like insecure resolver settings, missing security headers, and potential vulnerabilities.
Conclusion
You now have a complete, production-ready free SSL for NGINX configuration using Let’s Encrypt. DNS validation through Cloudflare enables zero-downtime certificate issuance. The NGINX configuration includes modern TLS settings, OCSP stapling, and essential security headers.
The automatic renewal ensures your certificates never expire. With the deploy hook, NGINX automatically loads new certificates. Your visitors enjoy encrypted connections with optimal performance.
For ongoing maintenance, periodically run SSL Labs tests to verify your configuration. Monitor the certbot logs for renewal issues. Keep NGINX updated to benefit from security patches and performance improvements.
Remember to bookmark the Let’s Encrypt documentation for reference. For NGINX-specific questions, the official NGINX documentation covers all SSL directives in detail.
