Production deployment now matches the host setup that already runs
neuronetz.ai / neuro-landing: the gateway sits behind the jwilder
nginx-proxy + acme-companion already on the host, instead of bundling
its own Caddy sidecar.
- docker-compose.yml: drop the Caddy service entirely. The gateway joins
an external `proxy` Docker network (the same one neuronetz-web /
neuronetz-www use) and advertises itself with VIRTUAL_HOST /
VIRTUAL_PORT / LETSENCRYPT_HOST / LETSENCRYPT_EMAIL. nginx-proxy
routes TLS-terminated traffic to it on the shared network;
acme-companion handles Let's Encrypt issuance + renewal for
api.neuronetz.ai automatically. NO host ports are published in this
compose file anywhere — gateway, postgres, redis, ollama all stay
unreachable from the host. Pinned container_names
(neuronetz-gateway / -postgres / -redis / -ollama) for stable
identification by nginx-proxy and ops scripts.
- .env.example: add GATEWAY_VIRTUAL_HOST + LETSENCRYPT_EMAIL; flip the
default GATEWAY_TRUSTED_PROXIES to `127.0.0.1,nginx-proxy`.
- docs/DEPLOYMENT.md: the canonical path is now jwilder-proxy.
Reorganized prerequisites + steps around it; documented adding HSTS
and the other security headers via the nginx-proxy custom-config
mechanism (/etc/nginx/vhost.d/<host>). The Caddy sidecar lives on as
a documented alternative for hosts without jwilder-proxy
(ops/caddy/Caddyfile.example is kept).
The Ollama-never-exposed non-negotiable is unchanged.
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).