Automated Certificate Lifecycle Manager sidecar. Auto-renews x509 certs without ACME challenges.
276
A lightweight, fully automated Certificate Lifecycle Manager designed to run as a Docker Sidecar alongside your applications. Built on Alpine Linux, this image interacts with the TWIT PKI Manager to seamlessly bootstrap and auto-renew internal x.509 certificates without requiring inbound ACME HTTP challenges.
Instead of complex ACME port forwarding, this client uses an "Inside-Out" Bootstrapping model:
PKI_TOKEN (JWK) to authenticate against the PKI Manager to obtain the first certificate.POST_RENEW_HOOK (like restarting a Docker container or sending a SIGHUP) to ensure the target application loads the new certificate.| Variable | Required | Default | Description |
|---|---|---|---|
PKI_URL | Yes | The full URL to the /1.0/sign endpoint of your PKI Manager Project (e.g. https://pki.corp.local/api/root/1.0/sign) | |
PKI_DOMAIN | Yes | The exact Common Name (CN) / Domain for the certificate | |
PKI_TOKEN | No* | A JWK One-Time Token (Only required for the very first initialization) | |
CERT_DIR | No | /certs | Path inside the container where the files (app.crt, app.key) are generated |
RENEW_DAYS | No | 30 | Request renewal when the certificate expires in less than X days |
POST_RENEW_HOOK | No | A system shell command executed only after a successful renewal. See Architecture Patterns below. | |
CHECK_INTERVAL | No | 86400 | Sleep interval in seconds between certificate checks (Default: 24h) |
Depending on your target application (the webserver that actually needs the certificate), you should choose one of three strategies for your docker-compose.yml.
The most elegant way for classic webservers. The Sidecar shares the PID namespace with Nginx and sends a soft-reload signal, preventing any traffic drops. No Docker-Socket required.
services:
nginx_server:
image: nginx:alpine
volumes:
- shared-certs:/etc/nginx/certs:ro
pki_sidecar:
image: toutzn/twit-pki-client:latest
pid: "service:nginx_server" # 👈 IMPORTANT: Share PID namespace
environment:
- PKI_URL=https://pki.corp.../1.0/sign
- PKI_DOMAIN=web.pki.test
- PKI_TOKEN=eyJhb...
- POST_RENEW_HOOK=kill -s SIGHUP 1 # 💥 HOOK: Soft reload Nginx
volumes:
- shared-certs:/certs:rw
volumes:
shared-certs:
Traefik's Dynamic Configuration Provider automatically watches its mounted certificate directories via Inotify. As soon as the PKI Sidecar updates the .crt file, Traefik hot-reloads it in milliseconds.
services:
pki_sidecar:
image: toutzn/twit-pki-client:latest
environment:
- PKI_URL=https://pki.corp.../1.0/sign
- PKI_DOMAIN=gateway.pki.test
- PKI_TOKEN=eyJhb...
- POST_RENEW_HOOK="" # 💥 HOOK: Blank, Traefik natively watches files!
volumes:
- shared-certs:/certs:rw
# The Traefik container simply mounts "shared-certs:/certs:ro"
For apps that cannot reload certificates on the fly (e.g. Node.js apps, Watchtower/WUD). The Sidecar controls the host Docker Daemon via a socket mount and issues a direct Docker restart command to the target container.
services:
pki_sidecar:
image: toutzn/twit-pki-client:latest
environment:
- PKI_URL=https://pki.corp.../1.0/sign
- PKI_DOMAIN=app.pki.test
- PKI_TOKEN=eyJhb...
- POST_RENEW_HOOK=docker restart my_target_app_1 # 💥 HOOK: Hard restart
volumes:
- shared-certs:/certs:rw
- /var/run/docker.sock:/var/run/docker.sock # 👈 IMPORTANT: Host socket mount!
The twit-pki-client creates cryptographic keys with secure 0600 permissions. If your target container runs as a strict non-root user (e.g., uid 1000), you may need to adjust the permissions so the target app can read app.crt and app.key. You can easily accomplish this by adding a chown chain directly into the POST_RENEW_HOOK:
POST_RENEW_HOOK=chown 1000:1000 /certs/app.* && docker restart my_app_1
Maintained by Toutzn - Built for the TWIT PKI Ecosystem.
Content type
Image
Digest
sha256:c85e8e33c…
Size
21.2 MB
Last updated
6 months ago
docker pull toutzn/twit-pki-client