Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Automate HTTPS with Lets Encrypt and Certbot

By Kokil Thapa | Last reviewed: September 2026

Every production site needs valid TLS, and manual renewals fail quietly until browsers show warnings. To automate HTTPS with Lets Encrypt and Certbot, you install the ACME client once, prove domain control, and schedule renewals before the 90-day expiry. I've maintained dozens of Ubuntu servers for Linux system administration clients in Nepal and abroad using this exact stack. This guide covers Apache and Nginx on Ubuntu 22.04/24.04 with copy-paste commands you can run today.

What is Let's Encrypt and how does Certbot automate HTTPS?

Let's Encrypt is a free, automated certificate authority run by the Internet Security Research Group. It issues domain-validated TLS certificates through the ACME protocol. Certbot is the official EFF client that talks to Let's Encrypt on your behalf.

Automation means three things in practice. First, initial issuance proves you control the hostname. Second, scheduled renewals repeat that proof before expiry. Third, a deploy hook reloads Apache or Nginx so visitors immediately get the new certificate.

On client projects I deploy with Ansible playbooks for server setup, Certbot is usually the last step after DNS and the web server are live. Treat TLS as infrastructure, not a launch-day afterthought. Browsers, search engines, and payment gateways all expect HTTPS in 2026.

Automate HTTPS with Lets Encrypt and CertbotBrowserHTTPS requestWeb ServerApache / NginxCertbotACME clientLet'sEncryptAutomated renewal cycle (every 60 days)Cron / Timercertbot renewNew cert filesReload server
End-to-end flow when you automate HTTPS with Lets Encrypt and Certbot on a Linux web server

Let's Encrypt certificates expire after 90 days by design. That short lifetime pushes operators toward automation instead of calendar reminders. Certbot's default renewal window starts at 30 days before expiry, though most teams renew around day 60.

For background on the initial manual path, see the companion guides on HTTPS setup with Let's Encrypt and Certbot and setting up free SSL with Let's Encrypt. This article focuses on making renewals hands-off.

Why automation beats one-time setup

A single successful certbot certonly run does not protect you six months later. I've seen law-firm portals and eCommerce stores go offline on a Sunday because nobody tested renewal. Automation plus monitoring closes that gap.

How do you install Certbot on Ubuntu for Apache or Nginx?

On Ubuntu 22.04 or 24.04, use the distribution packages or Snap. Both work in production. I prefer the Snap package on fresh servers because it tracks upstream Certbot releases closely.

sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
certbot --version

Confirm you see a recent Certbot release before proceeding. The Snap package bundles its own dependencies, which reduces conflicts with system Python.

Install via apt

sudo apt update
sudo apt install certbot python3-certbot-nginx
sudo apt install python3-certbot-apache

Install only the plugin package matching your web server. The Nginx plugin rewrites server blocks. The Apache plugin edits virtual host files.

Pre-flight checklist before any certificate request

  1. DNS A/AAAA records point to this server's public IP.
  2. Ports 80 and 443 are open in UFW or your cloud security group.
  3. The virtual host serves the correct server_name on port 80.
  4. No CDN orange-cloud proxy blocks direct HTTP validation unless you use DNS-01.

Domain and hosting decisions matter here. If DNS still propagates, wait before running Certbot. Our domain registration and hosting service usually confirms records before TLS work begins.

Which Certbot plugin should you use: webroot, standalone, or nginx/apache?

The plugin choice determines how Certbot proves domain control during HTTP-01 challenges. Pick the method that fits your downtime tolerance and server layout.

PluginBest forDowntimeNotes
--nginxNginx sites on UbuntuNoneEdits config and reloads automatically
--apacheApache virtual hostsNoneWorks well with PHP-FPM stacks
--webrootShared hosting, multiple appsNoneWrites token file under document root
standaloneFirst cert before web serverYes — binds port 80Stop Apache/Nginx temporarily
dns-*Wildcard certs, behind CDNNoneNeeds API credentials at your DNS host

On production Laravel and WordPress servers I usually run --nginx or --apache because the plugin handles both issuance and HTTPS redirects. Webroot is my fallback when the plugin cannot parse a complex config.

Nginx: fully automated first run

sudo certbot --nginx -d example.com -d www.example.com \
  --agree-tos --email admin@example.com --redirect

The --redirect flag adds an HTTP-to-HTTPS redirect. That single flag prevents duplicate-content SEO issues later. Pair it with canonical tags in your application layer.

Apache: fully automated first run

sudo certbot --apache -d example.com -d www.example.com \
  --agree-tos --email admin@example.com --redirect

After success, verify the new vhost with apachectl configtest and confirm PHP-FPM still serves dynamic pages. I've hit opcache stale paths after vhost rewrites — a quick FPM reload fixes it.

Webroot: when plugins fail

sudo certbot certonly --webroot -w /var/www/example.com/public \
  -d example.com -d www.example.com \
  --agree-tos --email admin@example.com

Ensure Nginx or Apache already maps /.well-known/acme-challenge/ to that webroot. Without that location block, HTTP-01 validation fails every time.

ACME HTTP-01 Challenge FlowCertbotWeb ServerLet's EncryptToken file/.well-known/1. Place2. Fetch3. Validate4. Issue certificateRenewal repeats steps 1–4 silently via cron or systemdCertbot only renews certs expiring within 30 daysDeploy hook reloads Nginx or Apache
HTTP-01 validation sequence used when you automate HTTPS with Lets Encrypt and Certbot

The official Let's Encrypt challenge types documentation explains when to switch from HTTP-01 to DNS-01. Use DNS-01 for wildcard certificates like *.example.com.

How do you obtain and auto-renew a Let's Encrypt certificate with Certbot?

Initial issuance is half the job. Auto-renewal is what keeps HTTPS alive for years without manual touch.

Verify the renewal timer on Ubuntu

Snap and apt installs register a systemd timer automatically. Check it:

systemctl list-timers | grep certbot
sudo systemctl status certbot.timer

You should see a twice-daily trigger. Certbot only renews certificates within 30 days of expiry, so most runs exit quickly with "no renewals were attempted".

Test renewal without applying changes

sudo certbot renew --dry-run

Always run a dry-run after first issuance and after any Nginx or Apache config change. A passing dry-run is your best proof that automation works. Schedule this in your deployment checklist alongside automated server backups with rsync and cron.

Add deploy hooks to reload the web server

Renewal replaces files under /etc/letsencrypt/live/yourdomain/. The web server must reload to pick up the new fullchain.

sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-webserver.sh

Example hook for Nginx:

#!/bin/bash
nginx -t && systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-webserver.sh

For Apache, swap the reload command:

#!/bin/bash
apachectl configtest && systemctl reload apache2

On sister sites sharing a Deployer 7 pipeline — including Notary Kathmandu and similar legal-tech portals — I run the dry-run after every deploy that touches vhost files.

Fallback cron entry (if no systemd timer)

0 3,15 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"

Running twice daily gives you room to fix failures before the 90-day cliff. Log output to a file if you want email alerts on failure.

Certificate file locations your app may reference

  • /etc/letsencrypt/live/example.com/fullchain.pem — send this to browsers
  • /etc/letsencrypt/live/example.com/privkey.pem — keep permissions at 600
  • /etc/letsencrypt/live/example.com/chain.pem — intermediate chain for some proxies

Never copy private keys into your Git repository. Reference the live symlink path in server config only. For generating strong passphrases for unrelated secrets, use the password generator tool — but never for TLS keys managed by Certbot.

Certbot Auto-Renewal Methods Comparedsystemd timerDefault on UbuntuRuns 2x dailyRandomised delayjournalctl loggingBest for VPS / cloud VMcron jobManual scheduleFixed run timesEmail on failureWorks without systemdFallback for containersBoth should call: certbot renew --dry-run monthly
systemd timer versus cron when you automate HTTPS renewals with Certbot on Linux

HTTP/2 and HTTP/3 performance gains only matter once TLS is stable. After automation works, read HTTP/2 vs HTTP/3 and QUIC for the next tuning step.

How do you troubleshoot Certbot auto-renewal failures in production?

Renewal failures are silent until expiry nears. Build habits that surface problems early.

Common failure causes and fixes

SymptomLikely causeFix
Connection refused on port 80Firewall or Nginx not listeningOpen UFW port 80; verify ss -tlnp | grep :80
404 on challenge URLMissing webroot or wrong server_nameAdd /.well-known/ location block
Too many requestsHit Let's Encrypt rate limitUse staging first; wait one week
DNS problemDomain moved to new IPUpdate A record; flush CDN cache
Renew succeeds, site still brokenNo deploy hook reloadAdd reload script under renewal-hooks

Our dedicated article on Let's Encrypt auto-renewal common failures walks through real log excerpts. Start every investigation with:

sudo certbot renew --dry-run -v
sudo tail -100 /var/log/letsencrypt/letsencrypt.log

Use the staging environment for experiments

sudo certbot --nginx -d test.example.com --staging --dry-run

Staging certificates are not trusted by browsers. They do not count against production rate limits. Test config rewrites there first.

Rate limits you should know

  • 50 certificates per registered domain per week
  • 5 duplicate certificates per week for the same hostname set
  • 300 new orders per account per 3 hours

Agencies managing many client subdomains should centralise account keys carefully. Wildcard certs via DNS-01 reduce hostname sprawl. The Certbot official installation instructions list supported DNS provider plugins.

Certbot Renewal Failure Decision TreeRenewal failed?Port 80 blocked?Fix UFW / SG rules404 on challenge?Fix webroot pathDNS wrong?Update A recordRate limited?Use --stagingRe-run: certbot renew --dry-runPass = automation restored
Production troubleshooting path for failed Certbot HTTPS renewals

Multi-domain and Laravel-specific notes

Laravel apps behind Nginx often use a single public/ webroot. Point Certbot's webroot flag there. Ensure APP_URL in .env uses https:// after redirect is enabled.

For WooCommerce or custom eCommerce stacks, mixed-content warnings usually mean hard-coded http:// asset URLs. Fix those in the database or config — the certificate itself is fine. See Quick And Easy Nepalese Grocery and similar Laravel eCommerce work for HTTPS-first deployment patterns.

Monitoring complements automation. Add an external uptime check that alerts 14 days before certificate expiry. Many teams pair this with support and maintenance plans so renewal regressions get caught during routine server reviews.

Hard-fail practices to avoid

  • Disabling port 80 after obtaining a certificate — HTTP-01 renewal needs it
  • Deleting /etc/letsencrypt during server migrations without backing up keys
  • Running Certbot on multiple servers against the same hostname simultaneously
  • Ignoring failed dry-runs because "the site still loads today"

Website migrations need a deliberate TLS cutover plan. Our website migration service re-runs Certbot on the destination before DNS flips.

Key Takeaways

  • Install Certbot via Snap or apt, then choose the plugin matching your web server: --nginx, --apache, or --webroot.
  • Run certbot renew --dry-run after every vhost change and after initial issuance to confirm automation works.
  • Add a deploy hook that runs nginx -t or apachectl configtest before reload so bad configs never go live.
  • Keep port 80 open permanently — HTTP-01 validation and redirects both depend on it.
  • Monitor expiry externally; systemd timers fail quietly if the server clock drifts or disk fills up.
  • Use Let's Encrypt staging when testing new domains to avoid production rate limits.

People Also Ask

Does Let's Encrypt auto-renew for free?

Yes. Let's Encrypt certificates cost nothing and Certbot renews them automatically via systemd timer or cron. You pay only for server time and the engineering to configure it correctly.

