{"schemaVersion":"1.0","type":"Article","types":["Article"],"slug":"i-built-certvault-to-stop-managing-certificates-on-every-homelab-host-5hvsp","url":"https://zyvop.com/i-built-certvault-to-stop-managing-certificates-on-every-homelab-host-5hvsp","title":"I Built CertVault to Stop Managing Certificates on Every Homelab Host","subtitle":null,"tldr":"I have several machines in my homelab that need TLS certificates. For a while, each machine handled this on its own. Every host had its own ACME setup, DNS prov...","keywords":[],"entities":["Douglas Maitelli","Senior Software Engineer","ZyVOP"],"keyTakeaways":["I have several machines in my homelab that need TLS certificates.","For a while, each machine handled this on its own.","Every host had its own ACME setup, DNS provider credentials, renewal schedule, and deployment script."],"headings":["One place for ACME and DNS credentials","Centralized renewal and distribution","Giving each client only what it needs","Keeping certificates updated on other machines","Protecting the sensitive parts","CertVault and DockDash","Why I built another certificate tool"],"outboundLinks":["https://github.com/dougmaitelli/CertVault","https://github.com/dougmaitelli/DockDash","https://dougmaitelli.github.io/CertVault/"],"contentText":"I have several machines in my homelab that need TLS certificates. For a while, each machine handled this on its own. Every host had its own ACME setup, DNS provider credentials, renewal schedule, and deployment script. In some cases, several machines requested separate certificates for the same domain. It worked, until it did not. That setup meant copying sensitive DNS credentials to several places and keeping track of multiple certificates with different fingerprints for the same domain. I wanted one service to obtain and renew certificates, then let each machine download only the certificate it was allowed to use. That is why I built CertVault. One inventory for certificates used across the homelab. One place for ACME and DNS credentials CertVault is a self-hosted ACME certificate controller designed for homelabs. It obtains certificates through the DNS-01 challenge, renews them automatically, and provides controlled download access to other machines on the network. DNS-01 is important for my setup because it works with wildcard certificates and does not require every service to be directly reachable from the internet. CertVault supports the DNS providers available through go-acme/lego, so it is not tied to Cloudflare or any other single provider. Instead of configuring Let's Encrypt and storing DNS credentials on every server, I configure them once in CertVault. The other machines only need a CertVault API key with access to the specific certificates they use. This reduces the number of places where powerful DNS credentials exist. It also gives me one place to see which certificates I have, when they expire, when they were renewed, and which clients downloaded them. Centralized renewal and distribution CertVault can manage multiple DNS zones, credentials, domains, and certificates. Each certificate can contain one domain, several domains, or a wildcard such as: certificates: - name: homelab-wildcard domains: - example.com - \"*.example.com\" renew_before: 720h It periodically checks whether certificates need renewal. Certificate operations use per-certificate locking, and new versions are written atomically. If a renewal fails, the previous certificate version remains untouched. Every issued version is kept in an immutable history. This gives me a clear record of what changed and makes it possible to inspect older versions without treating the current certificate files as the only source of truth. The web console shows the current certificate inventory, validity, covered domains, key types, issuance history, downloads, and manual renewal controls. Every certificate version and issuance event can be inspected from the web console. CertVault can also send Apprise notifications when a certificate is first issued, renewed, or cannot be issued. I can route those alerts to Slack, Discord, Telegram, email, or any of the other services supported by Apprise. Giving each client only what it needs Centralizing private keys is useful only if access to them is carefully controlled. CertVault uses scoped API keys. A key can be restricted by operation and by certificate, so a machine does not automatically get access to everything in the vault. Public certificate downloads require the certificates:read scope. Private keys require the separate private_keys:read scope. A key can also be limited to one named certificate. For example, a reverse proxy can receive a key that allows it to download one wildcard certificate and its private key, while another service can have read access to a different certificate. The raw API key is shown only once, stored as a hash, and can be revoked at any time. CertVault records API key usage and certificate downloads in its audit history. This makes it easier to answer basic questions such as which client fetched a certificate and when it happened. Each client receives only the certificate access it needs. Keeping certificates updated on other machines Clients can download certificate artifacts directly from the API, but CertVault can also generate an installation command for an automatic download job. The installed job periodically checks for changes and keeps the certificate files on that machine updated. It uses ETag and If-None-Match, so unchanged files return 304 Not Modified and are not rewritten. When a new certificate is available, the client downloads it into a temporary directory and installs the files atomically. An optional reload command can restart or reload the service that uses the certificate. Running the generated installer again replaces the existing job for that certificate instead of creating duplicates. This makes it easier to change the API token, schedule, destination, filenames, or reload command later. CertVault can generate a scheduled client job to keep certificate files updated. Protecting the sensitive parts A certificate manager handles private keys, so I did not want security to be an afterthought. CertVault encrypts certificate private keys and ACME account keys with AES-256-GCM. The encryption key is supplied separately and is not stored in the SQLite database. DNS credentials are also not persisted in SQLite. API keys are hashed, revocable, and scoped. Browser access can use OIDC with Authorization Code and PKCE, including an optional group allowlist. A separate bootstrap token can be kept as break-glass access or disabled completely. Hooks are restricted as well. Webhooks can be signed with HMAC-SHA256. Executable hooks must be explicitly configured, run without a shell, receive a minimal environment, and are stopped after their configured timeout. Apprise endpoints can contain credentials, so they need the same care as the other deployment secrets. CertVault reads them from configuration and does not store them in SQLite. The container runs as a non-root user with no Linux capabilities. Of course, the API can return private keys, so CertVault still needs to sit behind HTTPS and should never be exposed over plaintext HTTP across the network. The data volume and encryption master key also need to be backed up together. The encrypted private material cannot be recovered if the master key is lost. CertVault and DockDash CertVault automates certificate issuance, renewal, and distribution. My other project, DockDash, checks what each live service is actually presenting. I wanted both because successful renewal does not guarantee successful deployment. CertVault may have a new certificate while a server is still presenting the old one because its download job, file copy, or reload command failed. DockDash can compare the fingerprint of the live certificate with the fingerprint stored in CertVault. This verifies the exact certificate, not just whether the certificate is trusted and has not expired. A fingerprint mismatch may be a simple deployment mistake, but it can also reveal an unexpected certificate replacement. A different certificate could still be technically valid, so checking only the expiration date and trust chain would miss it. CertVault manages the expected certificate. DockDash checks the certificate that users actually receive. Why I built another certificate tool There are already many good ACME clients and certificate automation tools. CertVault is not an attempt to replace all of them. I built it because I did not want separate ACME accounts, DNS credentials, scripts, and certificates spread across every machine in my homelab. I wanted a small self-hosted controller with a web interface, an API, scoped client access, encrypted private material, and a history I could inspect when something went wrong. It is open source under the AGPL-3.0 license. Feedback is welcome, especially from people managing certificates across several homelab hosts. You can find the project here: CertVault on GitHub Documentation Thanks for reading ;)","contentHash":"sha256:abe2335b56d9801264ef7eab27cfec126f11fa075a0ed34887d0a7f31af067df","authorName":"Douglas Maitelli","authorUrl":"https://zyvop.com/author/doug","authorSameAs":["https://github.com/dougmaitelli/","https://www.linkedin.com/in/dougmaitelli/"],"category":null,"tags":[],"audience":"Software engineers and developers building applications with software development","tone":"Professional, senior software engineer perspective","readingTimeMinutes":5,"wordCount":1204,"faqs":null,"primaryTopic":null,"publishedAt":"2026-09-01T07:24:45.914Z","updatedAt":"2026-09-01T18:55:00.075Z","canonicalUrl":"https://zyvop.com/i-built-certvault-to-stop-managing-certificates-on-every-homelab-host-5hvsp"}