IP certificate with Certbot & change package manager from APT to Snap

On an Ubuntu VPS I was looking into creating an SSL certificate for the server’s IP address. In an official blog post it is stated:
“If you want to try getting an IP address certificate using Certbot, install version 5.4 or higher”

certbot --version showed 2.9.0 so the version packaged with my Ubuntu and APT is much lower. Snap apparently has the latest version so this is the process I used to change it from APT to Snap and request a certificate.

Removing APT Certbot

We don’t want multiple Certbots installed at the same time, so first it must be removed from APT.

Determining the currently installed packagesBash
dpkg -l '*certbot*'

Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                      Version      Architecture Description
+++-=========================-============-============-=================================================
ii  certbot                   2.9.0-1      all          automatically configure HTTPS using Let's Encrypt
un  python-certbot-apache-doc <none>       <none>       (no description available)
un  python-certbot-doc        <none>       <none>       (no description available)
ii  python3-certbot           2.9.0-1      all          main library for certbot
un  python3-certbot-abi-2     <none>       <none>       (no description available)
ii  python3-certbot-apache    2.9.0-1      all          Apache plugin for Certbot
un  python3-certbot-nginx     <none>       <none>       (no description available)

snap --version
snap          2.76.3+ubuntu24.04
snapd         2.76.3+ubuntu24.04
series        16
ubuntu        24.04
kernel        6.8.0-139-generic
architecture  amd64

Based on the dpkg output, the command to remove Certbot packages would be:

Removing the current CertbotBash
apt remove certbot python3-certbot python3-certbot-apache

The existing renewal configurations under /etc/letsencrypt should remain.

Installing the Certbot snap

Installing Certbot via SnapBash
snap install --classic certbot

--classic grants the Snap broader access to the system. Certbot needs that access because it must be able to:

  • Read and write /etc/letsencrypt
  • Access Apache configuration and certificate files
  • Bind to or inspect ports used for ACME validation
  • Reload or reconfigure Apache
  • Read web-server files when performing validation

Snap should keep Certbot updated in the background automatically.

Installed Snap packages and update frequencyBash
snap list
Name     Version   Rev    Tracking       Publisher     Notes
certbot  5.8.0     5893   latest/stable  certbot-eff✓  classic
core24   20260410  1643   latest/stable  canonical✓    base
snapd    2.76.3    27738  latest/stable  canonical✓    snapd

which certbot # Reload your terminal if `certbot` is not in path yet
/snap/bin/certbot

certbot --version
certbot 5.8.0

snap refresh --time
timer: 00:00~24:00/4
last: today at 06:58 UTC
next: today at 12:05 UTC

Check that Certbot is still working:

Simulate renewalBash
certbot renew --dry-run

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for example.com and www.example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Creating a certificate for an IP

I’m creating a cert for the default Apache site:

/etc/apache2/sites-available/000-default.confBash
<VirtualHost *:80>
	...
	ServerName {YOUR_IP}
	...
</VirtualHost>

The ServerName should be the server’s IPv4 address.
I also had the default SSL config enabled (with self-signed Snakeoil certificates), it should be disabled for the time being:

Bash
a2dissite default-ssl.conf
systemctl reload apache2

Certbot does not yet support creating the SSL configuration file automatically so we’ll need to edit the default-ssl.conf manually later (your file name may differ, or may not exist at all).

Requesting staging certificate

The official instructions recommend running the command with the --staging flag first:

Bash
certbot certonly --staging \
  --preferred-profile shortlived \
  --webroot \
  --webroot-path <filesystem path to webserver root> \
  --ip-address <your ip address>

This will request a non-trusted certificate from the Let’s Encrypt staging server. Once you’ve got things working the way you want, run without the --staging flag to get a publicly trusted certificate.

The --webroot flag tells it to place the challenge response file to the webroot path where an already-running server can serve it. Alternatives are --manual (in which you place the file yourself) and --standalone in which Certbot runs its’ own webserver to serve the file.

Bash
certbot certonly --staging --preferred-profile shortlived --webroot --webroot-path /var/www/html --ip-address {YOUR_IP}

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for {YOUR_IP}

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/{YOUR_IP}/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/{YOUR_IP}/privkey.pem
This certificate expires on 2026-09-14.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Configuring Apache

