SSL/TLS certificate automation using Cloudflare DNS
Project description
Cloudflare Request Cert
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.
Features
- 🔒 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
Prerequisites
- Python 3.10 or higher
- A Cloudflare account with API token
- Domain managed by Cloudflare DNS
Installation
Quick Setup
# Install dependencies (will install uv if not present)
make install
Manual uv Installation
If you prefer to install uv manually:
curl -LsSf https://astral.sh/uv/install.sh | sh
Configuration
1. Get Cloudflare API Token
- 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
2. Set Up Credentials
Create a .env file in the project root:
# Copy the example file
cp .env.example .env
# Edit with your credentials
nano .env
Your .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 time
Security Note: The .env file is already in .gitignore. Never commit API tokens to version control.
Usage
Three Ways to Use This Tool
1. Using .env File Only
Set everything in .env and run without arguments:
# .env file contains: CLOUDFLARE_API_TOKEN, DOMAIN, EMAIL
cloudflare-request-cert
2. Using Command-Line Arguments Only
# Provide all parameters via CLI (API token still from .env or environment)
cloudflare-request-cert -d example.com -e admin@example.com
3. Mix of Both (Recommended)
# 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.com
Using Make Commands
Request 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
Advanced Options
# 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.env
Priority Order
When 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
Makefile Commands
| 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 |
Certificate Locations
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
DNS Propagation Time
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=30
Automatic Renewal
Certbot 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.timer
Development
Install Development Dependencies
make dev
Run Tests
make test
Run Linting
make lint
Format Code
make format
Run All Checks
make check
Generate SBOM
Generate a Software Bill of Materials (SBOM) in CycloneDX JSON format:
make sbom
The SBOM will be saved to bom.json.
Example Workflows
First Time Setup
# 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
Managing Multiple Domains
# 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
Automated Script
#!/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"
done
Troubleshooting
"certbot not found"
Install certbot and the Cloudflare plugin:
make install
# or
uv sync
"CLOUDFLARE_API_TOKEN is required"
Make sure your .env file exists and contains:
CLOUDFLARE_API_TOKEN=your_actual_token_here
"DOMAIN is required" or "EMAIL is required"
Either set them in .env:
DOMAIN=example.com
EMAIL=admin@example.com
Or pass them as arguments:
cloudflare-request-cert -d example.com -e admin@example.com
API Token Permissions
Ensure your Cloudflare API token has:
- Zone:DNS:Edit permissions
- Zone:Zone:Read permissions
DNS Propagation Issues
If validation fails, try increasing propagation time:
cloudflare-request-cert -d example.com -e admin@example.com --propagation-seconds 60
Or set in .env:
PROPAGATION_SECONDS=60
Rate Limits
Let'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 --staging
Comparison with Original
This 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
License
MIT License
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Resources
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cloudflare_request_cert-0.1.9.tar.gz.
File metadata
- Download URL: cloudflare_request_cert-0.1.9.tar.gz
- Upload date:
- Size: 91.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
256b026004432a3da4c1c151dd4e83071445f1ddd2b784a1fa93b77ae0aa5f82
|
|
| MD5 |
9db4c2a1d98f9c40f74c24ad0f5f605c
|
|
| BLAKE2b-256 |
e1b4ccf4c4294041b41c5b0927370740b242695eaa177d41e3295d201aa96126
|
Provenance
The following attestation bundles were made for cloudflare_request_cert-0.1.9.tar.gz:
Publisher:
ci.yml on hellqvio86/cloudflare-request-cert
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cloudflare_request_cert-0.1.9.tar.gz -
Subject digest:
256b026004432a3da4c1c151dd4e83071445f1ddd2b784a1fa93b77ae0aa5f82 - Sigstore transparency entry: 1131436490
- Sigstore integration time:
-
Permalink:
hellqvio86/cloudflare-request-cert@93b29c15318a06fe1f02829260aef0ffa1637148 -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/hellqvio86
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@93b29c15318a06fe1f02829260aef0ffa1637148 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cloudflare_request_cert-0.1.9-py3-none-any.whl.
File metadata
- Download URL: cloudflare_request_cert-0.1.9-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ca74f58474fcd87ece423e57614cf275637a99245bf2a8ccfbc2ed2277e92a8
|
|
| MD5 |
2fb7313c9db6fe78c1230a656d39b604
|
|
| BLAKE2b-256 |
fc76bc31acbb6936f4bbd82bf53f4673929d445a534e9f980438848f65fa0b4f
|
Provenance
The following attestation bundles were made for cloudflare_request_cert-0.1.9-py3-none-any.whl:
Publisher:
ci.yml on hellqvio86/cloudflare-request-cert
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cloudflare_request_cert-0.1.9-py3-none-any.whl -
Subject digest:
5ca74f58474fcd87ece423e57614cf275637a99245bf2a8ccfbc2ed2277e92a8 - Sigstore transparency entry: 1131436572
- Sigstore integration time:
-
Permalink:
hellqvio86/cloudflare-request-cert@93b29c15318a06fe1f02829260aef0ffa1637148 -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/hellqvio86
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@93b29c15318a06fe1f02829260aef0ffa1637148 -
Trigger Event:
release
-
Statement type: