### Optional CertMagex Configuration Source: https://github.com/dominicletz/certmagex/blob/master/README.md Example configuration for CertMagex in config.exs, specifying the ZeroSSL provider, account key, address, user email, and storage module. ```elixir config :certmagex, provider: :zerossl, account_key: System.get_env("ZEROSSL_ACCOUNT_KEY"), addr: "0.0.0.0", user_email: "your@email.com", storage_module: CertMagex.Storage.Acmev2Adapter ``` -------------------------------- ### CertMagex.Acmev2.gen_cert/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Performs the full ACMEv2 HTTP-01 challenge flow to issue a certificate for a domain or IP address. It starts an HTTP server, handles account registration/reuse, and returns the private key and certificate in PEM format. ```APIDOC ## `CertMagex.Acmev2.gen_cert/1` — Low-level ACMEv2 certificate issuance Executes the full ACMEv2 HTTP-01 challenge flow for a domain or IP address. Starts an ephemeral HTTP server on port 80, registers or reuses an ACME account, completes the challenge, and returns `{private_key_pem, certificate_pem}`. Called automatically by `CertMagex.Worker`; can also be called directly for scripted certificate issuance. ### Configuration Examples ```elixir # config/runtime.exs (for Let's Encrypt, no extra config needed) config :certmagex, provider: :letsencrypt, user_email: "ops@example.com" # config/runtime.exs (for ZeroSSL — requires account key or email) config :certmagex, provider: :zerossl, account_key: System.get_env("ZEROSSL_API_KEY"), user_email: "ops@example.com" # config/runtime.exs (for Let's Encrypt staging / testing) config :certmagex, provider: :letsencrypt_test, user_email: "ops@example.com" ``` ### Usage ```elixir # Direct invocation (port 80 must be free): {cert_priv_key, public_cert} = CertMagex.Acmev2.gen_cert("example.com") File.write!("cert.pem", public_cert) File.write!("key.pem", cert_priv_key) # Files can now be used directly with :ssl or Plug.SSL # IP address certificate (Let's Encrypt only, ~6-day validity): {cert_priv_key, public_cert} = CertMagex.Acmev2.gen_cert("203.0.113.5") # Raises if provider is :zerossl ``` ``` -------------------------------- ### Configure Renewal Threshold in CertMagex Source: https://context7.com/dominicletz/certmagex/llms.txt Set the renewal threshold for CertMagex to renew certificates early. This example sets the renewal to occur 2 days before expiration. ```elixir config :certmagex, renewal_threshold: 172_800 # renew 2 days early ``` -------------------------------- ### Retrieve SSL Options for IP Certificates Source: https://context7.com/dominicletz/certmagex/llms.txt Use `CertMagex.ssl_opts/1` to safely retrieve SSL options for a domain or IP address, useful for non-Phoenix servers or IP-based certificates. It returns an empty list on error. ```elixir domain = "203.0.113.10" # IPv4 — only works with :letsencrypt or :letsencrypt_test ssl_opts = CertMagex.ssl_opts(domain) # => [cert: <<...>>, key: {:ECPrivateKey, <<...>>}] # => [] on error (logged via Logger.error) # Example: starting an :ssl listen socket manually {:ok, listen_socket} = :ssl.listen(8443, [ {:reuseaddr, true} | ssl_opts ]) ``` -------------------------------- ### Configure CertMagex for Cowboy Source: https://github.com/dominicletz/certmagex/blob/master/README.md Add this configuration to your prod.exs to enable CertMagex with Cowboy. Ensure port 80 is free and HTTP is commented out. ```elixir config , , https: [port: 443, sni_fun: &CertMagex.sni_fun/1], # ATTENTION: Ensure you comment http: out and port 80 is free! ... ``` -------------------------------- ### Insert Certificate into Cache (Auto-Detect Domains) Source: https://context7.com/dominicletz/certmagex/llms.txt Use `CertMagex.insert/2` to pre-load a PEM-encoded private key and certificate into the cache. Domains are automatically extracted from the certificate's Subject and Subject Alternative Names. ```elixir cert_priv_key = File.read!("priv/ssl/key.pem") public_cert = File.read!("priv/ssl/cert.pem") # Insert for all domains found in the certificate automatically CertMagex.insert(cert_priv_key, public_cert) # => [{"example.com", {{[<>], key_tuple}, ~U[2025-06-01 00:00:00Z]}}, ...] # (one entry per domain/SAN found in the cert) ``` -------------------------------- ### CertMagex Configuration Reference Source: https://context7.com/dominicletz/certmagex/llms.txt Configure CertMagex by setting options under the :certmagex application key. This includes specifying the ACME provider, user email, account key for ZeroSSL, and network settings for the challenge server. ```elixir # config/prod.exs (or config/runtime.exs for runtime secrets) config :certmagex, # ACME provider — :letsencrypt (default), :letsencrypt_test, or :zerossl provider: :letsencrypt, # Contact email sent to the ACME provider user_email: "ops@example.com", # ZeroSSL only: your API / account key (https://app.zerossl.com/developer) account_key: System.get_env("ZEROSSL_ACCOUNT_KEY"), # Bind address for the temporary HTTP-01 challenge server # Defaults to "0.0.0.0" (IPv4) or "::" (IPv6) depending on host capability addr: "0.0.0.0", # TCP port for the HTTP-01 challenge server (must be reachable as port 80 externally) port: 80, # Renew certificates this many seconds before expiry (default: 86_400 = 1 day) renewal_threshold: 86_400, # Storage module for ACME account key and EAB credentials # Defaults to CertMagex.Storage.Acmev2Adapter (DetsPlus-backed) storage_module: CertMagex.Storage.Acmev2Adapter, # Optional: only these SNI hostnames trigger ACME work (case-insensitive) # If unset or [], every SNI is handled sni_allowed_hosts: ["www.example.com", "api.example.com"] ``` -------------------------------- ### Configure CertMagex for Bandit Source: https://github.com/dominicletz/certmagex/blob/master/README.md Add this configuration to your prod.exs to enable CertMagex with Bandit. Ensure port 80 is free and HTTP is commented out. ```elixir config , , https: [port: 443, thousand_island_options: [transport_options: [sni_fun: &CertMagex.sni_fun/1]]], # ATTENTION: Ensure you comment http: out and port 80 is free! ... ``` -------------------------------- ### CertMagex.ssl_opts/1 Source: https://context7.com/dominicletz/certmagex/llms.txt A safe wrapper around `sni_fun/1` that catches exits and always returns a list. Useful for programmatically building SSL options for IP-address-based certificates or non-Phoenix servers. ```APIDOC ## CertMagex.ssl_opts/1 ### Description Retrieves SSL options for a domain or IP address, useful for IP certs or non-Phoenix servers. It's a safe wrapper around `sni_fun/1` that catches exits and always returns a list. ### Function Signature `CertMagex.ssl_opts(domain_or_ip)` ### Parameters #### Path Parameters - **domain_or_ip** (string) - The domain name or IP address for which to retrieve SSL options. ### Returns - `[cert: ..., key: ...]` - A list of SSL options if successful. - `[]` - An empty list on error (errors are logged via Logger.error). ### Example Usage ```elixir # Retrieve SSL options for a domain or IP address and merge into a socket config domain = "203.0.113.10" # IPv4 — only works with :letsencrypt or :letsencrypt_test ssl_opts = CertMagex.ssl_opts(domain) # => [cert: <<...>>, key: {:ECPrivateKey, <<...>>}] # => [] on error (logged via Logger.error) # Example: starting an :ssl listen socket manually {:ok, listen_socket} = :ssl.listen(8443, [ {:reuseaddr, true} | ssl_opts ]) ``` ``` -------------------------------- ### Custom Storage Backend for CertMagex Source: https://context7.com/dominicletz/certmagex/llms.txt Implement the `read/1`, `write/2`, and `exists?/1` callbacks to integrate a custom storage backend for ACME account keys and EAB credentials. Configure the custom module using `storage_module` in CertMagex configuration. ```elixir defmodule MyApp.CertStorage do @behaviour CertMagex.Storage # informal — match the 3 callbacks def read(key) do case MyApp.Vault.get("certmagex/#{key}") do {:ok, value} -> {:ok, value} :error -> {:error, :not_found} end end def write(key, value) do MyApp.Vault.put("certmagex/#{key}", value) end def exists?(key) do MyApp.Vault.exists?("certmagex/#{key}") end end # config/prod.exs config :certmagex, storage_module: MyApp.CertStorage ``` -------------------------------- ### CertMagex.sni_fun/1 Source: https://context7.com/dominicletz/certmagex/llms.txt The primary integration point for automatic certificate provisioning. Pass this function as the `sni_fun` option in your HTTPS configuration. It receives the SNI hostname, fetches or generates a certificate, and returns the OTP SSL options. Returns `:undefined` if the domain is not on the allow-list or if an IP certificate is requested with an unsupported provider. ```APIDOC ## CertMagex.sni_fun/1 ### Description SNI callback for automatic certificate provisioning. Receives the SNI hostname from each TLS handshake, fetches or generates a certificate, and returns the OTP SSL options `[cert: ..., key: ...]`. Returns `:undefined` if the domain is not on the allow-list or if an IP certificate is requested with an unsupported provider. ### Function Signature `CertMagex.sni_fun(hostname)` ### Parameters #### Path Parameters - **hostname** (string) - The SNI hostname from the TLS handshake. ### Example Usage ```elixir # config/prod.exs — Cowboy (Phoenix default) config :my_app, MyAppWeb.Endpoint, https: [ port: 443, sni_fun: &CertMagex.sni_fun/1 # IMPORTANT: comment out the http: option; port 80 must be free for ACME challenges ] # config/prod.exs — Bandit config :my_app, MyAppWeb.Endpoint, https: [ port: 443, thousand_island_options: [ transport_options: [sni_fun: &CertMagex.sni_fun/1] ] ] # Optional: restrict which SNI hostnames trigger certificate handling config :certmagex, sni_allowed_hosts: ["www.example.com", "api.example.com"] # Result when called at runtime: # CertMagex.sni_fun("www.example.com") # => [cert: <>, key: {:ECPrivateKey, <<...>>}] # # CertMagex.sni_fun("scanner.malicious.example") # not in allow-list # => :undefined ``` ``` -------------------------------- ### Configure Cowboy (Phoenix) HTTPS with CertMagex SNI Fun Source: https://context7.com/dominicletz/certmagex/llms.txt Configure your Phoenix application's endpoint to use CertMagex's `sni_fun` for automatic certificate provisioning. Ensure port 80 is free for ACME challenges. ```elixir config :my_app, MyAppWeb.Endpoint, https: [ port: 443, sni_fun: &CertMagex.sni_fun/1 # IMPORTANT: comment out the http: option; port 80 must be free for ACME challenges ] ``` -------------------------------- ### Configure Bandit HTTPS with CertMagex SNI Fun Source: https://context7.com/dominicletz/certmagex/llms.txt Configure your Bandit-based application's endpoint to use CertMagex's `sni_fun` for automatic certificate provisioning. ```elixir config :my_app, MyAppWeb.Endpoint, https: [ port: 443, thousand_island_options: [ transport_options: [sni_fun: &CertMagex.sni_fun/1] ] ] ``` -------------------------------- ### Insert Certificate for Specific Domain Source: https://context7.com/dominicletz/certmagex/llms.txt Use `CertMagex.insert/3` to pre-load a certificate for an explicit domain name, bypassing automatic domain extraction. Returns the decoded `{{certs, key}, validity}` tuple. ```elixir cert_priv_key = File.read!("priv/ssl/key.pem") public_cert = File.read!("priv/ssl/cert.pem") {{certs, key}, validity} = CertMagex.insert("www.example.com", cert_priv_key, public_cert) IO.inspect(validity) # => ~U[2025-09-01 12:00:00Z] IO.inspect(length(certs)) # => 2 (leaf cert + intermediate) ``` -------------------------------- ### Low-level ACMEv2 Certificate Issuance with CertMagex.Acmev2.gen_cert/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Executes the full ACMEv2 HTTP-01 challenge flow for domain or IP certificates. Requires configuration for the ACME provider and user email. Ensure port 80 is free for the temporary HTTP server. ```elixir # config/runtime.exs (for Let's Encrypt, no extra config needed) config :certmagex, provider: :letsencrypt, user_email: "ops@example.com" ``` ```elixir # config/runtime.exs (for ZeroSSL — requires account key or email) config :certmagex, provider: :zerossl, account_key: System.get_env("ZEROSSL_API_KEY"), user_email: "ops@example.com" ``` ```elixir # config/runtime.exs (for Let's Encrypt staging / testing) config :certmagex, provider: :letsencrypt_test, user_email: "ops@example.com" ``` ```elixir # Direct invocation (port 80 must be free): {cert_priv_key, public_cert} = CertMagex.Acmev2.gen_cert("example.com") File.write!("cert.pem", public_cert) File.write!("key.pem", cert_priv_key) # Files can now be used directly with :ssl or Plug.SSL ``` ```elixir # IP address certificate (Let's Encrypt only, ~6-day validity): {cert_priv_key, public_cert} = CertMagex.Acmev2.gen_cert("203.0.113.5") # Raises if provider is :zerossl ``` -------------------------------- ### Restrict SNI Hostnames for Certificate Handling Source: https://context7.com/dominicletz/certmagex/llms.txt Optionally, configure CertMagex to only handle certificate requests for specific hostnames to prevent unnecessary Let's Encrypt requests. ```elixir config :certmagex, sni_allowed_hosts: ["www.example.com", "api.example.com"] ``` -------------------------------- ### CertMagex.insert/2 Source: https://context7.com/dominicletz/certmagex/llms.txt Inserts a PEM-encoded private key and certificate into the in-memory and persistent cache. Domains are automatically extracted from the certificate's Subject and Subject Alternative Names. ```APIDOC ## CertMagex.insert/2 ### Description Pre-loads a private key and certificate into the CertMagex cache. Domains are automatically detected from the certificate's Subject and Subject Alternative Names (including DNS names and IP addresses). Useful for importing externally-issued certificates. ### Function Signature `CertMagex.insert(private_key_pem, public_cert_pem)` ### Parameters #### Path Parameters - **private_key_pem** (string) - The PEM-encoded private key. - **public_cert_pem** (string) - The PEM-encoded public certificate. ### Returns - `[ {domain, {ssl_opts, validity_tuple}} ]` - A list of tuples, where each tuple contains a domain found in the certificate, its corresponding SSL options, and the certificate's validity period. ### Example Usage ```elixir cert_priv_key = File.read!("priv/ssl/key.pem") public_cert = File.read!("priv/ssl/cert.pem") # Insert for all domains found in the certificate automatically CertMagex.insert(cert_priv_key, public_cert) # => [{"example.com", {{[<>], key_tuple}, ~U[2025-06-01 00:00:00Z]}}, ...] # (one entry per domain/SAN found in the cert) ``` ``` -------------------------------- ### Add CertMagex Dependency Source: https://github.com/dominicletz/certmagex/blob/master/README.md Add the CertMagex dependency to your project's deps function in mix.exs. ```elixir def deps do [ {:certmagex, "~> 1.0"} ] end ``` -------------------------------- ### CertMagex.insert/3 Source: https://context7.com/dominicletz/certmagex/llms.txt Inserts a certificate for an explicit domain name, bypassing automatic domain extraction. Returns the decoded `{{certs, key}, validity}` tuple. ```APIDOC ## CertMagex.insert/3 ### Description Pre-loads a certificate into the cache for a specific, explicitly provided domain name, bypassing automatic domain extraction from the certificate. Returns the decoded `{{certs, key}, validity}` tuple. ### Function Signature `CertMagex.insert(domain, private_key_pem, public_cert_pem)` ### Parameters #### Path Parameters - **domain** (string) - The explicit domain name to associate with the certificate. - **private_key_pem** (string) - The PEM-encoded private key. - **public_cert_pem** (string) - The PEM-encoded public certificate. ### Returns - `{{certs, key}, validity}` - A tuple containing the decoded certificate and key, and the certificate's validity period. ### Example Usage ```elixir cert_priv_key = File.read!("priv/ssl/key.pem") public_cert = File.read!("priv/ssl/cert.pem") {{certs, key}, validity} = CertMagex.insert("www.example.com", cert_priv_key, public_cert) IO.inspect(validity) # => ~U[2025-09-01 12:00:00Z] IO.inspect(length(certs)) # => 2 (leaf cert + intermediate) ``` ``` -------------------------------- ### Detect IP Address with CertMagex.ip?/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Use CertMagex.ip?/1 to determine if a string is a valid IPv4 or IPv6 address. This is useful for selecting the correct ACME identifier type and gating IP certificate support. ```elixir CertMagex.ip?("192.168.1.1") # => true CertMagex.ip?("::1") # => true CertMagex.ip?("2001:db8::1") # => true CertMagex.ip?("example.com") # => false CertMagex.ip?("sub.example.com") # => false ``` -------------------------------- ### CertMagex.ip?/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Detects whether a given string is a valid IPv4 or IPv6 address. Returns `true` for IP addresses and `false` for domain names. This is useful for determining the correct ACME identifier type. ```APIDOC ## `CertMagex.ip?/1` — Detect whether a string is an IP address Returns `true` for valid IPv4 or IPv6 address strings, `false` for domain names. Used internally to select the correct ACME identifier type (`"ip"` vs `"dns"`) and to gate IP certificate support to compatible providers. ### Usage ```elixir CertMagex.ip?("192.168.1.1") # => true CertMagex.ip?("::1") # => true CertMagex.ip?("2001:db8::1") # => true CertMagex.ip?("example.com") # => false CertMagex.ip?("sub.example.com") # => false ``` ``` -------------------------------- ### Check Certificate Renewal with CertMagex.Worker.needs_renewal/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Use CertMagex.Worker.needs_renewal/1 to check if a cached certificate requires renewal. It returns `true` if the remaining validity is less than the `renewal_threshold` or if no certificate exists. The threshold can be overridden globally. ```elixir result = CertMagex.Worker.lookup_domain("example.com") # => {{[<>], {:ECPrivateKey, <>}}, ~U[2025-09-01 12:00:00Z]} # => nil (not yet issued) CertMagex.Worker.needs_renewal(result) # => false (more than 1 day of validity remaining) # => true (within renewal window or nil) # Override the threshold globally: ``` -------------------------------- ### CertMagex.Worker.needs_renewal/1 Source: https://context7.com/dominicletz/certmagex/llms.txt Checks if a cached certificate requires renewal. It returns `true` if the certificate's remaining validity is less than the configured `renewal_threshold` (default 1 day), or if no certificate is currently cached (`nil`). ```APIDOC ## `CertMagex.Worker.needs_renewal/1` — Check if a cached certificate needs renewal Returns `true` if the cached certificate's remaining validity is less than `renewal_threshold` seconds (default 86_400 s / 1 day), or if no certificate exists (`nil`). ### Usage ```elixir result = CertMagex.Worker.lookup_domain("example.com") # => {{[<>], {:ECPrivateKey, <>}}, ~U[2025-09-01 12:00:00Z]} # => nil (not yet issued) CertMagex.Worker.needs_renewal(result) # => false (more than 1 day of validity remaining) # => true (within renewal window or nil) # Override the threshold globally: ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.