How often does Certbot renew certificates?

Certbot checks twice daily but only renews certificates within 30 days of their 90-day expiry. Most successful renewals happen around day 60, giving you a month to fix failures.

Can I automate HTTPS with Certbot on shared hosting?

Only if your host allows shell access and custom TLS configuration. Webroot mode works when you can write to the document root and serve /.well-known/acme-challenge/ over HTTP.

What happens if auto-renewal fails?

The existing certificate keeps working until it expires. Browsers then show security warnings and search rankings may suffer. Fix the root cause, pass a dry-run, and confirm the deploy hook reloads your server.

Ship HTTPS automation you can forget about

Manual certificate management does not survive busy launch schedules or holiday weekends. When you automate HTTPS with Lets Encrypt and Certbot, you get free TLS, predictable renewals, and one less production fire drill every quarter. Start with a clean dry-run, add deploy hooks, and keep port 80 alive.

Need help hardening TLS across Apache, Nginx, or a multi-site Deployer pipeline? Review our web development services, browse the Court Marriage in Nepal portfolio for live HTTPS examples, or contact us to audit your current certificate setup.

Frequently Asked Questions

No. Let's Encrypt certificates are free, and Certbot renews them automatically via a systemd timer or cron. You pay only for server hosting and the time to configure DNS, open ports 80 and 443, and verify renewals with a dry-run.

Certbot checks twice daily but only renews within 30 days of the 90-day expiry. Most successful renewals happen around day 60, leaving roughly a month to fix failures before browsers show warnings.

Let's Encrypt is a free certificate authority that issues domain-validated TLS certificates through the ACME protocol. Certbot is the official EFF client that talks to Let's Encrypt on your behalf. Automation means three things in practice: initial issuance proves you control the hostname, scheduled renewals repeat that proof before expiry, and a deploy hook reloads Apache or Nginx so visitors immediately receive the new certificate. On production Ubuntu servers I treat TLS as infrastructure, not a launch-day afterthought.

On Ubuntu 22.04 or 24.04, use Snap or apt packages — both work in production. I prefer Snap on fresh servers because it tracks upstream Certbot releases closely: install core, refresh it, then install certbot with the classic confinement flag and symlink it to /usr/bin/certbot. With apt, run apt update, install certbot, and add only the plugin matching your web server: python3-certbot-nginx or python3-certbot-apache. Confirm certbot --version shows a recent release before requesting any certificate.

The plugin choice determines how Certbot proves domain control during HTTP-01 challenges. Use --nginx on Nginx sites with no downtime — it edits config and reloads automatically. Use --apache on Apache virtual hosts, which works well with PHP-FPM stacks. Use --webroot when plugins cannot parse complex configs; Certbot writes a token under your document root. Standalone binds port 80 and requires stopping the web server temporarily. Use DNS-01 for wildcard certificates or sites behind a CDN orange-cloud proxy that blocks direct HTTP validation.

Before any certificate request, confirm DNS A or AAAA records point to this server's public IP. Ensure ports 80 and 443 are open in UFW or your cloud security group. The virtual host must serve the correct server_name on port 80. If a CDN proxy blocks direct HTTP validation, switch to DNS-01 instead of HTTP-01. If DNS is still propagating, wait before running Certbot. On client projects I confirm these records are live before TLS work begins, because a failed first run wastes time and can hit rate limits on repeated attempts.

For Nginx, run certbot --nginx with your domain flags, agree-tos, admin email, and --redirect to add HTTP-to-HTTPS redirects that prevent duplicate-content SEO issues. For Apache, use certbot --apache with the same flags, then run apachectl configtest and confirm PHP-FPM still serves dynamic pages — I have seen opcache stale paths after vhost rewrites, fixed by an FPM reload. For webroot mode, use certbot certonly --webroot pointing at your public directory, but ensure the server already maps /.well-known/acme-challenge/ to that path or validation fails every time.