Now the certificate files should be placed under /etc/letsencrypt/live/{YOUR_IP}, edit the apache configuration to use them:

/etc/apache2/sites-available/default-ssl.confBash
<VirtualHost *:443>
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html
	...

	# Remove
	SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
	SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
	SSLEngine on

	# Add
	Include /etc/letsencrypt/options-ssl-apache.conf
	SSLCertificateFile /etc/letsencrypt/live/{YOUR_IP}/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/{YOUR_IP}/privkey.pem

	...
</VirtualHost>

The options-ssl-apache.conf file (if you have it), contains the SSLEngine on as well as other related settings.

Reload you Apache configurations and visit your site via IP.

Bash
a2ensite default-ssl.conf
apache2ctl configtest
systemctl reload apache2

Given that we used --staging you should get a “Your connection is not private” NET::ERR_CERT_AUTHORITY_INVALID error, “Issuer: (STAGING) Baloney Bulgur YE2”:

Requesting production certificate

First, we’re going to disable the SSL site again, as it may cause the challenge to fail:

Bash
a2dissite default-ssl.conf
systemctl reload apache2

This time the same command, sans the --staging:

Bash
certbot certonly --preferred-profile shortlived --webroot --webroot-path /var/www/html --ip-address {YOUR_IP}

# Output

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2

If you get this error:

Renewing an existing certificate for {YOUR_IP}

Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
  Identifier: {YOUR_IP}
  Type:   unauthorized
  Detail: {YOUR_IP}: Invalid response from http://{YOUR_IP}/.well-known/acme-challenge/...: 404

Hint: The Certificate Authority failed to download the temporary challenge files created by Certbot. Ensure that the listed identifiers serve their content from the provided --webroot-path/-w and that files created there can be downloaded from the internet.

Some challenges have failed.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

Check the logs for what happened, re-run the command with -v (--verbose) for more info. In my case, I used the wrong webroot path which explains the 404.

To the HTTP configuration file you can add a redirect to HTTPS:

/etc/apache2/sites-available/000-default.confBash
<VirtualHost *:80>
	...
	RewriteEngine On
	RewriteRule ^ https://{YOUR_IP}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
Bash
a2ensite default-ssl.conf
systemctl reload apache2

The site should now redirect to HTTPS and have a valid certificate from LetsEncrypt to go with it.

Setting up automatic renewal

When requesting the cert, my output included “Certbot has set up a scheduled task to automatically renew this certificate in the background.” so the certificates themselves should automatically renew and you can use the following command to simulate the renewal process:

Bash
certbot renew --dry-run

In my case it successfully simulated the renewal of the short-lived IP certificate as well as the existing certificates for other domains that were set up using an older version of Certbot that was installed via apt.

The following command also checks that Certbot installed via Snap is properly working to automatically run renewals:

Bash
systemctl status snap.certbot.renew.timer
● snap.certbot.renew.timer - Timer renew for snap application certbot.renew
     Loaded: loaded (/etc/systemd/system/snap.certbot.renew.timer; enabled; preset: enabled)

How ever Apache will hold the certificates in memory and will not use the renewed cert unless the service is reloaded – for that reason you’ll need to set up a --deploy-hook to do that.

Since our original command didn’t contain --deploy-hook "systemctl reload apache2" we’ll have to reconfigure:

Bash
# Find out the cert names
certbot certificates

# Reconfigure
certbot reconfigure --cert-name {CERT_NAME/YOUR_IP} --deploy-hook "systemctl reload apache2"

# Output:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
You are attempting to set a --deploy-hook. Would you like Certbot to run deploy
hooks when it performs a dry run with the new settings? This will run all
relevant deploy hooks, including directory hooks, unless --no-directory-hooks is
set. This will use the current active certificate, and not the temporary test
certificate acquired during the dry run.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(R)un deploy hooks/(D)o not run deploy hooks: R

You can inspect the /etc/letsencrypt/renewal/{YOUR_IP}.conf file to verify that a renew_hook line was added.

Leave a Reply

Your email address will not be published. Required fields are marked *