A Python tool for requesting and renewing SSL/TLS certificates using Cloudflare DNS API with Let's Encrypt. Built with modern Python tooling using uv for fast dependency management.
Disclaimer: This project is not affiliated with, endorsed by, or supported by Cloudflare.
- 🔒 Automated SSL/TLS certificate requests using DNS-01 challenge
- ☁️ Cloudflare DNS API integration
- ⚡ Fast dependency management with uv
- 🛠️ Simple Makefile interface
- 🔄 Support for certificate renewal
- 🧪 Staging environment support for testing
- 📝 Configuration via .env file or command-line arguments
- 🔧 Flexible: use .env, CLI args, or both
- Python 3.10 or higher
- A Cloudflare account with API token
- Domain managed by Cloudflare DNS
# Install dependencies (will install uv if not present)
make installIf you prefer to install uv manually:
curl -LsSf https://astral.sh/uv/install.sh | sh- Log in to your Cloudflare dashboard
- Go to My Profile → API Tokens
- Create a token with these permissions:
- Zone:DNS:Edit for the zones you want to manage
- Zone:Zone:Read for all zones
Create a .env file in the project root:
# Copy the example file
cp .env.example .env
# Edit with your credentials
nano .envYour .env file can contain:
# Required
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token_here
# Optional (can also be passed as CLI arguments)
DOMAIN=example.com
EMAIL=admin@example.com
# Optional settings
STAGING=0 # Set to 1 for staging/test certificates
PROPAGATION_SECONDS=10 # DNS propagation wait timeSecurity Note: The .env file is already in .gitignore. Never commit API tokens to version control.
Set everything in .env and run without arguments:
# .env file contains: CLOUDFLARE_API_TOKEN, DOMAIN, EMAIL
cloudflare-request-cert# Provide all parameters via CLI (API token still from .env or environment)
cloudflare-request-cert -d example.com -e admin@example.com# Store sensitive data in .env, pass domain/email via CLI
# This is useful when managing multiple domains
cloudflare-request-cert -d example.com -e admin@example.comRequest a certificate with Make:
# Basic usage
make run DOMAIN=example.com EMAIL=admin@example.com
# Test with staging first (recommended)
make run DOMAIN=example.com EMAIL=admin@example.com STAGING=1# Custom DNS propagation time
cloudflare-request-cert \
-d example.com \
-e admin@example.com \
--propagation-seconds 30
# Use staging environment for testing
cloudflare-request-cert \
-d example.com \
-e admin@example.com \
--staging
# Use custom .env file
cloudflare-request-cert \
-d example.com \
-e admin@example.com \
--env-file /path/to/custom.envWhen the same setting is provided in multiple places, this is the priority order (highest to lowest):
- Command-line arguments (highest priority)
- .env file
- Environment variables (lowest priority)
Example:
# .env has DOMAIN=old.com
# This will use new.com (CLI argument takes precedence)
cloudflare-request-cert -d new.com -e admin@example.com| Command | Description |
|---|---|
make help |
Show all available commands |
make venv |
Create virtual environment |
make install |
Install uv and sync dependencies (alias for venv) |
make sync |
Sync dependencies with uv |
make dev |
Install development dependencies |
make run |
Run the certificate request tool |
make lint |
Lint code with ruff |
make format |
Format code with ruff |
make check |
Run all checks (lint + format) |
make test |
Run tests |
make sbom |
Generate SBOM (Software Bill of Materials) |
make clean |
Remove virtual environment and cache |
After successful certificate generation, your certificates will be stored at:
/etc/letsencrypt/live/your-domain.com/
├── cert.pem # Your certificate
├── chain.pem # The certificate chain
├── fullchain.pem # cert.pem + chain.pem
└── privkey.pem # Your private key
The tool waits for DNS changes to propagate before Let's Encrypt validates your domain. Default is 10 seconds, but you can adjust this:
# Via CLI
cloudflare-request-cert -d example.com -e admin@example.com --propagation-seconds 30
# Via .env
PROPAGATION_SECONDS=30Certbot automatically handles renewal. Set up a cron job or systemd timer:
# Cron example (runs daily at 2 AM)
0 2 * * * certbot renew --quiet
# Or use systemd timer (recommended)
sudo systemctl enable --now certbot-renew.timermake devmake testmake lintmake formatmake checkGenerate a Software Bill of Materials (SBOM) in CycloneDX JSON format:
make sbomThe SBOM will be saved to bom.json.
# 1. Install dependencies
make install
# 2. Set up configuration
cp .env.example .env
nano .env # Add your Cloudflare API token
# 3. Test with staging (won't affect rate limits)
cloudflare-request-cert -d example.com -e admin@example.com --staging
# 4. Get production certificate
cloudflare-request-cert -d example.com -e admin@example.com# Store API token in .env
echo "CLOUDFLARE_API_TOKEN=your_token" > .env
# Request certificates for different domains
cloudflare-request-cert -d site1.com -e admin@site1.com
cloudflare-request-cert -d site2.com -e admin@site2.com
cloudflare-request-cert -d site3.com -e admin@site3.com#!/bin/bash
# renew-certs.sh
DOMAINS=("site1.com" "site2.com" "site3.com")
EMAIL="admin@example.com"
for domain in "${DOMAINS[@]}"; do
echo "Requesting certificate for $domain..."
cloudflare-request-cert -d "$domain" -e "$EMAIL"
doneInstall certbot and the Cloudflare plugin:
make install
# or
uv syncMake sure your .env file exists and contains:
CLOUDFLARE_API_TOKEN=your_actual_token_hereEither set them in .env:
DOMAIN=example.com
EMAIL=admin@example.comOr pass them as arguments:
cloudflare-request-cert -d example.com -e admin@example.comEnsure your Cloudflare API token has:
- Zone:DNS:Edit permissions
- Zone:Zone:Read permissions
If validation fails, try increasing propagation time:
cloudflare-request-cert -d example.com -e admin@example.com --propagation-seconds 60Or set in .env:
PROPAGATION_SECONDS=60Let's Encrypt has rate limits. Use staging for testing:
# Set in .env
STAGING=1
# Or via CLI
cloudflare-request-cert -d example.com -e admin@example.com --stagingThis is a Cloudflare remake of the loopia-request-cert tool with several improvements:
- Uses Cloudflare instead of Loopia DNS
- Uses uv for faster dependency management (10-100x faster than pip)
- Modern pyproject.toml configuration
- Improved Makefile with more commands
- Better error handling and user feedback
- Flexible configuration: .env file, CLI args, or both
- Type hints for better code quality
- Ruff for linting and formatting
- Comprehensive tests
MIT License
Contributions are welcome! Please feel free to submit a Pull Request.