Install Certbot using Python PIP (Package Installer for Python) - without using SNAP, APT or SYSTEMD. (Debian/Ubuntu)
This guide will help you install LetsEncrypt / Certbot using venv PIP under Debian/Ubuntu.
-
This guide has been tested up to Debian 12 / Bookworm.
-
You should already be somewhat familiar with LetsEncrypt, Certbot and any plugin you might need.
-
A DNS plugin (AWS Route53) is used here, but this guide is about the install method- not plugins, or validation methods.
-
This pip Python install method should also work on other Linux distributions that support python3, venv, and pip.
In my opinion, this is the best install method (as of now) as the APT version is always behind and I refuse to use SNAPD.
Brady Shea / bmatthewshea 28SEP2021
Script original location: https://gist.github.com/bmatthewshea/f6a66ddb2e52ccdbc905aed73d9ca59c
Last Updated: 1JAN2025:
- Noticed Debian 12+ minimal install does not include crontab package.
- Kept crontab method, but added SYSTEMD renewal method using a timer as well.
Last Updated: 12DEC2024:
- Updated "Cronjob" area of guide. Wrote about it's importance in renewals.
- Added a check to see if "cron" is installed/found while also checking cron.d file syntax.
- Apprently, Debian 12/Bookworm has no "cron" package installed by default (at least on a headless server).
Update: 24FEB2024:
- Updated 'upgrading' to include all components involved.
- Outline cleanup and correct URLs/anchors
- Other general cleanup/typos/etc
Update 31DEC2023:
- Updated to use approved/eff.org pip install instructions. (See references below)
- These steps now use
python3 -m venv
instead of system/repo/apt pip. - Change is due to
pyopenssl
compatibility problems (the apt/repo version). (See comments) - Tested/working on Ubuntu 20, 22 and Debian 10, 11, 12.
- CERTBOT - Install using Python PIP
- 1. Cleanup, Install Python PIP, PIP dependencies and Certbot
- 2a. (Optional) Install needed plugins
- 2b. (Optional) Create an AWS-IAM credentials file
- 3. Dry Run and Execution
- 4. Setup automatic renewal (Optional, but recommended)
- 5. Setup renewal "hooks" (Optional, but recommended)
- 5. Expanding the certificate
- 6. Upgrading
- References
You should only run a single installed version of certbot.
You should not mix installation methods!
Optionally, some cleanup should be done just in case it's already installed/orphaned.
WARNING: If you have any certificates, you will need to recreate them after this!
Ignore any 'not found' errors:
sudo apt remove certbot* --purge # Purge any old certbots via apt.
sudo apt-add-repository --remove ppa:certbot/certbot # Remove certbot repo.
sudo snap remove certbot
sudo -H pip uninstall certbot; sudo -H pip3 uninstall certbot
pip uninstall certbot; pip3 uninstall certbot
sudo rm /usr/bin/certbot
sudo rm /usr/local/bin/certbot
rm ~/.local/usr/bin/certbot
rm ~/.local/bin/certbot
# You do not always need to delete the cert area, but it's usually best to start fresh:
sudo rm -rf /etc/letsencrypt
# Deactivate and remove any Certbot virtual Python environments you had running/setup.
# Example:
# `deactivate; sudo rm -rf /opt/certbot`
sudo apt update && sudo apt autoremove # Re-update and remove any orphaned packages.
Install Python 3 Pip under a virtual environment (we use /opt/certbot
here) and upgrade it:
sudo apt update && sudo apt install python3 python3-venv libaugeas0
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
Install Certbot using venv Python pip to the virtual area and then symlink it to our path:
sudo /opt/certbot/bin/pip install certbot certbot
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
Before going any further, it's a good idea to make sure it is now installed and found in path:
certbot --version
Should give something like:
certbot x.x.x
Then try:
sudo certbot certificates
-
At this point you shouldn't have any unless you chose to keep the
/etc/letsencrypt
area. -
The first run of "sudo certbot certificates" should also regenerate the
/etc/letsencrypt
area if you wiped it.
(Optional - See #4 - Renewal) Install cron/crontab scheduler (you may skip this and just use a 'systemd' timer):
sudo apt install cron
Optional - If you use AWS-Route53 DNS you'll need this. Or, pick your own plugin (if needed):
sudo /opt/certbot/bin/pip install certbot-dns-route53
For errors such as:
ERROR: zope-component 5.0.1 has requirement zope.interface>=5.3.0a1, but you'll have zope-interface 4.7.1 which is incompatible.
Upgrade the individual python package mentioned in error:
sudo /opt/certbot/bin/pip install zope.interface --upgrade
You should see: "Successfully installed zope.interface-5.4.0" depending on name-version.
If errors were encountered during plugin installation, upgrading (or reinstalling) certbot (sudo /opt/certbot/bin/pip install --upgrade certbot
) should also give 0 errors now. Re-check it is found and functions again per above (Step 1).
If so, continue on..
Again, I include this here for completeness only.
This guide is really about installing certbot using pip. If you do not use Route53, skip this.
Reference: https://certbot-dns-route53.readthedocs.io/en/stable/
sudo mkdir /root/.aws && sudo chmod 700 /root/.aws
sudo touch /root/.aws/credentials && sudo chmod 600 /root/.aws/credentials
sudo nano /root/.aws/credentials # (Add your own IAM creds in this file and save.)
Always do a "dry run" first - especially on a new install:
sudo certbot certonly --dry-run --agree-tos --dns-route53 --cert-name example -d example.net -d *.example.net
You should see: "The dry run was successful.". If so, execute same line w/o dry-run:
sudo certbot certonly --agree-tos --dns-route53 --cert-name example -d example.net -d *.example.net
If command completes successfully, you now have a functioning and up-to-date certbot installed via pip.
The importance of the "cron job" or systemd timer that schedules renewals is underated.
If it fails for any reason, your certificate may expire with little alerting.
PLEASE NOTE: Debian 12 minimal/headless install does not include the cron* packages anymore. You can install it, or use 'systemd'.
I have included both the crontab and systemd methods of automatic renewal (USE ONLY ONE METHOD).
Execute this command for a renewal cronjob. Update venv/Python path (/opt/certbot/bin) if it differs from guide:
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo /usr/bin/certbot renew -q" | sudo tee /etc/cron.d/certbot > /dev/null
- Please note that the official guide has this command tee'ed/appended to end of
/etc/crontab
. - I prefer to use
/etc/cron.d/certbot
instead. - I also recreate a new file (no
tee
flags as opposed to using-a
append flag).
Then run a check on your file -
crontab -n /etc/cron.d/certbot
That command will check your syntax and if command exists/installed.
It should come back with: The syntax of the crontab file was successfully checked.
It is worth checking that this file is being executed, or your renewal may FAIL.
If you prefer to use systemd
(and *not* CRON above), create the following two files:
sudo nano /etc/systemd/system/certbot.service
Add the following to the service file and save:
[Unit]
Description=Certbot Renewal
Documentation=https://certbot.eff.org/docs
[Service]
Type=oneshot
ExecStart=/opt/certbot/bin/certbot -q renew --no-random-sleep-on-renew
PrivateTmp=true
sudo nano /etc/systemd/system/certbot.timer
Add the following to the timer file and save:
[Unit]
Description=Run certbot renewal service twice daily
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true
[Install]
WantedBy=timers.target
Run the following commands to enable timer/renew service:
sudo systemctl enable certbot.timer && sudo systemctl start certbot.timer
"Global" hook methods (operates on all renewals regardless of certificate name, or type):
- You can opt to add it to
cli.ini
- Example:
post-hook /full/path/to/script/or/command
- Example:
- Or, directly on command line
- Example:
certbot renew --pre-hook /script/or/command --post-hook /script/or/command ...
- Example:
- Or, you can add a shell script to
/etc/letsencrypt/renewal-hooks
in the/post
or/pre
areas.
If you have many LE certificates and all of them need the same EXACT renewal parameters, you will probably want to use ONE of the "global" methods above such as the cli.ini file. You will add hook statements in same manner as the examples below, with the exception of the /renewal-hooks/
area. If you use this area, you create a shell script that stops, or restarts services (which amount to the same thing as the hook statements below).
For more granularity we are doing it a bit differently here:
We will edit the "renewal configuation" file for just one certificate.
Note: the '(certname)' is what you set for --cert-name
(when you created it above):
sudo nano /etc/letsencrypt/renewal/(certname).conf
-
If you need to execute something after renewal runs, you would add a
post_hook =
. Once a renewal happens, you will need to reload or restart any daemons/services which depend on this renewed certificate. (Examples would be a webserver, email services, etc.) -
If you need to execute something before renew runs, you would add a
pre_hook =
. An example of when this is needed is when usingstandalone
as the Certbot verification type. You will need to stop the system webserver before the renewal. You would issue a 'stop' on the pre_hook and a 'start' on the post_hook to Apache or Nginx (etc), so they aren't blocking the web port Certbot uses for verfication.
Under "[renewalparams]" add a line similar to one of the examples.
Example #1 (DNS authentication used. We only need to restart services to pickup new certificate.):
post_hook = systemctl restart apache2
Example #2 (DNS authentication used. We only need to restart services to pickup new certificate.):
post_hook = systemctl restart nginx postfix dovecot
Example #3 (Web authentication used. Needs web port open. Stop/(RE)Start web server.):
pre_hook = systemctl stop nginx
post_hook = systemctl restart nginx postfix
Example #4 (Uses DNS authentication. Web server stop unneeded. Email only server with multiple ssl virual domains.):
post_hook = /usr/sbin/postmap -F hash:/etc/postfix/vmail_ssl.map; systemctl restart postfix dovecot
Please note that you can also use a shell script instead of actual directive/commands.
If you need to add (or delete!) domain(s) at a later date, you can use the --expand
parameter to update it. Make sure you include ALL the original domains as well, or they will get removed (you will be prompted to continue before anything drastic happens).
sudo certbot certonly --expand --dns-route53 --cert-name example \
-d example.net -d *.example.net -d example.com -d *.example.com -d example.org -d *.example.org
To upgrade everything (and all dependencies), run these. You should probably do them seperately (do PIP first) and if you want to really stay up-to-date you should probably do this once a month - cronjob?:
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install --upgrade certbot
# And any plugin used:
sudo /opt/certbot/bin/pip install --upgrade certbot-dns-route53
https://letsencrypt.org/docs/
https://pypi.org/project/certbot/
https://certbot.eff.org/instructions?ws=other&os=pip
https://eff-certbot.readthedocs.io/en/stable
https://eff-certbot.readthedocs.io/en/stable/packaging.html
https://eff-certbot.readthedocs.io/en/stable/using.html#renewing-certificates
https://eff-certbot.readthedocs.io/en/stable/using.html#pre-and-post-validation-hooks
🥇 thanks!