Skip to content

Instantly share code, notes, and snippets.

@albertyw
Created November 9, 2025 03:56
Show Gist options
  • Select an option

  • Save albertyw/4ff24559a1ef6d1c447649b45dad1c10 to your computer and use it in GitHub Desktop.

Select an option

Save albertyw/4ff24559a1ef6d1c447649b45dad1c10 to your computer and use it in GitHub Desktop.
Generate Cloudflare origin certificate for multiple domains
"""
This script generates an origin certificate from Cloudlare using their API.
It requires the 'requests' library to make HTTP requests.
"""
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import requests
# Origin SSL Certificate Update API Token
# Generate at https://dash.cloudflare.com/profile/api-tokens
# Create a Token -> Create Custom Token
# Settings: Permissions Zone + SSL and Certificates + Edit
AUTH_TOKEN = "<TOKEN>"
INSTRUCTIONS = """
sudo cp certificates/server.key /etc/nginx/ssl/server.key
sudo cp certificates/server.pem /etc/nginx/ssl/server.pem
sudo chmod 640 /etc/nginx/ssl/server.key
# Restart nginx
# /etc/init.d/nginx restart
"""
def get_domains() -> list[str]:
return [
"example.com",
"example2.com",
"example3.com",
]
def generate_key() -> rsa.RSAPrivateKey:
# Generate our key
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Write our key to disk for safe keeping
with open("certificates/server.key", "wb") as f:
private_bytes = key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
print("Private Key for signing")
print(private_bytes.decode("utf-8"))
f.write(private_bytes)
return key
def generate_csr(key: rsa.RSAPrivateKey) -> str:
# Generate a CSR
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
# Provide various details about who we are.
x509.NameAttribute(NameOID.COUNTRY_NAME, "<COUNTRY>"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "<STATE>"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "<CITY>"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "<ORGANIZATION>"),
x509.NameAttribute(NameOID.COMMON_NAME, "<COMMON_NAME>"),
])).sign(key, hashes.SHA256())
csr_bytes = csr.public_bytes(serialization.Encoding.PEM)
with open("certificates/csr.pem", "wb") as f:
f.write(csr_bytes)
csr_string = csr_bytes.decode("utf-8")
print("Certificate Signing Request:")
print(csr_string)
return csr_string
def request_origin_certificate(csr: str, domains: list[str]) -> None:
# Request the origin certificate from Cloudflare
url = "https://api.cloudflare.com/client/v4/certificates"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer %s" % AUTH_TOKEN,
}
domains += ["*.%s" % d for d in domains]
print("Domains:")
print(domains)
data = {
"csr": csr,
"hostnames": domains,
"request_type": "origin-rsa",
"requested_validity": 5475, # Valid for 15 years
}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 200:
print("Origin certificate requested successfully.")
data = response.json()
certificate_pem = data["result"]["certificate"] # type: ignore
with open("certificates/server.pem", "w") as f:
f.write(certificate_pem.strip())
print("Origin certificate:")
print(certificate_pem)
else:
print("Failed to request origin certificate.")
print("Status Code:", response.status_code)
print(response.text)
def main() -> None:
domains = get_domains()
key = generate_key()
csr_string = generate_csr(key)
request_origin_certificate(csr_string, domains)
print(INSTRUCTIONS)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment