Files
azionelab-v2/docs/adr/0003-optional-letsencrypt.md
T
2026-06-24 11:06:33 +02:00

3.4 KiB

ADR-0003: Optional Let's Encrypt termination for direct deployments

Date: 2026-06-24

Status: Accepted

Context

Azione!Lab may be deployed either behind a load balancer that already terminates TLS or directly on a public host. Running an ACME client unconditionally would duplicate edge responsibilities in the first topology, while direct exposure still needs automated certificate issuance and renewal.

Decision

Add an opt-in Certbot service controlled by LETSENCRYPT_ENABLED. Docker Compose gives that service zero replicas by default and one replica only when the value is 1. Certbot uses the HTTP-01 webroot method and shares separate challenge and certificate volumes with NGINX.

NGINX always serves the ACME challenge path over HTTP. When TLS is enabled but no certificate exists, application traffic remains available over HTTP. An entrypoint watcher detects certificate creation or renewal, renders the HTTPS virtual host, validates the configuration, reloads NGINX, and redirects non-ACME HTTP traffic to HTTPS. No Docker socket or container-control privilege is required.

The direct-deployment operator is responsible for public DNS, inbound ports 80 and 443, a valid contact email, and selecting the staging or production ACME endpoint. Behind a load balancer, Certbot stays disabled and the load balancer owns certificates.

Consequences

  • One Compose definition supports both deployment topologies.
  • Direct deployments gain automated issue and renewal without manual certificate copy.
  • The first direct request can use HTTP until issuance completes; operators must not publish sensitive workflows before TLS has been verified.
  • Certificate and challenge volumes add persistent operational state.
  • HTTP-01 cannot issue when port 80 or DNS is controlled by another edge.

Alternatives considered

  • Always running Certbot was rejected because it conflicts with load-balancer-managed certificates and creates unnecessary ACME traffic.
  • Separate Compose files per topology were rejected as avoidable configuration drift for this small stack.
  • Giving Certbot access to the Docker socket to reload NGINX was rejected because that privilege is disproportionate; NGINX can safely watch its read-only certificate volume.
  • DNS-01 was not selected because it requires provider-specific credentials and dependencies. It remains a future option for wildcard certificates or closed port 80.

Security impact

The certificate private key is writable only by Certbot and read-only to NGINX. Certbot uses a read-only root filesystem, temporary runtime mounts, no-new-privileges, and no Docker socket. Production must restrict application ports and the proxy trust boundary; Django accepts the secure forwarded-protocol header for load-balancer deployments.

Operational impact

Operators must monitor both Certbot issue/renew logs and NGINX reload logs, protect the certificate volume, and test DNS/firewall changes with the staging CA. Renewals are checked every 12 hours and NGINX detects certificate changes every 30 seconds by default. These intervals are configurable.

Rollback

Set LETSENCRYPT_ENABLED=0 and recreate the stack to stop Certbot while retaining certificate state. Terminate TLS at a load balancer if public service must continue. The certificate volumes can be removed only after confirming they are no longer needed; database and media volumes are independent.