Skip to content

feat(deploy): optional Caddy TLS reverse-proxy compose layer#60

Merged
CryptoJones merged 1 commit into
masterfrom
feat/tls-reverse-proxy-compose
May 18, 2026
Merged

feat(deploy): optional Caddy TLS reverse-proxy compose layer#60
CryptoJones merged 1 commit into
masterfrom
feat/tls-reverse-proxy-compose

Conversation

@CryptoJones
Copy link
Copy Markdown
Owner

Summary

Adds opt-in docker-compose.tls.yml + caddy/Caddyfile so production deployments can terminate TLS without manual cert wrangling. Caddy handles ACME, redirect, HSTS, X-Forwarded-* headers, and gzip out of the box.

sudo docker compose -f docker-compose.yml -f docker-compose.tls.yml up -d

.env.example gets TLS_DOMAIN + TLS_EMAIL documented. README gets a "Behind TLS (production)" subsection.

For local TLS dev (HSTS, secure-cookie testing): set TLS_DOMAIN=localhost and Caddy uses its built-in self-signed CA — no ACME.

Test plan

  • docker compose -f docker-compose.yml -f docker-compose.tls.yml config validates clean
  • api rebinds off the host port when layered with tls.yml (verified in config output)
  • Live ACME bring-up against a real FQDN (not run — no test domain pointing at this host)

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

Production deployments now have a one-file overlay that puts Caddy
in front of the api:

  sudo docker compose -f docker-compose.yml -f docker-compose.tls.yml up -d

What Caddy handles automatically:
  - Let's Encrypt cert provisioning + renewal (ACME)
  - HTTP → HTTPS redirect on :80
  - HTTP/2 on :443 (and HTTP/3 via UDP :443)
  - X-Forwarded-{For,Proto,Host} headers, plus X-Real-IP
  - HSTS (Caddy default, max-age=31536000)
  - gzip compression
  - Structured access logs to stdout

The overlay rebinds the api service off the host port so Caddy is
the only thing reachable from outside the box — defense in depth
against accidentally exposing the api on the wrong interface.

Config is single-Caddyfile (caddy/Caddyfile) with two env vars:
  - TLS_DOMAIN (required) — FQDN, or 'localhost' for self-signed
    via Caddy's built-in CA (useful for local HSTS/cookie testing)
  - TLS_EMAIL (optional) — passed to Let's Encrypt for renewal
    notices

.env.example documents both. README gets a "Behind TLS (production)"
section + the bring-up one-liner.

Verified via \`docker compose -f docker-compose.yml -f
docker-compose.tls.yml config\` — the layered config parses
clean. Live ACME bring-up not done in this session (would need a
real FQDN pointing at this host).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@CryptoJones CryptoJones merged commit a0272b7 into master May 18, 2026
2 of 3 checks passed
@CryptoJones CryptoJones deleted the feat/tls-reverse-proxy-compose branch May 18, 2026 00:30
CryptoJones added a commit that referenced this pull request May 18, 2026
Continues the docs-sync pattern from #44 and #53. CHANGELOG
[Unreleased] now reflects:

  Added:
    - Sequelize associations (#54)
    - Integration test harness (#55)
    - Postman collection (#59)
    - TLS reverse-proxy compose (#60)
    - docker-compose.override.yml committed (#56)

  Fixed:
    - setup/TimeTracker.sql idempotency (#57) — removes the
      \`docker compose down -v\` workaround

  Docs:
    - Integration bring-up flow (#56, #58)
    - README sections for Testing and Behind TLS

Co-authored-by: Aaron K. Clark <akclark@thenetwerk.net>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant