{"id":1307,"library":"acme","title":"ACME protocol implementation in Python","description":"The `acme` library is a low-level, comprehensive Python implementation of the Automated Certificate Management Environment (ACME) protocol, primarily maintained as part of the Certbot project. It enables programmatic certificate issuance, renewal, and management, supporting Let's Encrypt and other ACME-compatible certificate authorities. Currently at version 5.5.0, `acme` follows the release cadence of Certbot, typically seeing several updates per year, often driven by new ACME RFCs or internal Certbot architectural changes.","status":"active","version":"5.5.0","language":"en","source_language":"en","source_url":"https://github.com/certbot/certbot","tags":["ACME","SSL","TLS","Certbot","Let's Encrypt","certificates","cryptography","PKI"],"install":[{"cmd":"pip install acme","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Requires Python 3.10 or later.","package":"python","optional":false},{"reason":"Cryptography utilities for JOSE (JSON Object Signing and Encryption).","package":"josepy","optional":false},{"reason":"Core cryptographic primitives for Python.","package":"cryptography","optional":false},{"reason":"HTTP library for making requests to ACME servers.","package":"requests","optional":false},{"reason":"OpenSSL wrapper for Python (though usage has been reduced/deprecated in favor of 'cryptography').","package":"pyopenssl","optional":false}],"imports":[{"symbol":"ClientV2","correct":"from acme import client"},{"symbol":"messages","correct":"from acme import messages"},{"symbol":"challenges","correct":"from acme import challenges"},{"symbol":"josepy","correct":"import josepy as jose"},{"note":"While developed with Certbot, crypto_util is part of the acme package itself.","wrong":"from certbot import crypto_util","symbol":"crypto_util","correct":"from acme import crypto_util"}],"quickstart":{"code":"import os\nfrom cryptography.hazmat.primitives.asymmetric import rsa\nfrom cryptography.hazmat.backends import default_backend\n\nfrom acme import client\nfrom acme import messages\nimport josepy as jose\n\n# This is the staging ACME URL for Let's Encrypt\nDIRECTORY_URL = os.environ.get('ACME_DIRECTORY_URL', 'https://acme-staging-v02.api.letsencrypt.org/directory')\n\ndef run_acme_client():\n    # 1. Create a new ACME account private key\n    acc_key_pem = rsa.generate_private_key(\n        public_exponent=65537, key_size=2048, backend=default_backend()\n    )\n    acc_key = jose.JWK.from_pem(acc_key_pem.private_bytes(\n        encoding=jose.serialization.Encoding.PEM,\n        format=jose.serialization.PrivateFormat.PKCS8,\n        encryption_algorithm=jose.serialization.NoEncryption()\n    ))\n\n    # 2. Initialize the client network\n    net = client.ClientNetwork(acc_key, user_agent=\"my-acme-client/1.0\")\n\n    # 3. Get the ACME directory object\n    directory = messages.Directory.from_json(net.get(DIRECTORY_URL).json())\n\n    # 4. Create the ACME client\n    acme_client = client.ClientV2(directory, net=net)\n\n    # 5. Register a new account (or load existing)\n    #   email_contact is optional for staging/testing\n    new_reg = messages.NewRegistration(\n        terms_of_service_agreed=True, \n        contact=('mailto:test@example.com',) if 'test@example.com' in os.environ.get('ACME_EMAIL', '') else None\n    )\n    \n    try:\n        regr = acme_client.new_account(new_reg)\n        print(f\"Account created/loaded: {regr.uri}\")\n    except client.errors.ConflictError as e:\n        # Account already exists, retrieve it\n        print(f\"Account already exists, retrieving: {e.uri}\")\n        regr = acme_client.query_registration(messages.RegistrationResource(uri=e.uri, body=new_reg))\n\n    print(\"ACME client initialized and account registered.\")\n    return acme_client, regr\n\nif __name__ == \"__main__\":\n    acme_client_instance, account_resource = run_acme_client()","lang":"python","description":"This quickstart demonstrates the absolute minimum to initialize the `acme` client and register an account with an ACME server (like Let's Encrypt staging). Note that `acme` is a low-level library; most users will prefer a higher-level client like Certbot for end-to-end certificate management. This example creates an RSA account key, sets up the network client, fetches the directory, and attempts to register a new ACME account, handling potential conflicts if the account already exists. It uses the Let's Encrypt staging environment by default."},"warnings":[{"fix":"Migrate any code using these removed classes/functions to their `cryptography` equivalents or alternative ACME challenge methods. Review the `certbot` changelog for detailed migration paths. For TLS-ALPN, re-evaluate if still necessary as its support was deprecated and then removed.","message":"Major architectural shift in version 5.0.0 (aligned with Certbot 5.0.0) removed `acme.crypto_util.SSLSocket`, `acme.crypto_util.probe_sni`, and TLS-ALPN related challenge classes (`acme.challenges.TLSALPN01Response`, `acme.challenges.TLSALPN01`, `acme.standalone.TLSServer`, `acme.standalone.TLSALPN01Server`). This also removed final `pyopenssl` x509 and PKey objects usage within `acme`'s core cryptography, favoring `cryptography` library objects.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Avoid using `acme.crypto_util.make_self_signed_cert`. If self-signed certificates are required, use `cryptography`'s API directly or an external tool.","message":"The function `acme.crypto_util.make_self_signed_cert` was deprecated in Certbot 5.1.0 and is slated for removal. This indicates a shift away from generating self-signed certificates directly within the `acme` library.","severity":"deprecated","affected_versions":">=5.1.0"},{"fix":"Ensure all ACME interactions adhere to RFC 8555. Update any references to `OLD_ERROR_PREFIX` or the removed `Directory` and `Authorization` attributes. The `source_address` removal requires alternative methods for binding to specific local IPs if needed.","message":"Version 2.0.0 (aligned with Certbot 2.0.0) removed support for pre-RFC 8555 ACME versions and related deprecated messaging constructs like `acme.messages.OLD_ERROR_PREFIX`. It also removed the `source_address` argument from `acme.client.ClientNetwork` and several deprecated attributes from `acme.messages.Directory` and `acme.messages.Authorization`.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure your environment meets these minimum dependency versions to avoid runtime errors, especially when upgrading `acme` or `certbot`.","message":"The `acme` library's cryptographic requirements are tightly coupled with `certbot`'s and have increased over time. As of Certbot 3.2.0, `acme` requires `cryptography>=43.0.0` and `pyOpenSSL>=25.0.0`.","severity":"gotcha","affected_versions":">=3.2.0"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}