Automated SSL Certificate Distribution Service
Securely distribute Let's Encrypt certificates to multiple servers with zero manual intervention.
CertDeliver automates the distribution of SSL certificates from a central server to multiple client machines. When certbot renews your certificates, CertDeliver packages them and makes them available for clients to download automatically.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Certbot │────▶│ CertDeliver │────▶│ Client 1 │
│ (renewal) │ │ Server │ │ (nginx/xray) │
└─────────────────┘ └─────────────────┘ ├─────────────────┤
│ Client 2 │
│ (nginx/xray) │
└─────────────────┘
| Feature | Description |
|---|---|
| 🔐 Secure Auth | Constant-time token comparison prevents timing attacks |
| 🌐 IP Whitelist | DNS-based client verification |
| 📦 Auto Package | Certbot hook bundles certs automatically |
| 🔄 Auto Sync | Clients poll and update certs automatically |
| 🐳 Docker Ready | One-command deployment with Docker Compose |
| ⚡ Modern Stack | Python 3.10+, FastAPI, Pydantic, Type Hints |
- Python 3.10 or higher
- Certbot (for certificate generation)
- Linux server (Debian/Ubuntu or RHEL/CentOS)
# Clone the repository
git clone https://github.com/yuanweize/CertDeliver.git
cd CertDeliver
# Install with pip
pip install .
# Or run installer script
sudo bash scripts/install.shcd docker
cp ../.env.example .env
# Edit .env with your settings
docker compose up -dCertDeliver uses environment variables for configuration. Create a .env file:
# Server Configuration
CERTDELIVER_TOKEN=your-secure-random-token
CERTDELIVER_DOMAIN_LIST=client1.example.com,client2.example.com
CERTDELIVER_PORT=8000
CERTDELIVER_TARGETS_DIR=/opt/CertDeliver/targets
# Client Configuration
CERTDELIVER_CLIENT_SERVER_URL=https://cert.example.com/api/v1/
CERTDELIVER_CLIENT_TOKEN=your-secure-random-token
CERTDELIVER_CLIENT_CERT_NAME=cert
CERTDELIVER_CLIENT_CERT_DEST_PATH=/etc/ssl/certs
CERTDELIVER_CLIENT_POST_UPDATE_COMMAND=systemctl reload nginx📄 See config/.env.example for all available options.
# Example with Aliyun DNS plugin
certbot certonly \
-a dns-aliyun \
--certbot-dns-aliyun:dns-aliyun-credentials /etc/letsencrypt/dns-key \
-d "*.example.com" \
--cert-name cert# Add to crontab
crontab -e
# Add this line:
0 0,12 * * * certbot renew -q --post-hook "certdeliver-hook"# Option 1: Direct run
certdeliver-server
# Option 2: Systemd service
sudo cp CertDeliver.service /etc/systemd/system/
sudo systemctl enable --now certdeliver
# Option 3: Docker
cd docker && docker compose up -dserver {
listen 443 ssl http2;
server_name cert.example.com;
ssl_certificate /etc/letsencrypt/live/cert/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cert/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}pip install git+https://github.com/yuanweize/CertDeliver.gitexport CERTDELIVER_CLIENT_SERVER_URL="https://cert.example.com/api/v1/"
export CERTDELIVER_CLIENT_TOKEN="your-token"
export CERTDELIVER_CLIENT_CERT_NAME="cert"
export CERTDELIVER_CLIENT_CERT_DEST_PATH="/etc/nginx/ssl"
export CERTDELIVER_CLIENT_POST_UPDATE_COMMAND="systemctl reload nginx"# Check for updates twice daily
crontab -e
# Add:
30 6,18 * * * certdeliver-client >> /var/log/certdeliver.log 2>&1CertDeliver/
├── src/certdeliver/ # Source code
│ ├── config.py # Configuration (Pydantic)
│ ├── server/ # FastAPI server
│ │ ├── app.py # Application entry
│ │ ├── routes.py # API endpoints
│ │ ├── auth.py # Authentication
│ │ └── whitelist.py # IP whitelist
│ ├── client/ # Certificate downloader
│ │ └── downloader.py
│ └── hooks/ # Certbot hooks
│ └── certbot_hook.py
├── tests/ # Unit tests
├── docker/ # Docker deployment
├── config/ # Configuration examples
├── scripts/ # Installation scripts
├── pyproject.toml # Package configuration
└── README.md
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Service info and client IP |
/health |
GET | Health check for monitoring |
/api/v1/{file} |
GET | Download/check certificate |
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string | ✅ | Authentication token |
download |
bool | ❌ | Force download mode |
- No Shell Injection: Uses Python's native
shutil,zipfile,subprocess - Timing-Safe Auth: Uses
secrets.compare_digest()for token comparison - IP Whitelist: DNS-based client verification with caching
- Minimal Privileges: Systemd service with security hardening
- No Root in Docker: Container runs as non-root user
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Type checking
mypy src/certdeliver
# Linting
ruff check src/This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request