nginx-acme

repository·main·Indexed 19 days ago

https://github.com/nginx/nginx-acme

An NGINX module (version 0.4.1) that automates certificate management using the ACMEv2 protocol. It supports HTTP-01 challenges and extensions including RFC8737 (ALPN), RFC8738 (IP Identifier), RFC9773 (ARI), and draft-ietf-acme-profiles. The module provides directives such as acme_issuer, acme_shared_zone, and acme_certificate, along with embedded variables $acme_certificate and $acme_certificate_key for SSL configuration.

Tokens
11.2K
Snippets
32
Records
52
Agent score
65%

What's inside nginx-acme

  1. Overview of nginx-acme

    main

    nginx-acme is an NGINX module that implements the ACMEv2 (Automatic Certificate Management Environment) protocol for automatic certificate management.

    It supports the following specifications:

    • RFC8555 (ACME) with HTTP-01 challenge type support only.
    • RFC8737 (ACME ALPN Challenge Extension).
    • RFC8738 (ACME IP Identifier Validation Extension).
    • RFC9773 (ACME Renewal Information (ARI) Extension).
    • draft-ietf-acme-profiles (ACME Profiles Extension, version 01).
  2. Build nginx-acme using NGINX auto/configure

    main

    Alternatively, you can use the NGINX configuration script. This method produces a slightly larger library because it does not currently instruct the linker to perform LTO. The resulting library will be located at objs/ngx_http_acme_module.so.

    # in the NGINX source directory
    auto/configure \
        --with-compat \
        --with-http_ssl_module \
        --add-[dynamic-]module=/path/to/nginx-acme
  3. Requirements for building nginx-acme

    main

    To build the module, ensure your environment meets the following requirements:

    NGINX Requirements:

    • NGINX sources, version 1.22.0 or later.
    • Regular NGINX build dependencies: C compiler, make, PCRE2, and Zlib.
    • The module is compatible with NGINX Plus if built against unmodified NGINX Open Source with --with-compat and --with-http_ssl_module.

    System & Toolchain Requirements:

    • System-wide installation of OpenSSL 1.1.1 or later.
    • Rust toolchain (1.81.0 or later).
    • pkg-config or pkgconf.
    • libclang for rust-bindgen.

    Critical SSL Compatibility Note: To avoid memory issues and crashes, the module must use the same SSL implementation as NGINX. It is highly recommended to build both using a system-provided shared library. If using an alternative SSL implementation, you must set the appropriate OPENSSL_* environment variables for the Rust bindings. If building a dynamic module, ensure you use dynamic linking for the SSL library to avoid independent global states.

  4. Build nginx-acme using cargo

    main

    You can build the module by exporting the path to a configured NGINX source tree and using cargo. The resulting library will be located at target/release/libnginx_acme.so.

    # checkout, configure and build NGINX at ../nginx
    cd nginx-acme
    export NGINX_BUILD_DIR=$(realpath ../nginx/objs)
    cargo build --release
  5. Configure nginx-acme in NGINX

    main

    To use the module, add it to your NGINX configuration. Note: This module requires a resolver configuration in the http block.

    Key configuration components:

    • acme_issuer: Defines the ACME issuer (URI, state path, etc.).
    • acme_shared_zone: Defines a shared memory zone for ACME data.
    • acme_certificate: Associates a server block with a specific issuer.
    • ssl_certificate / ssl_certificate_key: Uses the special $acme_certificate and $acme_certificate_key variables provided by the module.
    • Port 80: A listener on port 80 is required to process ACME HTTP-01 challenges.
    resolver 127.0.0.1:53;
    
    acme_issuer example {
        uri         https://acme.example.com/directory;
        # contact     admin@example.test;
        state_path  /var/cache/nginx/acme-example;
        accept_terms_of_service;
    }
    
    acme_shared_zone zone=ngx_acme_shared:1M;
    
    server {
        listen 443 ssl;
        server_name  .example.test
                     192.0.2.1      # not supported by some ACME servers
                     2001:db8::1    # not supported by some ACME servers
                     ;
    
        acme_certificate example;
    
        ssl_certificate       $acme_certificate;
        ssl_certificate_key   $acme_certificate_key;
    
        # do not parse the certificate on each request
        ssl_certificate_cache max=2;
    }
    
    server {
        # listener on port 80 is required to process ACME HTTP-01 challenges
        listen 80;
    
        location / {
            return 404;
        }
    }
  6. Get support for nginx-acme

    main

    For questions regarding the functionality, bugs, or feature requests of nginx-acme, use GitHub:

    • Bugs and Feature Requests: Open a GitHub issue.
    • General Questions: Open a GitHub issue with the question label, or start a GitHub discussion.

    Community support is provided on a best-effort basis via GitHub and other active communities.

  7. Run nginx-acme integration tests

    main

    The repository includes an integration test suite based on nginx-tests. To run them, you must specify the paths to your NGINX source and NGINX tests directories. Most tests require the pebble test server binary to be in your PATH or specified via the TEST_NGINX_PEBBLE_BINARY environment variable.

    # Path to the nginx source checkout, defaults to ../nginx if not specified.
    export NGINX_SOURCE_DIR=$(realpath ../nginx)
    # Path to the nginx-tests checkout; defaults to ../nginx/tests if not specified.
    export NGINX_TESTS_DIR=$(realpath ../nginx-tests)
    
    make test
  8. Configure NGX_ACME_STATE_PREFIX build option

    main

    All module build-time options are set via environment variables passed to cargo build or make.

    Use NGX_ACME_STATE_PREFIX to set a default prefix for per-issuer state paths. If this is unset, state paths are created relative to the NGINX prefix directory. The prefix directory must be existing and readable by NGINX worker processes.

    export NGX_ACME_STATE_PREFIX=/var/cache/nginx
    auto/configure \
        ... \
        --with-compat \
        --with-http_ssl_module \
        --add-dynamic-module=/path/to/nginx-acme
    make
  9. How the TLS ALPN-01 challenge works

    main

    The tls-alpn-01 challenge implementation intercepts TLS handshakes on port 443. It specifically looks for the acme-tls/1 protocol advertised via Application-Layer Protocol Negotiation (ALPN).

    When a client (like an ACME CA) advertises acme-tls/1, the module diverts the handshake processing from the standard NGINX flow. It uses a specialized SSL context to present a temporary challenge certificate. This allows the challenge to be completed even if the standard NGINX virtual server is configured to require client certificates or reject certain handshakes, as the module registers its handlers early in the ClientHello processing phase.

  10. Configure an ACME issuer with acme_issuer

    main

    Use the acme_issuer directive in the http context to define an ACME certificate issuer object. This object contains the configuration for connecting to an ACME server, managing account keys, and handling challenges.

    Mandatory Configuration:

    • uri: The directory URL of the ACME server.

    Key Options:

    • account_key: Specifies the account's private key. You can use an algorithm/size pair (e.g., ecdsa:256) to generate one, or provide a file path to an existing key.
    • challenge: Sets the challenge type. Supported values are http-01 (default) and tls-alpn-01.
    • state_path: Defines a directory to persist module data (account keys, issued certificates, private keys) across restarts. If not configured, keys will be lost on restart.
    • accept_terms_of_service: Agrees to the ACME server's terms of service (required by some servers).
    • contact: Sets an array of contact URLs (defaults to mailto: scheme).
    acme_issuer my_issuer {
        uri "https://acme-server.example.com/directory";
        account_key ecdsa:256;
        challenge http-01;
        state_path /var/lib/nginx/acme/my_issuer;
        accept_terms_of_service;
    }
  11. Configure ACME shared memory with acme_shared_zone

    main

    Use the acme_shared_zone directive in the http context to adjust the size of the in-memory storage used by the module. This zone stores issued certificates, keys, and challenge data for all configured issuers.

    Syntax: acme_shared_zone zone=name:size Default: zone=ngx_acme_shared:256k

    Capacity Note: The default size (256k) is sufficient for approximately 50 ECDSA prime256v1 keys or 35 RSA 2048 keys.