Let's Encrypt SSL VPS Automation with Certbot: systemd Timers & Nginx Setup
A complete sysadmin guide to automating Let's Encrypt SSL/TLS certificates on Linux KVM VPS using Certbot, HTTP-01 challenges, and automated systemd renewals.
Securing web traffic with Transport Layer Security (TLS) is mandatory for modern web applications, REST APIs, and client portals. Running an unencrypted HTTP service compromises sensitive authentication tokens and triggers visible browser warnings. Utilizing the Automated Certificate Management Environment (ACME) protocol via Let's Encrypt and the official Certbot client enables administrators to provision trusted, domain-validated SSL certificates at zero cost and automate renewals on Linux KVM virtual private servers.
How ACME and the HTTP-01 Challenge Function
Let's Encrypt verifies domain ownership automatically using challenge protocols defined by the IETF ACME standard. The most common method for public web servers is the HTTP-01 challenge:
- The Certbot client contacts the Let's Encrypt ACME server requesting a certificate for specified domain names (e.g.,
yourdomain.com). - Let's Encrypt responds with a unique cryptographic verification token.
- Certbot places the token file in the server's web root directory under the path
/.well-known/acme-challenge/<token>. - The Let's Encrypt validation server makes an HTTP request to that URL over port 80. If the token retrieved matches the cryptographic challenge, ownership is proven.
- Let's Encrypt generates and signs the digital certificate, which Certbot downloads and installs locally.
Step 1: Installing Certbot via Snap or Package Manager
The Electronic Frontier Foundation (EFF) recommends installing Certbot via snapd to ensure access to the latest security releases and cryptographic libraries:
# Ensure snapd is installed and updated
sudo apt update
sudo apt install -y snapd
sudo snap install core; sudo snap refresh core
# Remove legacy apt certbot packages if present
sudo apt remove -y certbot
# Install official Certbot snap with classic confinement
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotStep 2: Issuing Certificates Using the Nginx Plugin
If Nginx is already configured with your domain's server block, Certbot can automatically inspect your virtual host files, complete the challenge, and configure the SSL directives:
# Automatically obtain and configure SSL in Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comAlternatively, if you prefer to maintain full manual control over your Nginx configuration files, use the certonly mode with the webroot plugin:
# Obtain certificate only without modifying Nginx configuration
sudo certbot certonly --webroot -w /var/www/html \
-d yourdomain.com -d www.yourdomain.comThe certificate files are saved to /etc/letsencrypt/live/yourdomain.com/:
fullchain.pem: The server certificate concatenated with intermediate certificates.privkey.pem: The private key corresponding to the public certificate. Never share this file.
Step 3: Configuring Nginx SSL Directives
Reference the generated certificates in your Nginx configuration block:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
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 configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
# Session caching
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}Step 4: Automating Renewals with systemd Timers and Deploy Hooks
Let's Encrypt certificates expire every 90 days. Certbot installs a systemd timer (snap.certbot.renew.timer) that runs twice daily to check for certificates within 30 days of expiration.
When a certificate is successfully renewed, Nginx must reload its configuration to read the new certificate file from disk into memory. Configure a deploy hook in /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh:
#!/bin/bash
systemctl reload nginxMake the script executable: sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh.
Verify that automated renewal succeeds by running a dry run:
sudo certbot renew --dry-runStep 5: DNS-01 Challenges and Wildcard Certificates
While the standard HTTP-01 challenge works smoothly for public web servers accepting traffic on port 80, certain production environments cannot expose port 80 directly to the internet, such as internal staging platforms, private administrative portals, or infrastructure behind restrictive corporate firewalls. Additionally, if you need a wildcard certificate (such as *.yourdomain.com) that covers dynamic customer subdomains under a single TLS credential, Let's Encrypt requires the DNS-01 challenge protocol.
The DNS-01 challenge works by provisioning a temporary DNS TXT record under _acme-challenge.yourdomain.com. The Let's Encrypt ACME server queries authoritative DNS nameservers to verify domain control without requiring an inbound HTTP connection to your VPS. Certbot offers specialized DNS plugins for major DNS providers (such as Cloudflare, Route53, and DigitalOcean) to automate record provisioning and cleanup:
# Install the Cloudflare DNS plugin for Certbot
sudo snap install certbot-dns-cloudflare
# Request a wildcard certificate via DNS-01 challenge
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d yourdomain.com \
-d "*.yourdomain.com"Certbot automatically writes the required TXT record via the API, waits for DNS propagation, completes validation with the Let's Encrypt CA, and purges the temporary record. Deploy hooks configured in /etc/letsencrypt/renewal-hooks/deploy/ reload your reverse proxy when wildcard certificates renew, ensuring reliable end-to-end automation.
Deploying Secure Web Platforms on VPSWala
Automating TLS encryption ensures your cloud instances maintain compliance with modern web security standards. VPSWala provides unmanaged KVM cloud VPS plans starting from Rs 149 per month with full root access, RAID NVMe storage, and scalable configurations up to 128 GB RAM. For demanding production databases and heavy workloads, our AMD Ryzen 9 9950X VPS instances deliver exceptional performance with DDR5 memory and up to 5.7 GHz boost clock speeds.
Configure your cloud server on VPSWala KVM Cloud VPS, or discover high-frequency instances on VPSWala 9950X VPS.
Sources
Not sure which size?
Send the stack, get a size.
Tell us the operating system, application stack, current traffic, database size and where it hurts today. You get a sizing recommendation, the matching plan and a price.
Related
MySQL vs MariaDB for VPS Hosting: Thread Pools, Aria Engine & Performance
A database architecture deep dive comparing MySQL 8.0 and MariaDB on Linux VPS instances, evaluating thread pool concurrency, storage engines, and memory tuning.
Nginx vs Apache on a Linux VPS: Event Architecture, mpm_event & RAM Sizing
A technical architectural comparison between Nginx and Apache HTTP Server on Linux KVM VPS instances, evaluating memory consumption, concurrency, and static caching.
VPS Hosting for Guwahati: Which VPSWala Node to Pick and How to Test It
How engineering teams and enterprises in Guwahati can evaluate carrier transit, pick between Mumbai, Noida, and Jaipur nodes, and test latency empirically.