Created
November 9, 2025 03:56
-
-
Save albertyw/4ff24559a1ef6d1c447649b45dad1c10 to your computer and use it in GitHub Desktop.
Generate Cloudflare origin certificate for multiple domains
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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