
August 15, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Getting a valid TLS certificate used to mean paying annual fees and waiting days for validation. Today, HTTPS setup with Let's Encrypt and Certbot is free, automated, and takes under five minutes on a properly configured server. This guide walks through the exact commands and configuration I use on production Ubuntu 24.04 systems serving Laravel applications and legal-tech portals in Nepal.
certbot --nginx -d example.com or certbot --apache -d example.com, and verifying automatic renewal with certbot renew --dry-run. The entire process completes in minutes with zero downtime when DNS is correctly propagated.Before starting any certificate issuance, your server must have a working web root and correct DNS A/AAAA records pointing to its public IP. I always verify this first because Certbot will fail immediately if it cannot reach the domain over HTTP port 80. For developers building Laravel applications in Nepal or deploying client sites internationally, getting this foundation right prevents hours of debugging later. If you are managing multiple domains or need advanced infrastructure automation, reviewing DevOps best practices for website automation provides useful context for scaling beyond single-server setups.
How do you install Certbot on Ubuntu 24.04 for HTTPS setup with Let's Encrypt?
Ubuntu 24.04 LTS ships Certbot directly in the official repositories, which is now the recommended installation method for most deployments. The older PPA approach is no longer necessary unless you require specific pre-release features. On a fresh server, update your package index and install the appropriate plugin for your web server:
sudo apt update
sudo apt install certbot python3-certbot-nginx # For Nginx
# OR
sudo apt install certbot python3-certbot-apache # For Apache This installs Certbot 2.x (the current stable branch in 2026) along with the Python dependencies and web server plugin. The plugin is critical: it allows Certbot to automatically modify your Nginx or Apache configuration to serve the ACME challenge files and install the certificate without manual editing.
Verifying the installation
After installation, confirm everything is working before attempting issuance:
- Check the version:
certbot --versionshould return 2.x or higher. - Verify the plugin loaded:
certbot pluginslists installed authenticators and installers. - Ensure your web server is running:
systemctl status nginxorsystemctl status apache2. - Confirm port 80 is open:
sudo ufw statusmust show "80/tcp ALLOW".
A common mistake on new Ubuntu 24.04 deployments is having UFW enabled but not explicitly allowing HTTP traffic. Certbot needs port 80 open even if you intend to serve only HTTPS, because the HTTP-01 challenge validation occurs over unencrypted HTTP initially.
How do you obtain and install SSL certificates using Certbot with Nginx or Apache?
With prerequisites verified, obtaining a certificate is a single command. Certbot handles domain validation, certificate issuance, and web server configuration automatically when using the appropriate plugin.
Nginx certificate installation
sudo certbot --nginx -d example.com -d www.example.com Certbot will prompt for an email address (used for expiry notifications), ask you to agree to the Let's Encrypt Terms of Service, and optionally offer to redirect all HTTP traffic to HTTPS. I always select the redirect option for production sites; there is rarely a valid reason to serve both protocols simultaneously in 2026.
The --nginx flag tells Certbot to parse your existing Nginx configuration, insert the SSL directives into the correct server block, and reload Nginx atomically. If your site uses non-standard paths or complex includes, Certbot may fail to detect the configuration. In that case, use standalone mode instead:
sudo certbot certonly --standalone -d example.com Standalone mode temporarily binds to port 80 itself to complete validation. You must stop Nginx first (sudo systemctl stop nginx) or use the webroot method if stopping the server is unacceptable.
Apache certificate installation
sudo certbot --apache -d example.com -d www.example.com The Apache plugin works identically to the Nginx plugin but modifies virtual host files in /etc/apache2/sites-available/. It enables the SSL module automatically if not already active and creates a new -le-ssl.conf file alongside your original configuration.
Webroot method for complex setups
For Laravel applications or custom deployments where the web server configuration is managed externally (e.g., via Deployer or Ansible), the webroot method gives you full control:
sudo certbot certonly --webroot -w /var/www/example.com/public -d example.com This places challenge files in .well-known/acme-challenge/ within your document root without modifying server configuration. You then manually add the SSL directives to your Nginx or Apache config. This approach is preferable when you manage configurations as code and want Certbot to handle only certificate issuance.
How do you configure automatic SSL certificate renewal with Certbot?
Let's Encrypt certificates are valid for 90 days. Automatic renewal is mandatory for production systems; manually renewing every three months is unsustainable and error-prone. Certbot installs a systemd timer automatically during package installation on Ubuntu 24.04.
Verifying the renewal timer
sudo systemctl status certbot.timer You should see "active (waiting)" with the next trigger time listed. The timer runs twice daily at randomized intervals to avoid hammering Let's Encrypt's servers. Certbot only attempts renewal when certificates are within 30 days of expiry, so most runs exit immediately.
Testing renewal safely
Always test renewal before relying on it in production:
sudo certbot renew --dry-run The --dry-run flag simulates renewal against Let's Encrypt's staging environment without affecting live certificates. If this succeeds, automatic renewal will work. If it fails, the output shows exactly why—usually a DNS issue, firewall block, or web server misconfiguration introduced since initial issuance.
Post-renewal hooks
Some services need reloading after certificate renewal. For Nginx serving PHP-FPM applications, the web server reloads automatically via the plugin. But if you use HAProxy, Postfix, or other services consuming the same certificates, add a deploy hook:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh #!/bin/bash
systemctl reload nginx
systemctl restart postfix
echo "$(date): Certificates renewed and services reloaded" >> /var/log/certbot-deploy.log sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh Scripts in this directory execute after every successful renewal. This pattern is essential for securing websites and servers that integrate mail or proxy services alongside the primary web application.
| Renewal Method | Automation Level | Downtime Risk | Best For |
|---|---|---|---|
| Systemd timer (default) | Fully automatic | None | Standard Ubuntu 24.04 servers |
| Cron job (legacy) | Scheduled manual command | Low | Older systems, non-systemd environments |
Manual certbot renew | Human-triggered | Moderate | Troubleshooting, one-off renewals |
| Deploy hook scripts | Automatic + post-renewal actions | None | Multi-service deployments, Laravel + mail |
What security headers and SSL hardening should accompany HTTPS setup with Let's Encrypt and Certbot?
A valid certificate alone does not make a site secure. Modern browsers and security scanners expect additional headers and TLS configuration. After completing HTTPS setup with Let's Encrypt and Certbot, add these protections to your Nginx server block:
# /etc/nginx/sites-available/example.com
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;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always; HSTS (HTTP Strict Transport Security) tells browsers to never connect via HTTP again for the specified duration. Start with a shorter max-age during testing, then increase to two years once confident. The preload directive submits your domain to browser-maintained HSTS lists, but this is irreversible—only enable it after thorough testing.
OCSP stapling
Enable OCSP stapling to improve TLS handshake performance and privacy:
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s; Without stapling, browsers contact Let's Encrypt's OCSP responder separately during each new connection, adding latency and leaking browsing data. Stapling caches the OCSP response on your server and delivers it during the TLS handshake.
How do you troubleshoot common Certbot failures during HTTPS setup?
Even straightforward HTTPS setup with Let's Encrypt and Certbot encounters issues in production. These are the problems I encounter most frequently on client servers in Nepal and internationally.
DNS propagation delays
Certbot validates domain ownership by making HTTP requests to your domain. If you recently changed DNS records or added a new subdomain, propagation can take minutes to hours. Verify resolution before running Certbot:
dig +short example.com A
curl -I http://example.com/.well-known/acme-challenge/test If dig returns no result or the wrong IP, wait. If curl fails but dig is correct, check your web server configuration and firewall rules.
Port 80 blocked by ISP or cloud provider
Some Nepali ISPs and certain cloud providers block inbound port 80 by default. This breaks HTTP-01 validation entirely. Test from an external network:
curl -v http://example.com # From outside your network If blocked, either request the provider to open port 80 or switch to DNS-01 validation, which does not require HTTP access at all. DNS-01 works by placing TXT records in your DNS zone and is ideal for internal services or restrictive networks.
Certificate rate limits
Let's Encrypt enforces rate limits to prevent abuse. The most commonly hit limit is 50 certificates per registered domain per week. During development or testing, use the staging environment:
sudo certbot --staging --nginx -d dev.example.com Staging certificates are not trusted by browsers but bypass rate limits entirely. Switch to production only when your configuration is finalized.
Mixed content warnings after HTTPS migration
After enabling HTTPS, browsers may block insecure resources loaded over HTTP. For Laravel applications, ensure APP_URL in .env uses https:// and force scheme globally:
// app/Providers/AppServiceProvider.php
public function boot(): void
{
if ($this->app->environment('production')) {
URL::forceScheme('https');
}
} This ensures all generated URLs, including asset paths and form actions, use HTTPS. Without this, Blade templates and redirect responses may still reference HTTP, triggering mixed-content errors. For comprehensive technical SEO implications of HTTPS migrations, the technical SEO audit guide covers crawlability and indexation concerns specific to protocol changes.
Conclusion
Completing HTTPS setup with Let's Encrypt and Certbot on Ubuntu 24.04 is straightforward when you follow the correct sequence: verify prerequisites, choose the appropriate validation method, test renewal, and harden your TLS configuration. The entire process takes under ten minutes for standard deployments and eliminates the cost and complexity that once made HTTPS optional. In 2026, there is no excuse for serving unencrypted traffic—browsers penalize it, users distrust it, and search engines rank against it.
If you need help implementing HTTPS across multiple domains, integrating certificates into CI/CD pipelines, or auditing your existing TLS configuration for security gaps, get in touch to discuss your infrastructure requirements.

