DeployWise
HomeGuidesSSL Certificate for VPS
SSL/TLSLet's EncryptNginxSecurityVPS

Free SSL certificate for VPS: the complete guide

HTTPS is no longer optional — it's essential for SEO, security, and user trust. This guide walks you through installing free SSL certificates from Let's Encrypt, configuring Nginx, setting up auto-renewal, and troubleshooting common issues.

8 min read
Updated 2026

Why HTTPS matters (SEO, security, and trust)

HTTPS is critical for modern web. Here's why you need SSL/TLS encryption:

SEO Ranking

Google ranks HTTPS sites higher than HTTP. Missing HTTPS is an SEO penalty.

User Trust

Browsers show a warning for non-HTTPS sites. Users distrust unencrypted connections.

Security

Data is encrypted in transit. Attackers cannot intercept passwords, tokens, or sensitive data.

Compliance

PCI-DSS, HIPAA, and GDPR all require HTTPS for handling user data.

Best practice: Use Let's Encrypt for free SSL certificates with Certbot. They're trusted by all browsers, automatically renewed, and cost nothing.

Prerequisites

Before installing SSL, you need:

A VPS running Ubuntu 20.04 LTS or newer
Certbot works on Ubuntu, Debian, CentOS, and other Linux distros
Root or sudo access to your server
Certbot needs elevated permissions
A domain name pointing to your VPS
SSL certificates are bound to domain names. Ensure DNS is configured and pointing to your server IP
Nginx already installed and running
Certbot can install Nginx if needed, but it's usually pre-installed
Port 80 (HTTP) open
Let's Encrypt uses ACME challenge on port 80 to verify you own the domain

Installing Certbot on Ubuntu

Certbot is the official Let's Encrypt client. It automates certificate installation and renewal. Install it with:

bash
sudo apt update
sudo apt install certbot python3-certbot-nginx -y

This installs Certbot and the Nginx plugin. The plugin allows Certbot to automatically modify your Nginx config. Verify the installation:

bash
certbot --version

You should see something like certbot 2.x.x.

Getting your first certificate

Certbot can automatically update your Nginx config to use HTTPS. Simply run:

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

Replace yourdomain.com with your actual domain. If you have multiple domains:

bash
sudo certbot --nginx -d domain1.com -d domain2.com -d www.domain1.com

Certbot will:

Verify you own the domain by checking the ACME challenge on port 80
Download the certificate from Let's Encrypt
Install the certificate to /etc/letsencrypt/live/yourdomain.com/
Automatically update your Nginx config to use HTTPS
Restart Nginx

During installation, Certbot will ask:

Email address
Enter your email. Let's Encrypt will notify you before expiration (though auto-renewal is enabled)
Terms of Service
Type A to agree
Share email with EFF
Type Y or N (your preference)
HTTP → HTTPS redirect
Choose (1) to redirect all traffic to HTTPS (recommended)

That's it! Your certificate is installed. Visit https://yourdomain.com and check the lock icon.

Understanding your certificate files

Certbot stores certificates in /etc/letsencrypt/live/yourdomain.com/. There are four key files:

cert.pem
Your SSL certificate (public)
privkey.pem
Your private key (secret, never share)
chain.pem
Let's Encrypt intermediate certificate
fullchain.pem
Combined cert + chain (use this in Nginx)

Critical: Never commit privkey.pem to git. It's the master key to your HTTPS. If exposed, attackers can impersonate your domain.

Nginx SSL configuration

If Certbot didn't automatically configure Nginx (or you want to customize), here's the complete Nginx config:

nginx.conf
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    # Let's Encrypt ACME challenge
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # Redirect all HTTP to HTTPS
    location / {
        return 301 https://$server_name$request_uri;
    }
}

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

    # SSL certificate paths
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # SSL security settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # HSTS (optional but recommended)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Your app upstream
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Replace yourdomain.com and localhost:3000 with your values. Test and reload:

bash
sudo nginx -t
sudo systemctl reload nginx

Automatic renewal setup

Let's Encrypt certificates expire after 90 days. You need to renew them automatically. Certbot installs a systemd timer that renews certificates automatically.

Check if the timer is active:

bash
sudo systemctl list-timers | grep certbot

You should see output like:

bash
NEXT                          LEFT     LAST                      PASSED   UNIT                      ACTIVATES
Fri 2026-03-07 12:00:00 UTC  4d 14h  Wed 2026-03-03 12:00:00 UTC 4d 10h  certbot.timer             certbot.service

The timer runs daily at a random time and renews certificates that are 30 days or less from expiring. If the timer is not active, enable it:

bash
sudo systemctl enable --now certbot.timer

Test renewal manually (this doesn't actually renew, just does a dry-run):

bash
sudo certbot renew --dry-run

If it succeeds, renewal is set up correctly. Certbot will automatically renew your certificates before they expire.

Testing your SSL certificate

Use SSL Labs to check your certificate and configuration:

Visit https://www.ssllabs.com/ssltest/ and enter your domain. This checks:

  • Certificate validity and expiration date
  • TLS protocol versions (should be TLSv1.2+)
  • Cipher suite strength
  • Common vulnerabilities (Heartbleed, DROWN, etc.)
  • Certificate chain completeness

Aim for an A or A+ rating. Common issues:

Missing HSTS header - add to Nginx config: add_header Strict-Transport-Security max-age=31536000;
Old TLS versions enabled - use TLSv1.2 and TLSv1.3 only
Weak ciphers - use HIGH:!aNULL:!MD5
Missing intermediate certificates - use fullchain.pem, not cert.pem

Wildcard certificates

A wildcard certificate covers all subdomains: *.yourdomain.com matches api.yourdomain.com, app.yourdomain.com, etc. Install with:

bash
sudo certbot certonly --manual --preferred-challenges=dns -d yourdomain.com -d '*.yourdomain.com'

This uses manual DNS validation instead of HTTP. Certbot will ask you to add a TXT record to your DNS:

bash
_acme-challenge.yourdomain.com. 300 IN TXT "randomstring123..."

Add this TXT record in your DNS provider's dashboard. Wait for propagation (check with dig _acme-challenge.yourdomain.com), then press Enter in Certbot.

For easier management, use certbot-dns-* plugins (e.g., certbot-dns-route53 for AWS) to automate DNS validation.

Common SSL issues and fixes

DNS not pointing to your VPS
  • Certbot uses port 80 to verify you own the domain. If DNS doesn't point to your VPS, verification fails.
  • Check: nslookup yourdomain.com (should return your VPS IP)
  • Update DNS at your registrar (GoDaddy, Namecheap, etc.) to point to your VPS
  • Wait 15-30 minutes for DNS propagation (use mxtoolbox.com/dnschecker.com to verify)
Port 80 blocked by firewall or VPS provider
  • Let's Encrypt needs port 80 (or 443 for standalone) to verify domain ownership
  • Check if port 80 is open: sudo ufw status (for UFW firewall) or check your VPS provider's dashboard
  • If using UFW, allow port 80: sudo ufw allow 80/tcp
  • If using AWS Security Groups / Azure NSG, add inbound HTTP rule
  • If you can't open port 80, use DNS validation instead: certbot certonly --manual --preferred-challenges=dns
Certificate renewal failing
  • Check renewal logs: sudo systemctl status certbot.timer
  • Manually test renewal: sudo certbot renew --dry-run (if this fails, the real renewal will fail too)
  • Common cause: Port 80 blocked during renewal check. Ensure port 80 stays open.
  • Check Certbot service status: sudo journalctl -u certbot.service --no-pager | tail -20
  • If renewal is failing, run: sudo certbot renew --force-renewal (this forces immediate renewal)
Too many certificates issued (rate limit)
  • Let's Encrypt has rate limits: 50 certificates per domain per week
  • If you hit this, wait a week or use a different domain
  • This only happens during testing or if you're issuing many certs. Normal renewal is not counted.
  • Use staging: certbot --staging to test without hitting rate limits
Certificate shows as invalid in browser
  • Wrong domain in cert - check: openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text
  • Using fullchain.pem instead of cert.pem - fix Nginx config to use fullchain.pem
  • Nginx not reloaded after cert installation - run: sudo systemctl reload nginx
  • Browser cache - clear cache or use incognito mode
Renewal script permission issues
  • If renewal fails with permission denied, Certbot may need sudo
  • Check permissions: ls -la /etc/letsencrypt/ (should be readable by Nginx user)
  • Fix ownership: sudo chown -R root:root /etc/letsencrypt/
  • Ensure Nginx can read the cert: sudo usermod -aG ssl-cert www-data (if applicable)

How DeployWise automates SSL

Managing SSL certificates across multiple servers and renewals is tedious. DeployWise automates the entire SSL lifecycle:

One-click SSL setup
Add a domain, DeployWise installs Let's Encrypt cert and configures Nginx automatically
Automatic renewal
Certificates are renewed 30 days before expiration. No manual intervention needed.
Multi-domain support
Manage dozens of domains and subdomains from one dashboard
Monitoring & alerts
Get notified if a certificate expires or renewal fails
Wildcard certificates
Automatic DNS validation for wildcard certs across all subdomains
Multiple servers
Deploy and renew SSL on all your VPS at once with one click

Instead of manually running Certbot on each server and monitoring renewals, DeployWise handles the entire SSL workflow. Focus on your app, not server certificates.

SSL best practices checklist

Always use HTTPS (never leave HTTP-only apps in production)
Redirect all HTTP to HTTPS at the Nginx level
Use Let's Encrypt for free, automated certificates (no other choice needed)
Enable systemd timer for automatic renewal (certbot enables this by default)
Use fullchain.pem in Nginx, not cert.pem (avoids intermediate cert issues)
Set HSTS header to enforce HTTPS: add_header Strict-Transport-Security max-age=31536000;
Keep TLS versions modern: TLSv1.2+ only (disable SSLv3, TLSv1.0, TLSv1.1)
Use strong ciphers and disable weak ones (HIGH:!aNULL:!MD5)
Test your SSL configuration with ssllabs.com (aim for A or A+ grade)
Keep certbot updated: sudo apt update && apt install certbot
Backup your certificates and private keys securely
Review renewal logs monthly: sudo journalctl -u certbot.service
For wildcard certs, use automated DNS validation (avoid manual challenges)
Monitor certificate expiration: set a calendar reminder or enable DeployWise alerts

Automate SSL certificates across all your servers

DeployWise eliminates manual SSL management. Install certificates, auto-renew, and monitor expiration — all from one dashboard. No more expired certificates.

Launch DeployWise