Using HTTPS in a homelab requires the deployment of a Public Key Infrastructure. A PKI is the set of assets needed to manage a chain of certificates with a Certificate Authority at the top and hopefully short-lived certificates at the leaf nodes. This page describes how certificates are handled in the rachelski.internal homelab.
I wanted a simple web site that I could use to manage the highest levels of Certificates: creation of a root CA and creation/signing of Intermediates. Ideally, the root CA should have its keys offline and away from any everyday issuance infrastructure. For this purpose, I identified a small Django app called BounCA and this was deployed as a docker container on the Diskstation NAS.
This system was then used to create the root CA with common name: rachelski.internal Root CA series 2025 A. In addition, this system also contains an intermediate certificate named: Rachelski Internal Intermediate - Manual Signing 2025 Series A which, as the name suggests, would be used to manually issue certificates from BounCA. Lastly, another intermediate named rachelski.internal Certificate Issuing Authority was issued and configured into the Hashicorp Vault instance at the backend named pki-ranch. The root CA and passphrase are currently saved in BitWarden under the record named: Rachelski Internal Root CA key passphrase.
Unfortunately, over time, I have discovered why this system is not very popular. The docker instance crashes frequently. And the user interface is quite unreliable. It looks like a simple, and nice application. But day-to-day operational use shows why it probably won't work long-term. It lasted quite a while, well over a year, because I really only needed it to bootstrap the PKI and very occasionally issue manual certificates. But I will need to replace it at some point before I lock myself out of my PKI. The underlying data issued so far is in the backing PostgreSQL database, so I am not terribly worried about getting this migrated to a different system. I just need to plan out how this is done.
Hashicorp Vault is my primary online certificate issuer (in addition to being my secrets store). It is a fantastic piece of software that just works reliably. The primary methods for installing and managing it are in the Gitea project named hcl-vault. The deployment system is pretty well documented in that project.
This Vault instance is running on the Diskstation NAS as it is pretty foundational for operating my Kubernetes cluster. It is the backend to my cert-manager operator.
In a circular dependency issue that may come back to bite me, the Vault instance is now being used to issue certificates that are then loaded into the NAS for serving sites under the *.rachelski.internal hostnames.
Note:
The need for this section has been removed by having the NAS running an instance of acme.sh to renew my wildcard certificates. I am keeping this because it is an interesting technique to recover from certificate failures
In struggling with BounCA as mentioned above, I found that in a pinch, I can use Vault to manually issue certificates using the same backend that I use for supporting the Kubernetes cluster. The command to do this will look something like this:
ssh -L 8200:127.0.0.1:8200 admin@192.168.200.155
# in another terminal
VAULT_ADDR=http://127.0.0.1:8200 vault write pki-ranch/issue/ranch-cert-issuer common_name="*.rachelski.internal" alt_names="*.rachelski.internal" ttl="365d"
Note that even though we are asking for a 1-year certificate, this vault issuer will only issue certificates for a maximum of 30 days. So, this technique is really only used to get myself out of short-term trouble and I should eliminate all manually issued certificates. Vault's port 8200 only listens on the NAS's own loopback interface, so the command goes through an SSH tunnel to the NAS by IP address. Talking to Vault over plain HTTP inside that tunnel means the command still works even if the NAS is serving an expired certificate.
While I am doing manual issuance, my workflow is:
pki-systemmanual-certs directory using the serial number found at the bottom of the vault command outputOnce I have the 3 files saved to the filesystem, I go to the NAS UI and update the certificate (Control Panel -> Security -> Certificates):
Apps on the ranch cluster get their certificates automatically from cert-manager, through the ranch-cert-issuer ClusterIssuer. It uses the Vault PKI mount (pki-ranch). Certificates last at most 30 days (cert-manager renews them), and the issuer only issues names under rachelski.internal. Every Ingress must set the cert-manager.io/common-name annotation, because Vault needs an explicit common name. See Deploying Apps on the Ranch Cluster.
The issuer also produces the cluster's Traefik default certificate, a wildcard (*.rachelski.internal, Secret traefik-default-tls in traefik-system). Traefik serves it only for hostnames that no Ingress claims, so that it doesn't reveal itself with its own self-signed certificate. Apps must not reuse it. See Requests for unknown hostnames.
Trust is handled in two separate places:
k3s repo's node setup scripts install it (scripts/k3s-setup-initial-controller.sh, scripts/k3s-setup-worker.sh), and scripts/k3s-retrofit-ca-trust.sh adds it to existing nodes.Automatically rotating certificates on a Synology NAS issued from HashiCorp Vault is best achieved by combining Vault's PKI secrets engine with an ACME client (like acme.sh) running via Task Scheduler or Docker, or by using HashiCorp Vault Agent to manage the certificate lifecycle.
Here are the primary methods to automate this process:
This method uses the acme.sh tool to interact with HashiCorp Vault (acting as an ACME server) to generate certificates, and then uses a Synology-specific hook to upload and apply them.
./acme.sh --server https://vault.example.com:8200/v1/pki/acme/directory \
--issue -d "synology.example.com" \
--dns dns_hook_name
./acme.sh -d "synology.example.com" --deploy --deploy-hook synology_dsm
Note: By default, acme.sh renews a certificate 60 days after it was issued. Our Vault issuer caps certificates at 30 days, so with the default settings they would expire long before renewal. Pass something like
--days 20when issuing so acme.sh renews in time.
Source: Synology DSM 7 with Let's Encrypt and DNS Challenge
Vault Agent can be run in a Docker container on the Synology NAS to fetch, manage, and renew certificates, acting as a lightweight client.
Source: Consul-Template to automate certificate management for HashiCorp Vault PKI
For a simpler approach without acme.sh, you can use a custom script in Synology Task Scheduler.
Source: Synology: how to schedule Let's Encrypt certificate auto-renew