Install SSL Certificates on Ubuntu

Khimananda Oli 8 min read Virtualization
Install SSL Certificates on Ubuntu

By Khimananda Oli | Last reviewed: August 2026

You need to install SSL certificates on Ubuntu to encrypt traffic, satisfy browser security requirements, and meet compliance standards like SOC 2 or ISO 27001. On Ubuntu 24.04 LTS, the standard production path is Certbot with the Nginx plugin, which handles issuance, installation, and automated renewal without downtime. This guide walks you through the exact commands, secure configuration, and verification steps I use in client environments ranging from Kathmandu-based startups to global SaaS platforms.

How Do You Install SSL Certificates on Ubuntu Using Certbot?

The most reliable way to install SSL certificates on Ubuntu in 2026 is via Certbot with the official Nginx plugin. This method avoids manual file placement errors and integrates directly with your web server configuration. Before starting, ensure your domain resolves to this server’s public IP and that ports 80 and 443 are open in UFW. If you’re setting up a fresh VPS, follow the initial Ubuntu server setup guide first to harden SSH and configure the firewall correctly.

Prerequisites and Installation

  1. Update package indexes and install Certbot with the Nginx plugin:
    sudo apt update && sudo apt upgrade -y
    sudo apt install certbot python3-certbot-nginx -y
  2. Verify Nginx is running and has a valid server block for your domain:
    sudo systemctl status nginx
    sudo nginx -t
  3. Ensure DNS A/AAAA records point to this server. Propagation delays will cause validation failures.

Certificate Issuance and Automatic Configuration

Run Certbot in interactive mode to obtain and install the certificate in one step:

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

Certbot will prompt for an email (used for expiry warnings), agree to terms, and optionally redirect HTTP to HTTPS. Choose redirect unless you have a specific reason not to. The tool edits your Nginx server block in place, adding ssl_certificate, ssl_certificate_key, and modern TLS parameters. It also creates a renewal hook that reloads Nginx only when a new certificate is successfully deployed.

DNS RecordsA/AAAA → Server IPLet's EncryptACME ChallengeCertbotIssue + InstallNginxTLS Config UpdatedInstall SSL Certificates on Ubuntu: Certbot WorkflowValidates domain ownership → Issues cert → Modifies Nginx → Enables HTTPS
Certbot automates the entire SSL installation process on Ubuntu, from DNS validation to Nginx configuration.

How Do You Configure Nginx for Secure SSL After Installation?

Certbot applies sensible defaults, but production environments require additional hardening. Edit your server block at /etc/nginx/sites-available/example.com to enforce modern TLS and security headers. These settings align with Mozilla’s Intermediate compatibility profile and satisfy PCI-DSS and SOC 2 technical controls.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    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_stapling on;
    ssl_stapling_verify on;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;

    root /var/www/example.com/html;
    index index.html;
}

Key improvements over default Certbot output:

  • OCSP Stapling: Reduces latency and improves privacy by having Nginx fetch and cache OCSP responses.
  • HSTS with preload: Prevents downgrade attacks. Only enable after confirming HTTPS works flawlessly; submission to hstspreload.org is irreversible for the domain.
  • TLS 1.3 priority: Modern ciphers only; disables legacy CBC modes vulnerable to padding oracle attacks.
  • Session caching: Avoids repeated handshakes for returning visitors, improving Core Web Vitals.

After editing, test and reload:

sudo nginx -t && sudo systemctl reload nginx

For deeper Nginx tuning, especially if hosting Laravel or PHP applications, refer to the Laravel deployment guide with Nginx which covers PHP-FPM integration alongside SSL.

How Does Automated SSL Renewal Work on Ubuntu?

Let’s Encrypt certificates expire every 90 days. Manual renewal is unsustainable and error-prone. Certbot installs a systemd timer (certbot.timer) that runs twice daily and renews certificates within 30 days of expiry. This automation is critical for maintaining uptime and compliance evidence.

Verify and Test Renewal

Always confirm the timer is active and functional:

sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run

The dry-run simulates renewal without hitting rate limits. Successful output shows “Congratulations, all simulated renewals succeeded.” If it fails, check logs at /var/log/letsencrypt/letsencrypt.log and verify DNS/firewall haven’t changed.

systemd TimerRuns 2x dailyCertbot Check<30 days? RenewRenew CertificateNew cert + chainReload NginxZero downtimePost-Renewal Hooks/etc/letsencrypt/renewal-hooks/deploy/Custom scripts: restart services,notify Slack, update monitoringAutomated SSL Renewal Lifecycle on Ubuntu
Systemd-driven renewal ensures certificates stay valid without manual intervention, with hooks for post-deployment actions.

Custom Post-Renewal Actions

If your application requires more than an Nginx reload (e.g., restarting a Node.js app that caches certs), create a deploy hook:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/restart-app.sh
#!/bin/bash
# Only run for specific domains
if [[ "$RENEWED_DOMAINS" == *"example.com"* ]]; then
    systemctl restart myapp.service
    logger "SSL renewed for example.com; myapp restarted"
fi
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-app.sh

This hook executes only after successful renewal, preventing unnecessary restarts during dry-runs or failed attempts. For teams managing multiple services, consider integrating renewal events into your observability stack as described in the Prometheus and Grafana monitoring guide.

Certbot vs Manual SSL: Which Method Should You Use on Ubuntu?

While Certbot dominates, understanding alternatives prevents lock-in and informs architectural decisions. Here’s a practical comparison based on real-world trade-offs:

CriteriaCertbot (Recommended)Manual / Commercial CAacme.sh / Lego
Setup ComplexityLow (plugin-driven)High (manual CSR, file placement)Medium (script-based, no Python)
Auto-RenewalBuilt-in systemd timerNone (manual or custom cron)Cron-based, lightweight
Wildcard SupportDNS-01 only (requires API)Yes (paid)DNS-01 with many providers
Compliance EvidenceLogs + timestamps in /var/logVendor portal + invoicesLocal logs only
Resource FootprintPython runtime (~50MB)None (static files)Shell/Binary (~5MB)
Best ForMost Ubuntu web serversEV certs, legacy systemsContainers, minimal images

In practice, Certbot is the right choice for 95% of Ubuntu deployments. Switch to acme.sh only if Python is prohibited (e.g., hardened container images) or you need DNS-01 with a provider Certbot doesn’t support. Commercial certificates rarely offer technical advantages today; their value lies in warranty and EV indicators, which browsers no longer emphasize.

How Do You Troubleshoot Common SSL Issues on Ubuntu?