Snap and apt installs register a systemd timer automatically. Check it with systemctl list-timers filtered for certbot and systemctl status certbot.timer — you should see a twice-daily trigger. Most runs exit quickly with no renewals attempted because Certbot only acts within 30 days of expiry. Always run certbot renew --dry-run after first issuance and after any Nginx or Apache config change. A passing dry-run is your best proof that automation works. On sister sites sharing a Deployer 7 pipeline, I run the dry-run after every deploy that touches vhost files.

Renewal replaces files under /etc/letsencrypt/live/yourdomain/, but the web server must reload to pick up the new fullchain. Create a script under /etc/letsencrypt/renewal-hooks/deploy/, make it executable, and test config before reload. For Nginx: nginx -t followed by systemctl reload nginx. For Apache: apachectl configtest followed by systemctl reload apache2. Without this hook, renewal can succeed while visitors still receive the old certificate until someone manually reloads the server. I add this hook on every production Ubuntu server where Certbot manages TLS.

Ubuntu Snap and apt Certbot installs register a systemd timer that triggers twice daily — this is the default and preferred approach. If no timer exists, add a fallback cron entry running certbot renew --quiet twice daily at 03:00 and 15:00, with a deploy-hook to reload your web server. Running twice daily gives room to fix failures before the 90-day cliff. Log output to a file if you want email alerts on failure. Either method works, but verify whichever scheduler you use is actually active — systemd timers fail quietly if the server clock drifts or disk fills up.

HTTP-01 validation requires Let's Encrypt to reach your server on port 80 during every renewal, not just the initial issuance. Disabling port 80 after obtaining a certificate is a hard-fail practice that breaks auto-renewal silently until expiry nears. Port 80 also serves HTTP-to-HTTPS redirects when you use the --redirect flag during setup. Keep UFW or your cloud security group allowing both 80 and 443 permanently. On production Laravel and WordPress servers behind Nginx, I verify ss -tlnp shows something listening on port 80 before trusting any dry-run result.

Start every investigation with certbot renew --dry-run -v and tail the last 100 lines of /var/log/letsencrypt/letsencrypt.log. Connection refused on port 80 usually means a firewall block or Nginx not listening — open UFW port 80 and verify with ss -tlnp. A 404 on the challenge URL means a missing webroot or wrong server_name — add a /.well-known/ location block. Too many requests means you hit Let's Encrypt rate limits — use staging first and wait one week. If renewal succeeds but the site still serves the old cert, add a deploy hook reload script.

The existing certificate keeps working until its 90-day expiry date. Browsers then show security warnings, payment gateways may reject connections, and search rankings can suffer. Fix the root cause — DNS, firewall, missing webroot, or a failed deploy hook — then pass certbot renew --dry-run and confirm the deploy hook reloads your server. Monitor externally with an uptime check that alerts 14 days before certificate expiry. Ignoring failed dry-runs because the site still loads today is how law-firm portals and eCommerce stores go offline on a Sunday with nobody watching.

Only if your host allows shell access and custom TLS configuration. Webroot mode works when you can write to the document root and serve /.well-known/acme-challenge/ over HTTP on port 80. Without SSH, cron access, or the ability to reload the web server after renewal, full automation is not realistic — you may get a certificate once but not reliable renewals. Managed hosts with cPanel sometimes offer their own Let's Encrypt integration instead. For production Laravel or WordPress apps where you control the Ubuntu server, Snap or apt Certbot with the matching web server plugin is the approach I use on client projects.

Production rate limits matter when you manage many client subdomains from one server. Let's Encrypt allows 50 certificates per registered domain per week, 5 duplicate certificates per week for the same hostname set, and 300 new orders per account per 3 hours. Agencies managing many client subdomains should centralise account keys carefully. Wildcard certificates via DNS-01 reduce hostname sprawl compared to issuing separate certs for every subdomain. Use the staging environment when testing new domains — staging certificates are not trusted by browsers but do not count against production rate limits.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: