How to install a free SSL certificate on a VPS
Installing a free Let’s Encrypt certificate with certbot, and making sure it actually renews itself before it expires.
Let's Encrypt issues free SSL/TLS certificates, and certbot is the standard tool for requesting one, installing it into your web server's configuration, and keeping it renewed automatically. This works on a VPS exactly as it does anywhere else, with one precondition: the domain must already resolve to this server's IP address, because Let's Encrypt verifies ownership by having your web server answer a request over HTTP.
If you have not already pointed the domain at this server and configured Nginx or Apache to answer for it, do that first — see hosting a domain on your VPS. Certbot's automated validation will fail against a domain that does not yet resolve here, or one the web server does not recognise.
Install certbot
sudo apt install certbot python3-certbot-nginx -y # Ubuntu / Debian, Nginx
sudo apt install certbot python3-certbot-apache -y # Ubuntu / Debian, Apache
On RHEL-family systems, certbot's packages live in the EPEL repository, which needs enabling first:
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx -y # or python3-certbot-apache
Open port 443
If a firewall is running, allow HTTPS before requesting the certificate:
sudo ufw allow 443/tcp # ufw
sudo firewall-cmd --permanent --add-service=https && sudo firewall-cmd --reload # firewalld
Request the certificate
The plugin for your web server can request the certificate and edit its configuration to use it in one step:
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot --apache -d example.com -d www.example.com
Certbot will ask for an email address (used for expiry and security notices, not published anywhere) and offer to redirect all HTTP traffic to HTTPS automatically — accept that unless you have a specific reason not to. It then edits your Nginx server block or Apache virtual host directly, adding the certificate paths and the redirect.
If you would rather issue the certificate without letting certbot touch your web server config — useful if your config is more complex than the plugin expects — request it standalone instead and wire it in yourself:
sudo certbot certonly --webroot -w /var/www/example.com/public -d example.com -d www.example.com
This writes the certificate and key to /etc/letsencrypt/live/example.com/, and you reference fullchain.pem and privkey.pem from there in your own listen 443 ssl; block.
Confirm it worked
Visit https://example.com and check the browser shows a valid padlock with no warnings. From the command line:
sudo certbot certificates
This lists every certificate certbot manages on the server along with its expiry date.
Renewal is meant to be automatic — confirm it actually is
Let's Encrypt certificates are valid for 90 days, which is short by design to keep renewal automated rather than a manual, occasionally-forgotten task. certbot installs either a systemd timer or a cron job during installation to handle this without you doing anything — but "installed by default" is not the same as "confirmed working on your server", so check it:
systemctl list-timers | grep certbot
If nothing appears there, check for a cron job instead:
cat /etc/cron.d/certbot
Either way, test that renewal actually succeeds without waiting for it to matter:
sudo certbot renew --dry-run
A clean dry run means the real renewal, whenever it fires, will work the same way. If the dry run fails, it will tell you why — commonly a firewall rule that has since changed, or a web server config that was hand-edited after certbot last touched it.
An expired certificate does not fail quietly — visitors get a hard browser warning that actively discourages them from continuing to the site. If you run more than a couple of certificates, put a reminder in place to periodically check certbot certificates, rather than assuming automatic renewal is silently succeeding month after month.
Certificates for more than one site
Each domain on the server needs its own certbot run, though a single certificate can cover multiple names if you list them together with repeated -d flags, as in the examples above. Running certbot again for a different domain does not affect certificates already issued for others — each is managed and renewed independently, and a renewal failure on one domain does not stop the others from renewing on schedule.
If a renewal genuinely fails
The most common causes are a firewall rule that changed after the certificate was first issued, a web server configuration that was hand-edited in a way that broke the validation path certbot uses, or the domain's DNS having moved away from this server entirely. Check the certbot log for the specific reason:
cat /var/log/letsencrypt/letsencrypt.log
It generally states plainly which validation step failed and why, which is almost always faster to act on than guessing.
Renewing manually, if you ever need to
sudo certbot renew
This renews every certificate on the server that is within 30 days of expiry — it is a no-op for anything further out, so it is safe to run at any time, including from your own cron job if you would rather manage the schedule yourself instead of relying on certbot's own timer.
For current SSL options across our hosting plans, see /ssl-certificates.
Related reading
Pointing a domain at your VPS is DNS plus a matching web server config — here is both halves, and how to check they agree.
How to install Nginx or ApacheInstalling Nginx or Apache on your VPS, checking it serves a page, and where each one keeps its site configuration afterwards.
How to set up cron jobs on a Linux serverThe five-field crontab syntax explained properly, plus the logging habit that stops a failed scheduled job from failing silently.
How much RAM does my VPS need?It depends what is running, but free -h on an existing server and a look at what each extra service costs gets you a real answer fast.