Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
3.8 KiB
SECURITY — TLS via Caddy (automatic ACME, HTTP-01 / DNS-01)
Why Caddy: zero-config TLS. Caddy 2 auto-provisions certificates via Let's Encrypt / ZeroSSL on first request for a domain that resolves to it, auto-renews, and stores state under /var/lib/caddy/. Official docs: https://caddyserver.com/docs/automatic-https [VERIFIED 2026-04-21].
One-liner install (Debian/Ubuntu, official repo):
# Pinned to official Cloudsmith repo — NEVER `curl … | bash` a random domain.
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy
This installs the caddy systemd service owned by caddy:caddy. Never run Caddy as root — it uses CAP_NET_BIND_SERVICE ambient capability to bind low ports.
Minimal /etc/caddy/Caddyfile:
{
# Global options
email admin@example.com # ACME account contact (change!)
# auto_https disable_redirects # uncomment only if fronted by another TLS-terminating proxy
}
api.example.com {
encode zstd gzip
log {
output file /var/log/caddy/api.log {
roll_size 10mb
roll_keep 10
}
}
reverse_proxy 127.0.0.1:8080
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
caddy validate --config /etc/caddy/Caddyfile BEFORE systemctl reload caddy. Reload ≠ restart; reload is zero-downtime.
ACME challenge choice:
- HTTP-01 (default) — Caddy binds port 80, LE connects back, serves challenge. Requires: port 80 open to the internet, DNS pointing to the VM. Works for single-host public services.
- DNS-01 — Caddy writes a TXT record via DNS provider API, doesn't need port 80 open. Required for wildcard certs (
*.example.com) and for LAN-only hosts. Needs a DNS-provider plugin (e.g.caddy-dns/cloudflare) compiled into the binary — usexcaddy buildor the Cloudsmithcaddy-dns-*packages.
DNS-01 with Cloudflare (caddy-dns/cloudflare):
*.internal.example.com, internal.example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy 127.0.0.1:8080
}
CF_API_TOKEN — store in /etc/caddy/caddy.env (chmod 0640, caddy:caddy), load via systemd drop-in EnvironmentFile=. Never bake the token into the Caddyfile (RULE 0.8 — see domain-has-secrets.md).
CT log awareness: every LE cert is published to Certificate Transparency logs. Any subdomain you cert is publicly searchable via crt.sh. Use DNS-01 + wildcard for internal services whose names should not leak.
Firewall interop (see security-firewall-ufw.md): ufw allow 80,443/tcp is required for HTTP-01 and for public HTTPS. Do NOT open 80 if using DNS-01 exclusively and not redirecting HTTP→HTTPS publicly; skip the redirect with auto_https disable_redirects.
Hardening:
HSTSas shown above — 1 year, include subdomains. Addpreloadonly after submitting to the HSTS preload list.-Serverheader strip — removes Caddy version disclosure.- Rate limit via
caddy-ratelimitmodule (needsxcaddy buildwith the plugin) for per-IP throttling; otherwise rely on cloud/ufw layer.
Forbidden: running Caddy as root; embedding DNS/ACME API tokens in the Caddyfile; using tls internal (self-signed, ephemeral CA) for anything reachable from outside localhost; skipping caddy validate before reload; self-hosting ACME (step-ca is great, but needs its own runbook — out of scope here).