Files
neuronetz-gateway/ops/caddy/Caddyfile.example
Stephan Berbig d79f17b3bb scaffold: project skeleton, schema, healthz/readyz, CI
Initial project structure for neuronetz-gateway per scope-docs/SPEC.md:

- Python 3.12 / FastAPI / SQLAlchemy 2.0 (async) / Redis / Postgres stack
  managed by uv. Multi-stage non-root Dockerfile, prod + dev compose files
  (ollama service is NEVER published in either), Caddyfile + systemd unit,
  justfile, GitHub Actions CI (ruff, mypy --strict, pytest, bandit, pip-audit).
- Pydantic-Settings config covering every env var from SPEC §7, including the
  MODEL_DISCOVERY_* keys for the dynamic-discovery feature (§4.6).
- Alembic 0001_initial creates the full gateway schema (8 tables, 3 enums,
  notify_key_revoked() trigger), incl. allow_all_models on tenant_limits and
  key_limits for the per-tenant auto-grant toggle.
- Working /healthz, /readyz (fail-closed when deps unreachable), and a
  Prometheus /metrics stub. Sanitizing error handlers that attach X-Request-ID
  to every response and never leak upstream internals.
- SPEC + AGENT_PROMPT included under scope-docs/ (source of truth).
2026-05-26 20:50:35 +02:00

60 lines
2.4 KiB
Caddyfile

# neuronetz-gateway — Caddy reverse proxy (SPEC §4.1, §6.5).
#
# Caddy is the only public-facing component. It terminates TLS (HTTP/2 + HTTP/3),
# obtains a Let's Encrypt certificate for api.neuronetz.ai automatically, applies
# security headers, and reverse-proxies to the internal-only gateway:8080.
#
# Copy this file to `Caddyfile` and edit the site address / admin email.
# The production docker-compose.yml mounts it at /etc/caddy/Caddyfile.
{
# Email for Let's Encrypt account + expiry notices. Replace before deploy.
email ops@neuronetz.ai
}
api.neuronetz.ai {
# --- Reverse proxy to the internal gateway ---
# `gateway` is the Docker service name on the internal network; it is never
# published to the host. Caddy forwards plain HTTP/1.1 to it.
reverse_proxy gateway:8080
# --- Security headers ---
header {
# HSTS: force HTTPS for two years, include subdomains, allow preload.
Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Disable MIME sniffing.
X-Content-Type-Options "nosniff"
# Clickjacking defense (API has no UI, deny framing outright).
X-Frame-Options "DENY"
# Conservative referrer policy.
Referrer-Policy "no-referrer"
# Strip server-identifying headers so we don't advertise the stack.
-Server
-X-Powered-By
}
# Structured access logs to stdout (collected by the container runtime).
log {
output stdout
format json
}
}
# ─────────────────────────────────────────────────────────────────────────────
# DEV / LOCAL note:
#
# For local testing without a public domain or real certificate, replace the
# site block above with a localhost block that uses Caddy's internal self-signed
# CA (no Let's Encrypt round-trip):
#
# localhost {
# tls internal
# reverse_proxy gateway:8080
# }
#
# Caddy will install its local root CA; trust it or pass `-k` to curl. Note the
# Phase 1 *dev* compose stack (docker-compose.dev.yml) ships WITHOUT Caddy and
# exposes the gateway directly on localhost:8080 — this file is for the full
# production stack only.
# ─────────────────────────────────────────────────────────────────────────────