Even with automation, issues arise. Here are the most frequent problems and fixes from production incidents:

  • Mixed Content Warnings: Your site loads over HTTPS but references HTTP assets. Fix by updating asset URLs to protocol-relative (//cdn.example.com) or absolute HTTPS. Use browser devtools Network tab to identify offenders.
  • Certificate Not Trusted: Usually caused by missing intermediate chain. Certbot includes it by default, but manual installs often omit fullchain.pem. Always use fullchain.pem, not just cert.pem.
  • Renewal Failures: Check /var/log/letsencrypt/letsencrypt.log. Common causes: blocked port 80, changed DNS, or moved webroot. Re-run certbot certificates to verify current state.
  • OCSP Stapling Errors: Ensure ssl_trusted_certificate points to the chain file and that Nginx can reach ocsp.int-x3.letsencrypt.org. Test with openssl s_client -connect example.com:443 -status.
  • HSTS Lockout: If HTTPS breaks after enabling HSTS, users can’t access your site until max-age expires. Always test thoroughly before adding preload. Keep a non-HSTS staging environment for recovery.

For comprehensive server diagnostics beyond SSL, the Linux server monitoring guide with Netdata provides real-time visibility into TLS handshake performance and certificate expiry alerts.

SSL Issue DetectedCheck Browser Error / LogMixed ContentFix asset URLsUse // or https://DevTools → NetworkCert Not TrustedUse fullchain.pemVerify chain ordercertbot certificatesRenewal FailedCheck LE logPort 80 open?DNS unchanged?Test: curl -I https://siteReinstall: certbot --nginxDebug: LE log + dry-runSSL Troubleshooting Decision Tree for Ubuntu
Systematic diagnosis of SSL issues on Ubuntu: identify symptom, apply targeted fix, verify resolution.

Secure and Maintain Your Ubuntu SSL Setup

To reliably install SSL certificates on Ubuntu and keep them secure, treat SSL as part of your infrastructure-as-code and compliance posture—not a one-time task. Automate issuance with Certbot, harden Nginx beyond defaults, validate renewal monthly, and integrate certificate metrics into your monitoring. Document your TLS configuration in your runbooks; auditors will ask for it. If you’re managing multiple servers or need help designing a compliant infrastructure pipeline, reach out for a consultation—I help teams build systems that pass audits and survive traffic spikes.

Frequently Asked Questions

Use Certbot with the Nginx or Apache plugin. Run sudo apt install certbot python3-certbot-nginx then sudo certbot --nginx. This automates validation, installation, and renewal configuration in under two minutes without manual file editing.

Yes.

Run openssl s_client -connect yourdomain.com:443 -servername yourdomain.com to inspect the chain. Alternatively use curl -vI https://yourdomain.com and check for HTTP 200 plus valid issuer details in the TLS handshake output.

Yes, Certbot installs a systemd timer or cron job during setup that runs twice daily. Verify with systemctl list-timers | grep certbot. Renewals happen silently thirty days before expiry if the web server remains accessible and ports are open.

Yes.

Port 80 is required for HTTP-01 ACME challenges unless using DNS validation. Port 443 must also be open for HTTPS traffic after installation. Ensure ufw allows both: sudo ufw allow 80/tcp && sudo ufw allow 443/tcp before running Certbot.

For Nginx add return 301 https://$host$request_uri inside port 80 server block. For Apache enable mod_rewrite and add RewriteRule ^(.)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] in virtual host config then restart the service.

Usually caused by blocked port 80, incorrect DNS A record pointing to wrong IP, or web server not serving .well-known/acme-challenge directory. Check ufw status, verify DNS propagation with dig, and test challenge path accessibility via curl before retrying.

Yes but only via DNS-01 validation since HTTP-01 cannot prove wildcard ownership. Use plugins like certbot-dns-cloudflare or certbot-dns-route53. Configure API credentials in /etc/letsencrypt/dns.ini then run certbot certonly --dns-cloudflare -d .example.com.

Place certificate and intermediate chain in /etc/ssl/certs and private key in /etc/ssl/private with 600 permissions. Update Nginx ssl_certificate to point to fullchain.pem and ssl_certificate_key to privkey.pem then reload the web server.

Functionally identical encryption and browser trust. Paid certificates offer extended validation display, warranty coverage, and longer validity periods up to thirteen months. Let's Encrypt issues ninety-day DV certs automatically free. Choose paid only for compliance or brand assurance requirements.

Mixed content occurs when pages load HTTP resources over HTTPS. Search source code for http:// references and update to https or protocol-relative URLs. Use browser dev tools Network tab to identify specific assets causing warnings then fix at application level.

Yes.

Run sudo certbot revoke --cert-path /etc/letsencrypt/live/domain/fullchain.pem. This notifies the CA to add it to CRL and OCSP responders. Delete local files afterward with certbot delete. Revocation is irreversible so confirm necessity first.

Set 600 permissions owned by root:root using chmod 600 /etc/ssl/private/*.key. Never store keys in web-accessible directories or version control. Nginx and Apache read keys as root during startup then drop privileges ensuring runtime security compliance.