This project provides a robust and secure system for centralized management of Certbot certificates, built in Golang and protected exclusively by mTLS. It consists of two main components:
- Server (Distribution Center): Hosted on the Certbot server that generates and renews certificates, exposes a secure API for certificate distribution and verification.
- Client (Update Agent): Runs on remote servers via cron or on demand, checks the status of local certificates and updates them if necessary.
- API
/api/check: Compares the SHA256 hashes of certificates sent by the client with those on the server. If a difference is detected, the server instructs the client to proceed with the update. - Endpoint
/download/<domain>/<filename>: Allows direct download of certificate files (fullchain.pem,privkey.pem,chain.pem) for a given domain, protected by mTLS. - Security: All communications are protected by mTLS. No web interface listing domains is exposed.
- Logging: All errors and events are logged to the local syslog with the
daemonfacility andinfopriority.
- Certificate verification: Calculates SHA256 hashes of local certificates and sends them to the server for verification.
- Conditional update: If the server indicates that certificates have changed, the client downloads and replaces the local files.
- Execution via cron: Designed to be run regularly (e.g., weekly) via a cron job, coupled with Make for service restarts.
- Logging: All errors and events are logged to the local syslog with the
daemonfacility andinfopriority.
- Go 1.18+
- Generated mTLS certificates (CA, client, server)
- Certbot installed on the central server
- Private PKI [docs/PKI.md](Check docs/PKI.md)
-
Create and Install the mTLS certificates in the
tls/folder:server.crt,server.key,ca.crtREAD docs/PKI for example
-
Build the server:
cd server go build -o acme_dl_server main.go -
Configure the systemd service with server/acme_dl_server.service.
-
Check that the server is running:
# ps -auxww | grep acme_dl_serverThe server listens on port
8443( set static in main.go server code).
-
Build the client:
cd client go build -o acme_dl_client client.go -
Place the mTLS certificates in the
tls/folder:client.crt,client.key,ca.crt
You can read docs/PKI.md for how you can create certificates for mTLS
<client>:/local/acme_dl# tree -p
[drwxr-xr-x] .
├── [-rwxr-x---] acme_dl_client
├── [-rw-r--r--] Makefile
└── [drwxr-xr-x] tls
├── [-rw-r-----] ca.crt
├── [-rw-------] client.crt
└── [-rw-------] client.key- copy Makefile from dist/Makefile and configure for your needs
Edit CERTS if you want a list, COMMANDS for restarting services
# Liste des certificats
CERTS := $(shell hostname -f)
# Chemins
CLIENT_PATH := ./acme_dl_client
LIVE_PATH := /etc/letsencrypt/live
COMMANDS := systemctl restart httpd
# COMMANDS := echo "Restart ssl service"
.PHONY: all
all: $(foreach cert,$(CERTS),update-$(cert))
# La règle utilise le timestamp de fullchain.pem pour détecter le changement
update-%:
@CERT_FILE=$(LIVE_PATH)/$*/fullchain.pem; \
BEFORE=$$(stat -c %Y $$CERT_FILE 2>/dev/null || echo 0); \
$(CLIENT_PATH) $*; \
AFTER=$$(stat -c %Y $$CERT_FILE 2>/dev/null || echo 0); \
if [ $$AFTER -gt $$BEFORE ]; then \
echo "Changement détecté pour $* (nouveau certificat)."; \
$(COMMANDS); \
fi-
Set up a weekly cron job:
0 3 * * 0 make -f ..../Makefile
./acme_dl_client <example.com>- Certificates
<domain>: lives in the folder in/etc/letsencrypt/live/<domain>(e.g.,example.com).
The server starts and exposes the following endpoints:
POST /api/check: Certificate verificationGET /download/<domain>/<filename>: Direct file download
- Authentication: mTLS is required for all endpoints.
- No web interface listing domains. You can filter hosts accessing your certs
- Certificate renewal: Managed by Certbot via cron or external script, not included in the Golang server.
- No needs for Certbot on each server and CLI secret dissemination
- central storing of certificats ( useful for batch renewal )
- Automating transfer and service restarts
- client restrictions on server ( self(default), list, any )
All errors and events are sent to the local syslog (daemon.info) using the standard log/syslog library.
.
├── client/
│ └── client.go
├── server/
│ ├── main.go
│ └── acme_dl_server.service
├── tls/
│ ├── ca.crt
│ ├── client.crt
│ ├── client.key
│ ├── server.crt
│ └── server.key
On Certbot and other servers:
└── /etc/letsencrypt/live/<domain>/
├── fullchain.pem
├── privkey.pem
└── chain.pemFor any questions or improvements, contact the DevOps team.
