Files
neuronetz-gateway/ops/systemd/neuronetz-gateway.service
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

59 lines
1.8 KiB
Desktop File

# neuronetz-gateway — systemd unit for non-Compose deployments.
#
# Assumes the project is installed into a virtualenv at /opt/neuronetz-gateway/venv
# (e.g. `uv venv /opt/neuronetz-gateway/venv && uv pip install ...`) and that
# configuration lives in /etc/neuronetz-gateway/gateway.env (same keys as
# .env.example). Postgres, Redis and Ollama are reached over the network/loopback
# per that env file — Ollama must remain bound to localhost / a private network
# and never be published publicly.
#
# Install:
# sudo cp neuronetz-gateway.service /etc/systemd/system/
# sudo systemctl daemon-reload
# sudo systemctl enable --now neuronetz-gateway
[Unit]
Description=neuronetz-gateway — secure API gateway in front of Ollama
Documentation=https://github.com/neuronetz/neuronetz-gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# Dedicated unprivileged service account (create with: useradd --system gateway).
User=gateway
Group=gateway
WorkingDirectory=/opt/neuronetz-gateway
EnvironmentFile=/etc/neuronetz-gateway/gateway.env
# Apply migrations before starting (idempotent; no-op when already at head).
ExecStartPre=/opt/neuronetz-gateway/venv/bin/alembic upgrade head
ExecStart=/opt/neuronetz-gateway/venv/bin/python -m neuronetz_gateway
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
# --- Hardening ---
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# Allow writing only where the app legitimately needs to (none by default).
ReadWritePaths=
[Install]
WantedBy=multi-user.target