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.

Set Up Free SSL with Let's Encrypt and Certbot

By Kokil Thapa | Last reviewed: September 2026

Every production website needs HTTPS in 2026. Browsers flag HTTP as insecure, search engines reward encrypted pages, and payment gateways refuse plain-text checkout flows. If you run Laravel, WordPress, or a custom PHP app on Ubuntu, the fastest path is to set up free SSL with Let's Encrypt and Certbot. I've done this on dozens of client servers — from legal-tech portals to WooCommerce shops — and the process is straightforward once DNS, ports, and your web server config align. This guide walks through install, issuance, renewal, and the failures I see most often in the field.

What do you need before you set up free SSL with Let's Encrypt and Certbot?

Let's Encrypt issues Domain Validation (DV) certificates at no cost. Certbot is the official client that talks to the ACME protocol, proves you control the domain, and writes certificate files to disk. Before you run either tool, confirm four prerequisites.

  • A registered domain with an A record (or AAAA for IPv6) pointing to your server's public IP.
  • Port 80 open for HTTP-01 validation, or port 443 if you use TLS-ALPN-01.
  • A working web server — Apache or Nginx — serving a response on that domain.
  • Root or sudo access on Ubuntu 22.04 or 24.04 LTS.

On shared hosting in Nepal, your provider may offer a one-click SSL panel instead. For VPS or dedicated servers you manage yourself, Certbot is the standard. If you also handle domain registration and hosting setup, get DNS propagation right first. Use a DNS lookup tool or wait 15–60 minutes after changing records.

Let's Encrypt ACME Certificate FlowYour ServerApache / NginxCertbotACME ClientLet's EncryptACME CABrowserHTTPS :443HTTP-01 Challenge Steps1. Certbot requests cert for example.com2. CA sends random token file path3. CA fetches http://example.com/.well-known/...4. Cert issued to /etc/letsencrypt/live/
How Let's Encrypt validates domain ownership before Certbot installs your free SSL certificate

Certificates expire after 90 days. That short lifetime is intentional. It limits damage from compromised keys and forces automated renewal. Manual yearly renewals belong to the old paid-CA era. Plan for automation from day one.

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

Install Certbot through the official snap package or your distribution repository. Snap tracks current releases and is what the Certbot documentation recommends for most Linux systems.

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

For Apache plugin support, ensure Apache is running first. For Nginx, confirm your site block responds on port 80 before requesting a certificate.

Install via apt (alternative)

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

Check the version after install:

certbot --version

On production Laravel stacks I maintain, PHP 8.3 or 8.5 runs behind Apache with mod_proxy or Nginx as a reverse proxy. Certbot sits outside the app layer. It only manages TLS termination at the web server. See our LEMP stack guide if you are building the server from scratch.

How do you set up free SSL with Let's Encrypt and Certbot on Apache?

Apache with a valid VirtualHost is the simplest path on Ubuntu servers I admin daily. Certbot reads your existing vhost, injects SSL directives, and reloads Apache.

  1. Create a VirtualHost on port 80 with ServerName matching your domain.
  2. Confirm the site loads at http://yourdomain.com.
  3. Run Certbot with the Apache plugin.
  4. Test HTTPS and HTTP-to-HTTPS redirect.

Example VirtualHost before SSL:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example/public

    <Directory /var/www/example/public>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Issue the certificate interactively:

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

Certbot asks for an email address, agrees to terms, and optionally shares your email with the Electronic Frontier Foundation. Choose redirect when prompted — it adds a permanent 301 from HTTP to HTTPS. That redirect matters for technical SEO. Google treats the HTTP and HTTPS versions as duplicates without it.

Non-interactive mode suits CI and server provisioning scripts:

sudo certbot --apache \
  -d example.com -d www.example.com \
  --non-interactive --agree-tos \
  -m admin@example.com --redirect

Certificate files land in /etc/letsencrypt/live/example.com/. Apache references them through symlinks Certbot writes into your SSL vhost. Never copy those files manually — always let Certbot manage paths.

Certbot SSL Setup PipelineDNS ReadyInstallRun CertbotVerify HTTPSPost-Install Checklist✓ curl -I https://example.com returns 200 or 301✓ openssl s_client -connect example.com:443✓ UFW allow 443/tcp✓ Enable certbot renew timer
Step-by-step pipeline to set up free SSL with Let's Encrypt and Certbot on a production Ubuntu server

How do you set up free SSL with Let's Encrypt and Certbot on Nginx?

Nginx needs a server_name block listening on port 80 before Certbot can complete HTTP-01 validation. If you terminate TLS at Nginx and proxy to PHP-FPM, the pattern is the same.

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

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Issue the certificate:

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

Certbot adds a second server block on port 443 with ssl_certificate and ssl_certificate_key directives. It also configures the HTTP-to-HTTPS redirect. For advanced proxy setups — multiple backends, WebSocket headers — read our reverse proxy with Nginx guide.

Manual certificate-only mode works when you prefer to edit Nginx yourself:

sudo certbot certonly --webroot \
  -w /var/www/example/public \
  -d example.com -d www.example.com

Then reference the cert paths in your own SSL server block:

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

Reload Nginx after any manual edit:

sudo nginx -t && sudo systemctl reload nginx
MethodBest forCertbot commandConfig changed by
Apache pluginLaravel/PHP on mod_php or proxycertbot --apacheCertbot edits vhost
Nginx pluginLEMP, reverse proxycertbot --nginxCertbot edits server block
WebrootCustom configs, Dockercertbot certonly --webrootYou edit manually
StandaloneNo web server yet, port 80 freecertbot certonly --standaloneTemp listener only

Standalone mode stops anything on port 80 temporarily. Use it during initial server setup before Apache or Nginx goes live. Never run standalone on a production box serving traffic.

How do you automate Let's Encrypt certificate renewal with Certbot?

Let's Encrypt certificates expire every 90 days. Certbot renews them when 30 days or less remain. The snap package installs a systemd timer automatically. Verify it:

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

Test renewal without actually replacing the cert:

sudo certbot renew --dry-run

A successful dry run means your cron or timer will work silently for years. I've seen law-firm sites go dark because nobody tested renewal after a server migration. Our auto-renewal failures article covers the full diagnostic list.

Hook scripts for zero-downtime reload

After renewal, the web server must reload to pick up new certificate files. Certbot deploy hooks handle this:

sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-webserver.sh
#!/bin/bash
systemctl reload apache2
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-webserver.sh

On sister sites I deploy with Deployer 7 and GitLab CI, renewal runs on the server independently of application deploys. TLS and app releases should not share a pipeline step. Keep them separate.

Apache vs Nginx Certbot SetupApache• mod_ssl + VirtualHost• certbot --apache• .htaccess still works• Common on shared VPS• Laravel public/ root• systemctl reload apache2Nginx• server block + try_files• certbot --nginx• Faster static files• LEMP stack default• php-fpm upstream• nginx -t then reload
Choosing Apache or Nginx affects which Certbot plugin you run when setting up free SSL

What are common Certbot and Let's Encrypt errors in production?

Most failures are environmental, not Certbot bugs. Fix the underlying condition and re-run the same command.

DNS and connectivity failures

NXDOMAIN or wrong IP: The domain does not resolve to your server. Check A records at your registrar or Cloudflare panel. Propagation can take up to 48 hours across rare resolvers.

Connection refused on port 80: UFW or cloud security groups block inbound HTTP. Open the port:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

AWS, DigitalOcean, and local Nepali VPS providers all have network-level firewalls separate from UFW. Check both layers.

Rate limits

Let's Encrypt allows 50 certificates per registered domain per week. Staging helps during development:

sudo certbot --apache --staging -d test.example.com

The staging CA issues untrusted certs. Use it to validate your automation before hitting production limits. Full rate limit docs live on the Let's Encrypt website.

Webroot and permission issues

HTTP-01 places a file at /.well-known/acme-challenge/. If Nginx serves a custom 404 or Laravel catches all routes, validation fails. Add a dedicated location block:

location ^~ /.well-known/acme-challenge/ {
    root /var/www/certbot;
    allow all;
}

File ownership matters too. Certbot often runs as root but your app runs as www-data. Mismatched permissions on /etc/letsencrypt/archive/ break reloads after renewal.

Mixed content and HSTS

After SSL works, audit pages for hard-coded http:// asset URLs. Browsers block mixed content on secure pages. Add HSTS only when you are confident HTTPS is stable everywhere:

# Apache — inside SSL VirtualHost
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

HSTS with a broken subdomain locks users out until the cert is fixed. Test on staging first. Our staging environment guide explains how to mirror TLS settings safely.

Certbot Renewal TroubleshootingRenewal Failed?Check DNS / Port 80dig +short A recordCheck Webroot Path.well-known accessFix UFW / Cloud FWallow 80 and 443Fix Nginx Locationbypass Laravel routescertbot renew --dry-run
Decision tree for diagnosing Let's Encrypt and Certbot renewal failures on production servers

For multi-domain setups — apex plus www plus staging — use a single certificate with multiple -d flags or separate certs per vhost. Wildcard certs require DNS-01 validation through a DNS provider plugin. That path needs API credentials at Cloudflare or Route53. HTTP-01 cannot issue wildcards.

After HTTPS is live, harden the rest of the stack. Generate strong database and admin passwords with our password generator tool. Schedule periodic testing and optimization passes that include SSL Labs scans and Core Web Vitals checks.

On a recent notary service portal migration, the old host still answered on port 80 for the same domain during DNS cutover. Let's Encrypt validated against the wrong server and issuance failed twice before TTL expired. Patience and a lower TTL before migration prevent that loop.

If you need a deeper walkthrough with alternate validation methods, the companion post on HTTPS setup with Let's Encrypt covers overlapping ground from a security-first angle. For ongoing server care after go-live, support and maintenance plans typically include renewal monitoring and expiry alerts.

Key Takeaways

  • Point DNS to your server and open ports 80 and 443 before running Certbot — most failures start there.
  • Use certbot --apache or certbot --nginx for automatic vhost configuration on Ubuntu.
  • Run certbot renew --dry-run after every server change to confirm automation still works.
  • Enable HTTP-to-HTTPS redirects immediately — they protect SEO and stop mixed-scheme duplicate URLs.
  • Keep TLS management separate from application deploys; renewals should not depend on a code release.
  • Test with the Let's Encrypt staging CA during development to avoid weekly rate limits.

People Also Ask

Is Let's Encrypt really free for commercial websites?

Yes. Let's Encrypt issues DV certificates at no charge for any domain, including commercial sites. There is no per-seat or per-domain fee. You pay only for server and admin time. Extended Validation (EV) certs from paid CAs still exist for specific compliance niches, but most Laravel, WordPress, and eCommerce sites do not need them.

How long does a Let's Encrypt certificate last?

Each certificate is valid for 90 days. Certbot auto-renews when 30 days or less remain. Shorter lifetimes improve security by limiting key exposure windows. They also push operators toward automation instead of manual yearly renewals.

Can I use Certbot on Windows or cPanel hosting?

Certbot targets Linux servers with root access. Windows IIS has ACME clients like win-acme. cPanel and Plesk panels often include AutoSSL or built-in Let's Encrypt buttons. On raw Ubuntu VPS instances — common for Nepali businesses — Certbot via snap is the standard approach.

What happens if my Let's Encrypt certificate expires?

Browsers show a full-page security warning. Users cannot proceed easily on modern Chrome or Firefox. API clients and webhooks may fail silently. Monitoring tools should alert at 14 days before expiry. Never rely on human calendar reminders alone.

Ship HTTPS the Right Way on Your Next Project

Free TLS is no longer optional — it is baseline infrastructure. When you set up free SSL with Let's Encrypt and Certbot correctly, you get trusted encryption, better search visibility, and fewer support tickets from browser warnings. The commands take minutes. DNS alignment, firewall rules, and renewal testing take careful attention. If you want hands-off server setup — from web development through TLS hardening and speed optimization — reach out via contact us or browse the portfolio for live examples. You can also read more on the blog or learn about my background on about me.

Frequently Asked Questions

Yes. Let's Encrypt issues Domain Validation certificates at no charge for any domain, including commercial sites. There is no per-seat or per-domain fee. You pay only for server hosting and the time to install and maintain Certbot renewal automation.

Each certificate is valid for 90 days. Certbot automatically renews when 30 days or less remain. The short lifetime limits damage from compromised keys and pushes you toward automation instead of manual yearly renewals.

Confirm four prerequisites: a registered domain with an A record pointing to your server’s public IP, port 80 open for HTTP-01 validation, a working Apache or Nginx site responding on that domain, and root or sudo access on Ubuntu 22.04 or 24.04 LTS. Wait 15–60 minutes after DNS changes before running Certbot.

The recommended path is the official snap package: install and refresh core, then install Certbot with the classic confinement flag and symlink it to /usr/bin/certbot. Alternatively, use apt to install certbot plus python3-certbot-apache or python3-certbot-nginx. Run certbot --version after install. Ensure your web server is running and responding on port 80 before requesting a certificate.

Create a port-80 VirtualHost with ServerName matching your domain and confirm the site loads over HTTP. Run sudo certbot --apache -d example.com -d www.example.com, provide an email, agree to terms, and choose redirect when prompted for a permanent 301 to HTTPS. Certbot injects SSL directives into your vhost and stores certificates under /etc/letsencrypt/live/. Never copy cert files manually — let Certbot manage the paths.

Define a server block listening on port 80 with the correct server_name and document root, confirm HTTP works, then run sudo certbot --nginx -d example.com -d www.example.com. Certbot adds a port-443 block with ssl_certificate and ssl_certificate_key directives plus an HTTP-to-HTTPS redirect. For manual control, use certonly --webroot, then reference fullchain.pem and privkey.pem in your own SSL block and reload with nginx -t && systemctl reload nginx.

The Apache and Nginx plugins are best for standard setups — Certbot edits your vhost or server block automatically. Webroot suits custom configs and Docker: you run certonly --webroot and edit SSL paths yourself. Standalone temporarily binds port 80 with no web server running, useful during initial server setup only. Never use standalone on a production box already serving traffic.

The snap package installs a systemd timer that renews certificates when 30 days or less remain. Verify with systemctl status certbot.timer and list-timers. Test with sudo certbot renew --dry-run after every server change. Add a deploy hook script under /etc/letsencrypt/renewal-hooks/deploy/ to reload Apache or Nginx after renewal so new certificate files take effect without downtime.

Browsers display a full-page security warning and modern Chrome or Firefox make it hard for users to proceed. API clients and webhooks may fail silently. Set monitoring alerts at 14 days before expiry. Never rely on calendar reminders alone — a failed renewal after a server migration can take a law-firm or eCommerce site offline without anyone noticing until users complain.

Most failures are environmental. NXDOMAIN or a wrong A record means the domain does not resolve to your server — check registrar or Cloudflare records and allow up to 48 hours for rare resolver propagation. Connection refused on port 80 usually means UFW or a cloud provider security group blocks inbound HTTP. Open both port 80 and 443 at every firewall layer, not just UFW on the server itself.

HTTP-01 validation places a file at /.well-known/acme-challenge/. If Nginx serves a custom 404 or Laravel catches all routes, validation fails. Add a dedicated Nginx location block pointing to a certbot webroot with allow all. File ownership matters too — Certbot runs as root but your app runs as www-data, and mismatched permissions on /etc/letsencrypt/archive/ can break reloads after renewal.

Let's Encrypt allows 50 certificates per registered domain per week. Repeated failed issuance attempts during testing can exhaust that quota quickly. Use the staging CA with sudo certbot --apache --staging -d test.example.com during development — staging issues untrusted certificates but validates your automation without counting against production limits. Switch to production flags only once DNS, ports, and webroot paths are confirmed working.

Wildcard certificates require DNS-01 validation through a DNS provider plugin with API credentials at Cloudflare or Route53. HTTP-01 cannot issue wildcards. For apex plus www plus staging subdomains, either request one certificate with multiple -d flags or issue separate certs per vhost. Most Laravel and WordPress production sites on a single domain do not need wildcards unless you run many subdomains under one cert.

Add HSTS only after HTTPS is stable everywhere and you have audited pages for hard-coded http:// asset URLs that cause mixed-content blocking. In Apache, set Strict-Transport-Security with max-age=31536000 and includeSubDomains inside the SSL VirtualHost. A broken subdomain or expired cert combined with HSTS locks users out until the certificate is fixed, so test the full redirect chain on staging before enabling it in production.

Certbot targets Linux servers with root or sudo access, which is the standard on raw Ubuntu VPS instances common for Nepali businesses. Shared hosting providers in Nepal often offer a one-click SSL panel instead of shell access. Windows IIS uses separate ACME clients like win-acme. cPanel and Plesk include AutoSSL or built-in Let's Encrypt buttons that handle issuance without manual Certbot commands.

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: