Install Let's Encrypt SSL on VPS with Certbot

Let's Encrypt is a free Certificate Authority that issues SSL certificates via the Certbot client tool, handling automatic renewal. This guide covers installation on Ubuntu VPS for both Nginx and Apache.

Prerequisites

Install Certbot

sudo apt update
sudo apt install snapd -y
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Get Certificate for Nginx

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

Certbot automatically edits your Nginx config and adds HTTP → HTTPS redirect.

For manual control, use certonly mode:

sudo certbot certonly --nginx -d yourdomain.com

Get Certificate for Apache

sudo apt install python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

Let's Encrypt vs Paid SSL: When to Choose Which

Let's Encrypt works well for most websites needing basic HTTPS. However, paid SSL certificates offer additional value in certain scenarios. Use this comparison to make the right choice for your situation.

Feature Let's Encrypt Paid SSL (OV/EV)
Cost Free From 1,000+ THB/year
Certificate type DV only DV / OV / EV / Wildcard
Validity 90 days (auto-renewed) 1 or 3 years
Identity validation Domain only OV: Organization / EV: Strict
Wildcard Supported via DNS challenge Full support, no DNS challenge needed
Warranty None Included (varies by issuer)
Best for Personal sites, blogs, dev servers, startups E-commerce, banking, enterprises, multi-subdomain

In summary: if your site is a WordPress blog, portfolio, or web app that doesn't handle payments directly, Let's Encrypt is perfectly adequate. For e-commerce or sites requiring Wildcard coverage across many subdomains, a paid SSL certificate is worth considering.

Verify Installation

sudo certbot certificates

Test renewal:

sudo certbot renew --dry-run

Automatic Renewal

Certbot installs a systemd timer automatically to renew certificates daily. Check it:

sudo systemctl status certbot.timer

Add a post-renewal hook to reload Nginx:

sudo nano /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh

Configuring HTTPS Redirect and HSTS for Maximum Security

After installing SSL, the next critical step is forcing all traffic to HTTPS and adding the HTTP Strict Transport Security (HSTS) header to tell browsers they must connect via HTTPS only. This prevents downgrade attacks and mixed-content issues.

Nginx: HTTPS Redirect and HSTS

# /etc/nginx/sites-available/yourdomain.com

# HTTP to HTTPS redirect
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

# HTTPS server block
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;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # HSTS (1 year)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
}

Apache: HTTPS Redirect and HSTS

# /etc/apache2/sites-available/yourdomain.com.conf

<VirtualHost *:80>
    ServerName yourdomain.com
    Redirect permanent / https://yourdomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>

Restart your web server after editing config:

# Nginx
sudo nginx -t && sudo systemctl reload nginx

# Apache
sudo apachectl configtest && sudo systemctl reload apache2

Test your SSL configuration at SSL Labs (ssllabs.com/ssltest/) to see your grade and further improvement suggestions. Aim for grade A or higher.

Monitoring Certificate Expiry Automatically

Even with Certbot's automatic renewal, set up additional monitoring so you receive alerts before a certificate expires — especially in cases where Certbot encounters errors or DNS issues.

Check expiry date using openssl:

echo | openssl s_client -servername yourdomain.com \
  -connect yourdomain.com:443 2>/dev/null \
  | openssl x509 -noout -dates

Create a warning script that triggers when fewer than 30 days remain:

#!/bin/bash
# /usr/local/bin/check-cert-expiry.sh
DOMAIN="yourdomain.com"
DAYS_WARN=30
EXPIRY=$(echo | openssl s_client -servername $DOMAIN \
  -connect $DOMAIN:443 2>/dev/null \
  | openssl x509 -noout -enddate \
  | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -le $DAYS_WARN ]; then
  echo "WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days!"
  # Add email notification command here
fi

Add this script to cron to run daily:

# Run check every day at 09:00
0 9 * * * /usr/local/bin/check-cert-expiry.sh

Alternatively, use a monitoring tool such as Uptime Kuma which includes built-in SSL certificate monitoring with configurable alert thresholds, or any external monitoring service that can send email or webhook notifications when a certificate is close to expiry.

Common Troubleshooting

Port 80 Blocked

sudo ufw allow 80/tcp && sudo ufw allow 443/tcp

DNS Not Propagated

Check: dig +short yourdomain.com — must return your VPS IP.

Certificate Expired and Won't Renew

sudo certbot renew --force-renewal -d yourdomain.com

SSL Best Practices and Pre-Deployment Checklist

Before pushing your website to production, verify that your SSL configuration is complete and secure. Use this checklist to avoid common pitfalls.

SSL Installation Checklist

Verify TLS Protocol Versions

Disable old TLS versions (1.0 and 1.1) and enable only TLS 1.2 and 1.3. For Nginx, check /etc/letsencrypt/options-ssl-nginx.conf and confirm it contains:

ssl_protocols TLSv1.2 TLSv1.3;

For Apache, check ssl.conf:

SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1

Disabling old TLS versions prevents vulnerabilities like POODLE and BEAST and improves your SSL Labs grade.

Multi-Domain Certificate (SAN)

If you host multiple domains on a single VPS, you can request a certificate covering all of them in one command:

sudo certbot --nginx \
  -d domain1.com -d www.domain1.com \
  -d domain2.com -d www.domain2.com \
  -d domain3.com

Let's Encrypt supports up to 100 domains per certificate (SAN). In practice, group certificates by application for easier management and renewal tracking.

Additional Tips for Let's Encrypt on VPS

Summary: Let's Encrypt via Certbot is the easiest free SSL for VPS, auto-renewing every 90 days. For OV/EV or Wildcard SSL covering multiple subdomains, AsiaGB offers a range of commercial SSL certificates.

VPS for Your Web Server

AsiaGB VPS Ubuntu includes Full Root Access — install Nginx/Apache + SSL immediately. From 500 THB/month.

View VPS Plans