Generate Absolutely Free SSL Certificate for Your Setup (Let’s Encrypt on Ubuntu) with Auto-Renew Script
Step-by-step Let’s Encrypt SSL generation on Ubuntu plus automated renewal script and verification for long-term secure deployments.
HTTPS is not optional anymore. Browsers warn users, APIs reject insecure callbacks, and WebSockets often fail behind proxies without valid TLS.
This guide shows the most reliable way to generate a free SSL certificate using Let’s Encrypt + Certbot on Ubuntu, configure it with NGINX, and set up automatic renewal that you can actually verify.
It also covers the real-world problems people hit: DNS issues, ports blocked, “too many redirects”, failed renewals, broken WebSockets, and how to debug each one.
Official references you can trust: Let’s Encrypt Docs, Certbot (EFF) Instructions, NGINX Docs.
Architecture: What You’re Setting Up (So You Don’t Break Routing)
Let’s Encrypt validates domain ownership using HTTP on port 80 (HTTP-01) or DNS records (DNS-01). The most common production flow with NGINX is:
The key idea: port 80 must be reachable from the public internet for HTTP-01 validation (unless you use DNS validation). Most failures happen because port 80 is blocked or DNS is wrong.
Before You Start: Checklist That Prevents 90% of SSL Failures
1) Your DNS must point to the correct public IP
Confirm the domain resolves to your server’s public IP. From your local machine:
dig +short yourdomain.com
dig +short www.yourdomain.com
The output should match your server’s public IPv4 (or IPv6 if you’re using IPv6). If it doesn’t, fix DNS first (or wait for propagation).
2) Ports 80 and 443 must be open
On Ubuntu with UFW:
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
If you’re behind a router/NAT, also ensure router port forwarding is correct. (Port 80 is required for HTTP-01 challenge.)
3) NGINX should already serve your domain on HTTP (temporary is fine)
Make sure this works before SSL:
curl -I http://yourdomain.com
You should see a response (200/301/302 is okay). A timeout usually means networking/firewall.
Step 1: Install NGINX + Certbot (Ubuntu)
Install NGINX
sudo apt update
sudo apt install -y nginx
Verify NGINX is running:
systemctl status nginx --no-pager
Install Certbot for NGINX
On Ubuntu, the common production approach is using the packaged Certbot with the NGINX plugin:
sudo apt install -y certbot python3-certbot-nginx
If your environment uses snap for certbot, follow the official EFF flow here: certbot.eff.org
Step 2: Create a Clean HTTP Server Block (So Certbot Can Upgrade It)
Create (or edit) an NGINX server block for your domain. Example:
sudo nano /etc/nginx/sites-available/yourdomain.com
Use this minimal HTTP config first:
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
# Temporary safe root for ACME challenge
root /var/www/html;
location / {
return 200 "OK - HTTP reachable\n";
add_header Content-Type text/plain;
}
}
Enable it:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/yourdomain.com
sudo nginx -t
sudo systemctl reload nginx
Test from the internet (or at least from your laptop):
curl -i http://yourdomain.com
Step 3: Generate the Let’s Encrypt SSL Certificate (Recommended Command)
This command will:
- Request a certificate for your domain(s)
- Prove ownership using HTTP-01 validation
- Modify your NGINX config to enable HTTPS
- Optionally configure HTTP → HTTPS redirect
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
If prompted for redirect, choosing redirect is usually correct for production websites and dashboards. For some telecom APIs (callbacks) you may intentionally keep HTTP endpoints — but then you must manage that safely.
Where certificates are stored
Certbot typically stores certificates here:
/etc/letsencrypt/live/yourdomain.com/fullchain.pem
/etc/letsencrypt/live/yourdomain.com/privkey.pem
Check the certificate:
sudo certbot certificates
Step 4: Confirm HTTPS Works (Real Checks, Not Guessing)
1) Confirm the certificate is served
curl -Iv https://yourdomain.com
Look for:
- subject: yourdomain.com
- issuer: Let’s Encrypt
- HTTP/2 (optional but common)
2) Confirm auto-redirect (if enabled)
curl -I http://yourdomain.com
You should see a 301/308 redirect to https://...
3) Confirm NGINX config
sudo nginx -T | sed -n '1,200p'
Production-Safe NGINX TLS Settings (Modern Defaults)
Certbot will generate a working HTTPS config, but production systems often tighten TLS. You can add/confirm these settings inside your HTTPS server block.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Modern TLS: keep it simple and compatible
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# Optional security headers (adjust based on your app)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
# WebSocket support (common in dashboards/telecom apps)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Reload:
sudo nginx -t
sudo systemctl reload nginx
If your app uses long-running requests or streaming: configure proxy timeouts (common with telecom reports or media control APIs).
Auto-Renewal: Make Sure It Actually Renews (And Prove It)
Let’s Encrypt certificates expire (typically 90 days). Auto-renewal is mandatory. On Ubuntu, certbot usually installs a systemd timer automatically.
1) Check the systemd timer
systemctl list-timers | grep certbot || true
systemctl status certbot.timer --no-pager || true
2) Dry-run renewal test (must succeed)
sudo certbot renew --dry-run
You want to see output indicating renewal simulation succeeded. If dry-run fails, your real renewal will fail too.
3) Reload NGINX after renewal (if not already handled)
Many setups already reload automatically, but you can ensure it by adding a deploy hook:
sudo certbot renew --deploy-hook "systemctl reload nginx"
For a permanent hook:
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/sh
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Most Common SSL Problems People Search For (And Exact Fixes)
Problem: “Certbot failed authorization procedure”
Usually one of these:
- DNS A record points to wrong IP
- Port 80 blocked (UFW / cloud security group / router)
- NGINX not serving the requested domain (wrong server_name)
- Another service is using port 80
Quick checks:
sudo ss -lntp | grep -E ':80|:443' || true
curl -I http://yourdomain.com
dig +short yourdomain.com
Problem: “Too many redirects” after enabling SSL
This often happens when:
- Your app forces HTTPS while NGINX already redirects HTTP→HTTPS
- Reverse proxy doesn’t set X-Forwarded-Proto so the app thinks it’s HTTP
Fix in NGINX:
proxy_set_header X-Forwarded-Proto $scheme;
Problem: WebSockets fail after SSL (telecom dashboards / real-time UI)
Usually missing Upgrade/Connection headers:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Problem: Renewal fails later even though initial issuance worked
Common causes:
- Port 80 was later closed by firewall changes
- Domain moved to a different IP without updating DNS
- NGINX config changed and broke ACME location handling
Always run:
sudo certbot renew --dry-run
Alternative: DNS Validation (When Port 80 Cannot Be Open)
Some environments cannot expose port 80 publicly (strict enterprises, certain network policies). In that case, use DNS-01 validation. This requires adding TXT records in DNS.
Start here: Let’s Encrypt Challenge Types
DNS validation is powerful but depends on your DNS provider automation. If you do it manually, you must carefully manage TXT records.
Certificate Files for Apps That Need PEM (Common in Telecom Integrations)
Many telecom components (WebRTC gateways, SIP-related dashboards, Java services) require separate PEM files. Let’s Encrypt already provides PEM. Usually you will use:
- fullchain.pem (server cert + chain)
- privkey.pem (private key)
If a tool demands a combined file:
sudo sh -c 'cat /etc/letsencrypt/live/yourdomain.com/fullchain.pem \
/etc/letsencrypt/live/yourdomain.com/privkey.pem > /etc/ssl/private/yourdomain.com-combined.pem'
sudo chmod 600 /etc/ssl/private/yourdomain.com-combined.pem
Keep private keys locked down. Never copy them into world-readable folders.
Final Verification Checklist (Use This Before Calling It “Done”)
- HTTP works:
curl -I http://yourdomain.com - HTTPS works:
curl -Iv https://yourdomain.com - NGINX reload ok:
sudo nginx -t - Certbot sees cert:
sudo certbot certificates - Renewal dry-run passes:
sudo certbot renew --dry-run - Timer exists:
systemctl status certbot.timer
If all checks pass, you have a production-grade free SSL setup with automatic renewal.
Want to see API-driven CRM + Telecom workflows in action? Try the WhatsApp bot or explore the demos.
Comments (0)
Be the first to comment.