Configuration Reference

Complete reference for all YAML configuration sections

ACMEEH uses a single YAML configuration file validated against a JSON Schema. The file is loaded via ConfigKit, which provides schema validation, environment variable substitution, and typed access.

Environment Variables

Use ${VAR} or ${VAR:-default} syntax anywhere in the YAML to reference environment variables:

database:
  password: ${DB_PASSWORD}
  host: ${DB_HOST:-localhost}

Variables are resolved during config loading in additional_checks(). If a variable is missing and has no default, config loading fails with a clear error.

Tip

Inline Comments

Add a _comment field (string or array of strings) at the top level of your YAML for in-file documentation. It is ignored by the server.

Settings Sections

The configuration tree has 27 top-level sections. Only server.external_url, database.database, and database.user are required — everything else has sensible defaults.

server

HTTP server settings for both development and gunicorn production modes.

Field

Type

Default

Description

external_url

string

required

Public-facing URL of the server (used in ACME directory)

bind

string

0.0.0.0

Address to bind to

port

integer

8443

Port to listen on

workers

integer

4

Number of gunicorn workers

worker_class

string

sync

Gunicorn worker class

timeout

integer

30

Worker timeout in seconds

graceful_timeout

integer

30

Graceful shutdown timeout

keepalive

integer

2

Keep-alive timeout

max_requests

integer

0

Max requests before worker restart (0 = disabled)

max_requests_jitter

integer

0

Random jitter added to max_requests

proxy

Reverse proxy configuration for extracting real client IP and protocol.

Field

Type

Default

Description

enabled

boolean

false

Enable reverse proxy support

trusted_proxies

string[]

[]

List of trusted proxy IP addresses/ranges

forwarded_for_header

string

X-Forwarded-For

Header containing real client IP

forwarded_proto_header

string

X-Forwarded-Proto

Header containing original protocol

Note

X-Forwarded-Prefix

The middleware also handles X-Forwarded-Prefix automatically (not configurable). When present on a trusted request, its value is used as the WSGI SCRIPT_NAME to support reverse proxies that mount ACMEEH under a sub-path.

security

Cryptographic policies, rate limiting, and identifier restrictions.

Field

Type

Default

Description

allowed_algorithms

string[]

[ES256, RS256]

Allowed JWS signing algorithms

min_rsa_key_size

integer

2048

Minimum RSA key size for account keys

max_rsa_key_size

integer

8192

Maximum RSA key size

allowed_ec_curves

string[]

[P-256, P-384]

Allowed EC curves for account keys

max_request_body_bytes

integer

65536

Maximum request body size

allowed_csr_signature_algorithms

string[]

[SHA256withRSA, ...]

Allowed CSR signature algorithms

min_csr_rsa_key_size

integer

2048

Minimum RSA key size in CSRs

min_csr_ec_key_size

integer

256

Minimum EC key size in CSRs

hsts_max_age_seconds

integer

63072000

HSTS header max-age in seconds

require_csr_profile

boolean

false

Require every account to have a CSR profile assigned before certificate finalization. See CSR Profile Enforcement.

security.rate_limits

Field

Type

Default

Description

enabled

boolean

true

Enable rate limiting

backend

string

memory

Rate limit storage backend

new_nonce

object

100/60s

Nonce endpoint rate limit

new_account

object

10/3600s

Account creation rate limit

new_order

object

300/3600s

Order creation rate limit

new_order_per_identifier

object

50/604800s

Per-identifier order rate limit

challenge

object

60/60s

Challenge response rate limit

challenge_validation

object

30/60s

Challenge validation rate limit

gc_interval_seconds

integer

300

Rate limit GC interval

gc_max_age_seconds

integer

7200

Max age for rate limit entries

Each rate limit rule has requests (count) and window_seconds (time window).

security.identifier_policy

Field

Type

Default

Description

allowed_domains

string[]

[]

Allowlist of domain suffixes (empty = allow all)

forbidden_domains

string[]

[]

Blocklist of domain suffixes

allow_wildcards

boolean

true

Allow wildcard identifiers

allow_ip

boolean

false

Allow IP address identifiers

max_identifiers_per_order

integer

100

Maximum identifiers per order

max_identifier_value_length

integer

253

Maximum identifier string length

enforce_account_allowlist

boolean

false

Enforce per-account allowed identifiers

acme

ACME protocol settings including URL paths and policy.

Field

Type

Default

Description

website_url

string

null

URL for terms of service / website

caa_identities

string[]

[]

CAA record identities for validation

eab_required

boolean

false

Require External Account Binding

eab_reusable

boolean

false

Allow EAB credentials to be reused across multiple accounts

caa_enforce

boolean

true

Enforce CAA DNS record checks

orders_page_size

integer

50

Number of orders per page in account orders list

acme.paths

Field

Type

Default

Description

directory

string

/directory

Directory endpoint path

new_nonce

string

/new-nonce

New nonce endpoint path

new_account

string

/new-account

New account endpoint path

new_order

string

/new-order

New order endpoint path

new_authz

string

/new-authz

Pre-authorization endpoint path

revoke_cert

string

/revoke-cert

Certificate revocation endpoint path

key_change

string

/key-change

Key change endpoint path

api

Field

Type

Default

Description

base_path

string

""

Base URL path prefix for all ACME endpoints

challenges

Challenge validation configuration.

Field

Type

Default

Description

enabled

string[]

[http-01]

Enabled challenge types: http-01, dns-01, tls-alpn-01

auto_accept

boolean

false

Automatically accept all challenges without validation

retry_after_seconds

integer

3

Retry-After header value for pending challenges

backoff_base_seconds

integer

5

Base delay for exponential backoff on retries

backoff_max_seconds

integer

300

Maximum backoff delay

challenges.http01

Field

Type

Default

Description

port

integer

80

Port to connect to for HTTP-01 validation

timeout_seconds

integer

10

Connection timeout

max_retries

integer

3

Maximum validation retries

auto_validate

boolean

true

Auto-validate this challenge type

blocked_networks

string[]

[127.0.0.0/8, ...]

Networks blocked from validation (SSRF protection)

max_response_bytes

integer

1048576

Maximum response body size for HTTP-01 validation (1 MB)

challenges.dns01

Field

Type

Default

Description

resolvers

string[]

[]

DNS resolver addresses (empty = system default)

timeout_seconds

integer

30

DNS query timeout

propagation_wait_seconds

integer

10

Wait time for DNS propagation

max_retries

integer

5

Maximum validation retries

auto_validate

boolean

false

Auto-validate this challenge type

require_dnssec

boolean

false

Require DNSSEC validation

require_authoritative

boolean

false

Require response from authoritative nameserver

challenges.tlsalpn01

Field

Type

Default

Description

port

integer

443

Port for TLS-ALPN-01 validation

timeout_seconds

integer

10

Connection timeout

max_retries

integer

3

Maximum validation retries

auto_validate

boolean

true

Auto-validate this challenge type

challenges.background_worker

Field

Type

Default

Description

enabled

boolean

false

Enable background challenge worker

poll_seconds

integer

10

Polling interval

stale_seconds

integer

300

Threshold for stale challenges

ca

Certificate Authority settings. See CA Backends for detailed backend configuration.

Field

Type

Default

Description

backend

string

internal

CA backend: internal, external, hsm, acme_proxy, or ext:pkg.mod.Class

default_validity_days

integer

90

Default certificate validity

max_validity_days

integer

397

Maximum certificate validity

circuit_breaker_failure_threshold

integer

5

Failures before circuit opens

circuit_breaker_recovery_timeout

float

30

Seconds before circuit half-opens

deferred_signing_timeout

integer

600

Timeout in seconds for deferred (background thread) signing. Used by backends where deferred=True (e.g., acme_proxy).

ca.profiles

Named certificate profiles. A default profile is always present. Each profile supports:

Field

Type

Default

Description

key_usages

array

[]

Key Usage extension values (e.g., digital_signature, key_encipherment)

extended_key_usages

array

[]

Extended Key Usage values (e.g., server_auth, client_auth)

validity_days

integer

null

Override ca.default_validity_days for this profile

max_validity_days

integer

null

Override ca.max_validity_days for this profile

Example:

ca:
  profiles:
    default:
      key_usages: [digital_signature, key_encipherment]
      extended_key_usages: [server_auth]
    client:
      key_usages: [digital_signature]
      extended_key_usages: [client_auth]
      validity_days: 365
      max_validity_days: 730

database

PostgreSQL connection settings.

Field

Type

Default

Description

host

string

localhost

Database hostname

port

integer

5432

Database port

database

string

required

Database name

user

string

required

Database user

password

string

""

Database password

sslmode

string

prefer

PostgreSQL SSL mode

min_connections

integer

5

Minimum pool connections

max_connections

integer

50

Maximum pool connections

connection_timeout

float

10.0

Connection timeout in seconds

max_idle_seconds

float

300.0

Maximum time (seconds) a connection can remain idle in the pool before being closed

auto_setup

boolean

false

Automatically create tables on startup

dns

Field

Type

Default

Description

resolvers

string[]

[]

DNS resolver addresses

timeout_seconds

integer

10

DNS query timeout

retries

integer

3

DNS query retries

email

Field

Type

Default

Description

require_contact

boolean

false

Require email contact on accounts

allowed_domains

string[]

[]

Allowed email domains (empty = any)

validate_mx

boolean

false

Validate MX records for email domain

account

Account modification and lifecycle policy settings.

Field

Type

Default

Description

allow_contact_update

boolean

true

Allow accounts to update their contact information

allow_deactivation

boolean

true

Allow accounts to self-deactivate

smtp

Field

Type

Default

Description

enabled

boolean

false

Enable SMTP for notifications

host

string

""

SMTP server hostname

port

integer

587

SMTP server port

username

string

""

SMTP username

password

string

""

SMTP password

use_tls

boolean

true

Use STARTTLS

from_address

string

""

Sender email address

cc

list[string]

[]

CC recipients added to every outgoing notification

bcc

list[string]

[]

BCC recipients added to every outgoing notification (envelope only, not in headers)

templates_path

string

null

Custom Jinja2 templates directory

timeout_seconds

integer

30

SMTP operation timeout

logging

Field

Type

Default

Description

level

string

INFO

Log level: DEBUG, INFO, WARNING, ERROR

format

string

json

Log format: json or human

logging.audit

Field

Type

Default

Description

enabled

boolean

true

Enable audit logging

file

string

null

Audit log file path

syslog

boolean

false

Send audit logs to syslog

max_file_size_bytes

integer

104857600

Maximum audit log file size before rotation (100 MB)

backup_count

integer

10

Number of rotated audit log backups to keep

notifications

Field

Type

Default

Description

enabled

boolean

true

Enable notification system

max_retries

integer

3

Max delivery retries

retry_delay_seconds

integer

60

Initial retry delay

batch_size

integer

50

Notifications per batch

retry_interval_seconds

integer

300

Retry worker interval

expiration_warning_days

integer[]

[30, 14, 7, 1]

Days before expiry to warn

expiration_check_interval_seconds

integer

3600

Expiration check interval

retry_backoff_multiplier

float

2.0

Exponential backoff multiplier

retry_max_delay_seconds

integer

3600

Maximum retry delay

disabled_types

string[]

[]

Notification types to suppress. Valid values: delivery_succeeded, delivery_failed, revocation_succeeded, revocation_failed, registration_succeeded, registration_failed, admin_user_created, admin_password_reset, expiration_warning, order_rejected, challenge_failed, csr_validation_failed, order_stale_recovered, account_deactivated, key_rollover_succeeded, order_quota_exceeded, authorization_deactivated

hooks

Lifecycle hook configuration. See Hook System in the Development guide for writing custom hooks.

Field

Type

Default

Description

timeout_seconds

integer

30

Default hook execution timeout

max_workers

integer

4

Thread pool size for hook execution

max_retries

integer

0

Default retry count on failure

dead_letter_log

string

null

File path for failed hook payloads

hooks.registered[]

See Extensibility for the full list of hook events, configuration fields, and a complete YAML example.

nonce

Field

Type

Default

Description

expiry_seconds

integer

3600

Nonce expiry time

gc_interval_seconds

integer

300

Garbage collection interval

length

integer

32

Nonce byte length

audit_consumed

boolean

false

Log consumed nonces in audit trail

max_age_seconds

integer

min(expiry_seconds, 300)

Max age for nonce reuse. Defaults to the lesser of expiry_seconds and 300.

order

Field

Type

Default

Description

expiry_seconds

integer

604800

Order expiry (7 days)

authorization_expiry_seconds

integer

2592000

Authorization expiry (30 days)

cleanup_interval_seconds

integer

3600

Expired order cleanup interval

stale_processing_threshold_seconds

integer

600

Threshold for stale processing orders

pre_authorization_lifetime_days

integer

30

Pre-authorization validity

retry_after_seconds

integer

3

Retry-After for processing orders

quotas

Field

Type

Default

Description

enabled

boolean

false

Enable per-account quotas

max_certificates_per_account_per_day

integer

0

Daily cert limit (0 = unlimited)

max_orders_per_account_per_day

integer

0

Daily order limit (0 = unlimited)

tos

Field

Type

Default

Description

url

string

null

Terms of Service URL

require_agreement

boolean

false

Require TOS agreement for account creation

admin_api

See Admin API for endpoint documentation.

Field

Type

Default

Description

enabled

boolean

false

Enable admin REST API

base_path

string

/api

Admin API base path

token_secret

string

""

JWT signing secret

token_expiry_seconds

integer

3600

Token validity period

initial_admin_email

string

""

Email for auto-created initial admin

password_length

integer

20

Generated password length

default_page_size

integer

50

Default pagination size

max_page_size

integer

1000

Maximum pagination size

crl

Field

Type

Default

Description

enabled

boolean

false

Enable CRL distribution point

path

string

/crl

CRL endpoint path

rebuild_interval_seconds

integer

3600

Automatic rebuild interval

next_update_seconds

integer

86400

Next Update field in CRL

hash_algorithm

string

sha256

CRL signing hash algorithm

metrics

Field

Type

Default

Description

enabled

boolean

false

Enable Prometheus metrics endpoint

path

string

/metrics

Metrics endpoint path

auth_required

boolean

false

Require authentication for metrics

ct_logging

Certificate Transparency log submission.

Field

Type

Default

Description

enabled

boolean

false

Enable CT log submission

submit_precert

boolean

false

Submit pre-certificates

ct_logging.logs[]

Each entry in the logs array defines a Certificate Transparency log to submit to:

ct_logging:
  enabled: true
  logs:
    - url: https://ct.example.com/log
      public_key_path: /path/to/ct-log-key.pem
      timeout_seconds: 10

Field

Type

Default

Description

url

string

required

CT log submission URL

public_key_path

string

null

Path to the CT log’s public key (PEM). Used for SCT verification.

timeout_seconds

integer

10

HTTP request timeout for CT log submission

audit_retention

Field

Type

Default

Description

enabled

boolean

false

Enable audit log cleanup

max_age_days

integer

90

Maximum audit log age

cleanup_interval_seconds

integer

86400

Cleanup interval

ari

ACME Renewal Information (draft-ietf-acme-ari).

Field

Type

Default

Description

enabled

boolean

false

Enable ARI endpoint

renewal_percentage

float

0.6667

Suggested renewal point (fraction of validity)

path

string

/renewalInfo

ARI endpoint path

audit_export

Field

Type

Default

Description

webhook_url

string

null

Webhook URL for audit event export

syslog_host

string

null

Syslog server hostname

syslog_port

integer

514

Syslog server port

retention

Data retention policies for automatic cleanup of expired/invalid resources.

Field

Type

Default

Description

enabled

boolean

true

Enable data retention cleanup

invalid_order_max_age_days

integer

30

Max age for invalid orders

expired_authz_max_age_days

integer

30

Max age for expired authorizations

invalid_challenge_max_age_days

integer

30

Max age for invalid challenges

expiration_notice_max_age_days

integer

90

Max age for expiration notices

cleanup_interval_seconds

integer

86400

Cleanup worker interval

cleanup_loop_interval_seconds

integer

60

Internal cleanup loop sleep interval

Cross-Field Validation Rules

ACMEEH performs cross-field validation during config loading. Errors prevent startup; warnings are logged but non-fatal.

Errors (prevent startup)

Condition

Message

server.external_url ends with /

External URL must not end with a slash

ca.backend=internal without root_cert_path or root_key_path

Required paths for internal CA backend

ca.backend=acme_proxy without directory_url, email, or challenge_handler

Required fields for ACME proxy backend

ca.backend=hsm without pkcs11_library, token identifier, key identifier, or issuer_cert_path

Required fields for HSM backend

ca.backend=hsm with login_required=true but no pin

PIN required when login is required

ca.default_validity_days > ca.max_validity_days

Default validity must not exceed maximum

database.min_connections > database.max_connections

Min connections must not exceed max

challenges.backoff_base_seconds > challenges.backoff_max_seconds

Backoff base must not exceed max

smtp.enabled=true without host or from_address

SMTP host and from_address required when enabled

tos.require_agreement=true without tos.url

TOS URL required when agreement is required

proxy.enabled=true with empty trusted_proxies

Trusted proxies must be specified when enabled

admin_api.enabled=true without token_secret (min 16 chars) or initial_admin_email

Token secret and initial admin email required

admin_api.base_path collides with api.base_path

Admin and ACME paths must not overlap

ct_logging.enabled=true with empty logs array

At least one CT log required when enabled

nonce.length < 16

Minimum 16 bytes for cryptographic safety

security.min_rsa_key_size < 2048

Minimum RSA key size is 2048 bits

Unknown hook event name in hooks.registered[].events

Event must be a known lifecycle event

Invalid hook class path format

Must be a valid dotted Python path (e.g., pkg.mod.Class)

Warnings (logged, non-fatal)

Condition

Message

notifications.enabled=true but smtp.enabled=false

Notifications will be recorded but not sent via email

admin_api.enabled=true but smtp.enabled=false

Generated passwords will only be printed to stdout/log

security.identifier_policy.enforce_account_allowlist=true but admin_api.enabled=false

Cannot manage allowlists without admin API

security.require_csr_profile=true but admin_api.enabled=false

CSR profiles cannot be managed without admin API

acme.eab_reusable=true but acme.eab_required=false

EAB reusability has no effect when EAB is not required

security.rate_limits.backend=memory with server.workers > 1

In-memory rate limits are per-process, not shared across workers

database.max_connections < server.workers x 2 + 5

Connection pool may be too small for configured workers

email.validate_mx=true with empty dns.resolvers

MX validation will use system DNS resolvers

quotas.enabled=true with both limits set to 0

Quotas are enabled but have no effect

0 < security.hsts_max_age_seconds < 86400

HSTS max-age less than 1 day is not recommended

crl.enabled=true with non-internal CA backend

CRL generation requires access to the CA signing key

Hook timeout_seconds > server.timeout

Hook execution may outlive the HTTP request

CSR Profile Enforcement

When security.require_csr_profile is true, every ACME account must have a CSR profile assigned before it can finalize an order. If an account has no profile, the finalize request is rejected with a badCSR error.

This pairs naturally with EAB-based enrollment: assign a CSR profile to each EAB credential, and when a client registers using that credential, the profile is automatically copied to the new account.

Recommended setup:

acme:
  eab_required: true

security:
  require_csr_profile: true

admin_api:
  enabled: true
  token_secret: ${ADMIN_TOKEN_SECRET}
  initial_admin_email: admin@example.com
  base_path: /admin

Workflow:

  1. An admin creates a CSR profile via POST /admin/csr-profiles

  2. The admin assigns it to an EAB credential via PUT /admin/eab/{eab_id}/csr-profile/{profile_id}

  3. A client registers with the EAB credential — the profile is copied to the new account

  4. All certificate orders from that account are validated against the profile

Accounts without a profile receive a badCSR error at finalization with the detail “No CSR profile assigned to this account”.

Note

The admin_api.enabled option must be true for CSR profile management. If require_csr_profile is true but the admin API is disabled, a configuration warning is logged at startup and all finalization requests will fail.

Full Configuration Example

A comprehensive configuration file showing all commonly used sections:

# ACMEEH Configuration --- Full Example

server:
  external_url: https://acme.example.com
  bind: 0.0.0.0
  port: 8443
  workers: 8
  timeout: 30
  max_requests: 1000
  max_requests_jitter: 50

proxy:
  enabled: true
  trusted_proxies:
    - 10.0.0.0/8
    - 172.16.0.0/12

database:
  host: ${DB_HOST:-localhost}
  port: 5432
  database: acmeeh
  user: acmeeh
  password: ${DB_PASSWORD}
  sslmode: require
  max_connections: 20
  auto_setup: true

ca:
  backend: internal
  default_validity_days: 90
  max_validity_days: 397
  internal:
    root_cert_path: /etc/acmeeh/ca/root-ca.pem
    root_key_path: /etc/acmeeh/ca/root-ca-key.pem
  profiles:
    default:
      key_usages: [digital_signature, key_encipherment]
      extended_key_usages: [server_auth]
    client:
      key_usages: [digital_signature]
      extended_key_usages: [client_auth]
      validity_days: 365

challenges:
  enabled:
    - http-01
    - dns-01
  dns01:
    resolvers:
      - 8.8.8.8
      - 8.8.4.4
    propagation_wait_seconds: 30

security:
  allowed_algorithms: [ES256, RS256]
  rate_limits:
    enabled: true
  identifier_policy:
    allowed_domains:
      - .example.com
      - .internal.corp
    allow_wildcards: true

acme:
  eab_required: true
  caa_enforce: true
  caa_identities:
    - acme.example.com

tos:
  url: https://example.com/tos
  require_agreement: true

admin_api:
  enabled: true
  token_secret: ${ADMIN_TOKEN_SECRET}
  initial_admin_email: admin@example.com

smtp:
  enabled: true
  host: smtp.example.com
  port: 587
  username: ${SMTP_USER}
  password: ${SMTP_PASSWORD}
  from_address: acmeeh@example.com
  cc: []
  bcc: []

notifications:
  enabled: true
  expiration_warning_days: [30, 14, 7, 1]

logging:
  level: INFO
  format: json
  audit:
    enabled: true
    file: /var/log/acmeeh/audit.log

crl:
  enabled: true

metrics:
  enabled: true