Homelab Certs

homelabsslcertificatesmallstep

879 

2026-03-24 14:14 -0400


What Exactly is this all about

When interacting with the various pieces of my home network over the years I’ve frequently gotten irritated with certificate issues, mostly in the form of rejected connections and having to click through browser warnings. In the interests of saving myself a lot of annoying (and probably slightly dangerous) clicking, I decided to deploy TLS certs across my various devices. But I’m also very lazy and I didn’t want to have to deal with cert expirations or rolling internal certs on a regular basis. Ideally I would use something like Let’s Encrypt, but for the automated challenges to work I would have to expose parts of my network to the internet that I’d really rather not. So I decided to run my own CA and then automate the renewal process inside of my network.

Setup CA Server

Pick an ednpoint that will act as certificate authority. In my case I have a machine that acts as a central point for a variety of network functions and so it makes sense to use it as a CA as well. We’ll use smallstep to configure it to act as a CA.

Install the smallstep tool

Follow the [installation instructions]. In my case I am using a NUC running Ubuntu so the commands look like:

sudo curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/trusted.gpg.d/smallstep.asc && \
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/smallstep.asc] https://packages.smallstep.com/stable/debian debs main' \
    | sudo tee /etc/apt/sources.list.d/smallstep.list
sudo apt update && sudo apt install -y step-cli

Intitialize the CA

Getting your own CA started is realtively straightforward. The first command will be:

step ca init

This will alunch an interactive process that will create a few important files and give you some important data that will be needed later. It will create 2 pairs of certificate and key files. The root cert/key pair forms the base layer of cryptographic trust for the chain. You want to back these up somewhere and keep them safe. The intermediate cert/key pair will be used to actually sign certs. In order to create trust across the network this intermediate cert will get installed in a variety of places, which is why it is deliberately offset from the root cert. For more info about this checkout this guide from Digicert

Client Setup

Now to configure the client devices to use the CA and setup automatic renewal. If you wanted you could use CertBot to do this, though it can be a bit finnicky if you aren’t using a valid TLD. For simplicity and consistency I continued to use step-cli.

Common

The following steps apply to all linux based client devices: Install step cli on client devices

sudo curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/trusted.gpg.d/smallstep.asc && \
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/smallstep.asc] https://packages.smallstep.com/stable/debian debs main' \
    | sudo tee /etc/apt/sources.list.d/smallstep.list
sudo apt update && sudo apt install -y step-cli

Bootstrap CA and install in trust store:

sudo step ca bootstrap --ca-url https://ca.<domain>.home:8443 --fingerprint <fingerprint> --install

allow step to bind to 80 for ACME:

sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/step-cli

This last step is important as the step executable will need to bind to port 80 (which is a privileged port) and you don’t want your renewals to be running as root for security reasons.

Service Specific

Now to configure a few services that I care about to use certs off of the CA and renew them.

Pihole

First create an appropriate certificate for the pihole. You want to ensure that the SANs match the IP addresses and DNS names associated to each service.

Create Cert

step ca certificate pihole.<domain>.home pihole.crt pihole.key --san <IP> --san pihole.<domain>.home --ca-url 'https://ca.<domain>.home:8443'

Renewal Service

[Unit]
Description=Pihole Dashboard cert renewal

[Service]
Restart=on-failure
RestartSec=1
User=pihole
ExecStart=/bin/bash -c "/opt/pihole-cert-scripts/renew-cert.sh"
WorkingDirectory=/opt/pihole-cert-scripts
StandardOutput=append:/var/log/pihole-dashboard-renew.log
StandardError=append:/var/log/pihole-dashboard-renew.log

[Install]
WantedBy=multi-user.target

It depends on two smaller script files. renew-cert.sh, as its name implies, simply renews the certificate. It looks like this:

#!/bin/sh
/usr/bin/step ca renew --daemon --force \
--exec "/opt/pihole-cert-scripts/concatenate-restart.sh" \
--ca-url https://ca.<domain>.home:8443 \
/opt/pihole-cert-scripts/pihole.crt /opt/pihole-cert-scripts/pihole.key;

However, this script by itself is not sufficient because the pihole expects the certificate to be in a single PEM formatted file rather than a cert/key pair. To accomplish this the renewal is called with the --exec flag to execute a script that concatenates the two files into a single PEM and then restarts the service. That script looks like this:

#!/bin/sh
/usr/bin/cat pihole.key pihole.crt > ./pihole.pem;
/usr/bin/systemctl daemon-reload;
/usr/bin/systemctl restart pihole-FTL

Proxmox

Proxmox is nice because it has native acme support built in and it will set all of the vms that it creates to automatically trust your CA as well. Configure ACME certs on proxmox:

pvenode acme account register <domain>-ca root@<domain>.home --directory https://ca.<domain>.home:8443/acme/acme/directory

Wazuh Dashboard

Wazuh is also fairly straightforward.

step ca certificate wazuh.<domain>.home wazuh.pem wazuh.key --san <IP> --ca-url 'https://ca.<domain>.home:8443' --provisioner acme
sudo cp wazuh.pem /etc/wazuh-dashboard/certs/
sudo cp wazuh.key /etc/wazuh-dashboard/certs/
sudo chown wazuh-dashboard:wazuh-dashboard /etc/wazuh-dashboard/certs/wazuh.pem
sudo chown wazuh-dashboard:wazuh-dashboard /etc/wazuh-dashboard/certs/wazuh.key
sudo chmod 440 /etc/wazuh-dashboard/certs/wazuh.key
sudo chmod 444 /etc/wazuh-dashboard/certs/wazuh.pem

Automate renewal with daemon mode:

sudo step ca renew --daemon --ca-url https://ca.<domain>.home:8443 /etc/wazuh-dashboard/certs/wazuh.pem /etc/wazuh-dashboard/certs/wazuh.key &

This will actually die on logout so I need to create service. It is very similar to the service used for the pihole so I won’t repost the code here. The main thing is that you have to repoint the config in /etc/wazuh-dashboard/opensearch_dashboards.yml and afterwards remember to restart the dashboard service.

sudo systemctl daemon-reload
sudo systemctl restart wazuh-dashboard