Files
infosave2007 057abaa95a feat!: API keys actually gate the gateway — auth, attribution, rate limits, budgets
The office-readiness audit found the foundation missing: configured API keys
were decorative. Any bearer — or none — passed every model endpoint, per-key
rate limits existed only in the form, and all real traffic was recorded as
"anonymous", leaving the per-key spend table permanently blank.

A middleware on the model surface (/v1/*, /route, /mcp) now enforces keys:
- no keys configured → open mode as before (the console already warns);
- keys exist → Bearer or x-api-key must match (401 invalid_api_key);
- per-key rate_per_min → fixed one-minute window, 429 with Retry-After;
- NEW per-key monthly_budget_usd → 429 insufficient_quota once the account's
  month-to-date spend crosses the ceiling;
- the matched account rides the request into stats — the keys table's spend
  columns finally see real traffic.

Month-to-date spend is tracked per account in stats and persisted in the
totals sidecar with a watermark (no double counting across restarts). The
key dialog gains a budget field; the table shows "budget $N/mo" in red once
exhausted. All verified live: 401 wrong/missing key, 200 + attribution with
the right key, 429 + Retry-After over the limit, 429 insufficient_quota on
the second request past a $0.000001 budget.

Also: the dashboard shows the OpenRouter credit balance (GET
/api/v1/credits via the stored key, cached 5 min, hidden without a key, red
under $5 — live: $16.18), the server drains connections on Ctrl-C instead
of dropping them, request bodies are capped at 32 MB, and docs/DEPLOY(.ru)
cover office deployment: systemd/launchd/Windows service, nginx/caddy TLS,
security checklist, backups. 10 strings ×7 languages.
2026-08-08 14:01:16 +03:00

123 lines
3.6 KiB
Markdown

# Deploying cortiq-gateway for a team / office
One gateway on a small server, API keys per department, local models for the
cheap tiers, cloud models for the hard ones. This page covers the ops side.
## 1. Run as a service
### Linux (systemd)
```ini
# /etc/systemd/system/cortiq-gateway.service
[Unit]
Description=Cortiq Gateway
After=network-online.target
[Service]
User=cortiq
Environment=CORTIQ_GATEWAY_HOME=/var/lib/cortiq-gateway
ExecStart=/usr/local/bin/cortiq-gateway --no-port-search
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
```
```bash
sudo systemctl enable --now cortiq-gateway
```
### macOS (launchd)
```xml
<!-- ~/Library/LaunchAgents/com.cortiq.gateway.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>com.cortiq.gateway</string>
<key>ProgramArguments</key><array>
<string>/usr/local/bin/cortiq-gateway</string>
<string>--no-port-search</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict></plist>
```
```bash
launchctl load ~/Library/LaunchAgents/com.cortiq.gateway.plist
```
### Windows
Task Scheduler → Create Task → "Run whether user is logged on or not",
trigger At startup, action `cortiq-gateway.exe --no-port-search`. Or use
[NSSM](https://nssm.cc): `nssm install cortiq-gateway C:\bin\cortiq-gateway.exe`.
### Docker
```bash
docker run -d --restart unless-stopped -p 9000:9000 \
-v cortiq-data:/data ghcr.io/infosave2007/cortiq-gateway:latest
```
## 2. TLS and the outside world
The gateway itself speaks plain HTTP — put a reverse proxy with TLS in front
and bind the gateway to localhost:
```toml
# gateway.toml
listen = "127.0.0.1:9000"
```
```nginx
server {
listen 443 ssl;
server_name ai.example.com;
ssl_certificate /etc/letsencrypt/live/ai.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ai.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_http_version 1.1;
proxy_buffering off; # SSE streaming
proxy_read_timeout 3600s; # long generations
}
}
```
(`caddy reverse-proxy --from ai.example.com --to 127.0.0.1:9000` does the
same with automatic certificates.)
## 3. Security checklist
- **Admin token**: set `[admin] token` (or `CORTIQ_ADMIN_TOKEN`) — without it
the console warns that it is open to the network.
- **API keys**: create one per department/developer on the keys page. With at
least one key configured the model APIs require Bearer / x-api-key —
requests without a valid key get 401.
- **Rate limits**: per-key requests/min → 429 with Retry-After.
- **Monthly budgets**: per-key $ ceiling → 429 insufficient_quota when the
account's month-to-date spend crosses it.
- Bind to 127.0.0.1 behind the proxy; never expose the admin console raw.
## 4. Backups
Everything lives under the data directory (`CORTIQ_GATEWAY_HOME`):
- `gateway.toml` — full config incl. keys (or use the console's TOML export);
- `secrets.toml` — provider API keys (chmod 600);
- `stats.jsonl` + `stats.jsonl.totals.json` — request accounting incl.
cumulative per-key totals and month-to-date budget spend.
Copy those three and you can rebuild the instance anywhere.
## 5. Observability
- Dashboard: KPIs, per-key spend, recent requests with complexity scores,
OpenRouter balance (red under $5).
- `GET /metrics` (enable `[telemetry] metrics = true`) for Prometheus.
- Logs view in the console; `stats.max_file_mb` keeps the disk bounded.