Let’s say you’re not a DevOps developer. You’re a pretty good front-end developer, a back-end developer, maybe even a mobile developer. But here’s the problem: you have a server, and it needs SSL. And the DevOps developer is on vacation. Or not hired at all. So you’re standing there, looking at the terminal and thinking: “Well, that’s it, now I’m a DevOps developer.” 😅

Don’t be scared. Today I’ll tell you how to quickly and automatically set up SSL certificates from Let’s Encrypt using Certbot on Ubuntu. With jokes, examples and bash magic.


🔒 Why do you need Certbot and Let’s Encrypt?

Let’s Encrypt is a free certificate authority. It allows you to issue SSL certificates for HTTPS. Certbot is a utility for automatically obtaining and renewing these certificates.

A combo for those who don’t want to bother with manual key generation and visits to commercial CAs.


🚀 Installing Certbot

sudo apt update
sudo apt install certbot

Important:  Certbot must be run on the same server for which you want to issue a certificate.


📜 Obtaining a certificate (and displaying information about current certificates)

sudo certbot certonly --standalone -d project.com -d www.project.com
sudo certbot certificates
  • --standalone means that Certbot will temporarily set up its own server on port 80 to validate the domain.
  • Make sure port 80 is not busy!  Otherwise nothing will work.

    If your Nginx or Docker is there, stop it while the command is running:

sudo systemctl stop nginx

Alternative:  you can use a plugin  webroot – it does not require stopping the service and simply creates a special file in the site directory.

More information about plugins can be found  in the official documentation .


⏱ Automatic update via systemd

After installation, Certbot automatically adds a systemd timer:

systemctl list-timers | grep certbot

Example output:

Mon 2025-03-10 03:12:00 UTC  10h left  Mon 2025-03-09 03:12:00 UTC  certbot.timer  certbot.service

Check that auto-update works:

sudo certbot renew --dry-run

If everything is good:

Certbot dry-run was successful.

Latest update logs:

journalctl -u certbot.service --no-pager --since "2 days ago"

Reminder:  Certbot only renews certificates if they have < 30 days left until expiration.


🕰️ Alternative: Update via Cron

Sometimes systemd timers are inconvenient, especially if you configure everything via Ansible or shell scripts. In this case, you can use Cron.

  1. Turn off the timer:
sudo systemctl stop certbot.timer
sudo systemctl disable certbot.timer
  1. Add a Cron task:
sudo crontab -e

Example:

0 0 1 * * /usr/bin/certbot renew --standalone --quiet

To find out the exact path to  certbot, use:

which certbot

⚙️ Hooks for restarting services

Certbot can perform actions before, after, or only if a certificate is successfully renewed. This is useful if you need to stop a service, copy certificates, or restart a server.

# /etc/letsencrypt/renewal/project.com.conf

pre_hook = systemctl stop my-project.service
deploy_hook = systemctl reload my-project.service
post_hook = systemctl start my-project.service

🛠️ Script for all occasions

Instead of describing everything in the cron, you can create a bash script that will:

  1. Stop service
  2. Update certificates
  3. Copy files to the desired location
  4. Set rights
  5. Start the service back
#!/bin/bash

APP_PATH="/home/projects/project"
DOMAIN="project.com"

FULL_CHAIN_SRC="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
PRIVATE_KEY_SRC="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
FULL_CHAIN_DIST="${APP_PATH}/volumes/etc/ssl/certs/project_com.full.crt"
PRIVATE_KEY_DIST="${APP_PATH}/volumes/etc/ssl/private/project_com.key"

echo "Starting script execution: $(date "+%Y-%m-%d %H:%M:%S")"

echo "Stopping the service..."
systemctl stop my-project.service

echo "Renewing the certificates..."
/usr/bin/certbot renew --standalone --quiet
/usr/bin/certbot certificates

echo "Copying the certificates to the project..."
cp -f "$FULL_CHAIN_SRC" "$FULL_CHAIN_DIST"
cp -f "$PRIVATE_KEY_SRC" "$PRIVATE_KEY_DIST"

echo "Setting correct permissions for the certificates..."
chmod 644 "$FULL_CHAIN_DIST"
chmod 644 "$PRIVATE_KEY_DIST"

echo "Running the service..."
systemctl start my-project.service

echo "End of script execution: $(date "+%Y-%m-%d %H:%M:%S")"

And in the crown we call it like this:

0 0 1 * * sh /home/projects/project/cert-renew.sh >> /var/log/project-cert-renew.log 2>&1

🧠 Conclusion

Sometimes even a developer has to be a little bit of a DevOps. The main thing is not to be afraid of the terminal and know where to google. And also, don’t forget to check in six months that the auto-update still works. 😁

Similar Posts