Ollama Proxy mit API-Keys und Quotas

Ein Reverse-Proxy für Ollama mit API-Key-Authentifizierung, Quota-Management und Web-Admin-Oberfläche.

Features

  • API-Key-Authentifizierung (Bearer Token oder sk--Prefix)
  • Optionales Ablaufdatum pro API-Key
  • Quota-Management mit getrennten Tages- und Monatslimits (Tokens & Requests)
  • Token-Zählung via tiktoken, Reset-Grenzen in der Zeitzone Europe/Berlin
  • Web-Admin-Oberfläche (API-Keys verwalten, Ollama-Einstellungen, Proxy-Info)
  • OpenAI-kompatibler /v1/chat/completions-Endpunkt

Sicherheit

  • Admin-Oberfläche passwortgeschützt (ADMIN_PASSWORD)
  • Admin-API bindet lokal auf 127.0.0.1 (nicht von außen erreichbar)
  • API-Keys als SHA-256-Hash in der DB — Plaintext nur einmalig bei Erstellung
  • Quota-Check atomar mit SELECT FOR UPDATE (kein TOCTOU-Race)
  • CORS-Origins konfigurierbar via ALLOWED_ORIGINS

Konfiguration

.env-Datei im Projektverzeichnis anlegen (Vorlage: .env.example):

ADMIN_PASSWORD=change-me
PROXY_HOST=0.0.0.0
PROXY_PORT=8000
ADMIN_PORT=8001
DATABASE_URL=sqlite:///./test.db
OLLAMA_URL=http://localhost:11434
DEFAULT_MODEL=llama3
APP_TZ=Europe/Berlin
Variable Standard Beschreibung
ADMIN_PASSWORD Passwort für die Admin-Oberfläche (Pflicht)
PROXY_HOST 0.0.0.0 Bind-Adresse des Proxys
PROXY_PORT 8000 Port des Proxys
ADMIN_PORT 8001 Port der Admin-API
DATABASE_URL sqlite:///./test.db DB-Verbindungsstring
OLLAMA_URL http://localhost:11434 Adresse der Ollama-Instanz (auch in der UI änderbar)
DEFAULT_MODEL llama3 Standard-Modell für /v1/chat/completions (auch in der UI änderbar)
APP_TZ Europe/Berlin Zeitzone für tägliche/monatliche Quota-Resets
ALLOWED_ORIGINS http://localhost:5173 Kommagetrennte CORS-Origins

Entwicklung (lokal)

cp .env.example .env
# ADMIN_PASSWORD in .env setzen

./start.sh

Das Script prüft alle Ports auf Belegung, aktiviert automatisch eine vorhandene .venv, initialisiert die Datenbank und startet Proxy, Admin-API und Vite-Dev-Server.

Admin-Oberfläche: http://localhost:5173

Voraussetzungen

  • Python 3.12+ mit virtualenv
  • Node.js 18+
python -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements-dev.txt

cd frontend && npm install

Produktion (Docker)

Image bauen

docker build -t llm-quota .

Container starten

docker run -d \
  -p 8000:8000 \
  -p 127.0.0.1:8001:8001 \
  -e ADMIN_PASSWORD=geheim \
  -e OLLAMA_URL=http://host.docker.internal:11434 \
  -e DATABASE_URL=sqlite:///./data/quota.db \
  -v $(pwd)/data:/app/backend/data \
  --name llm-quota \
  llm-quota
Port Bindung Dienst
8000 0.0.0.0 — öffentlich Proxy (für LLM-Clients)
8001 127.0.0.1 — nur lokal am Server Admin-API + Admin-Oberfläche

Docker unterscheidet beim Port-Mapping zwischen 0.0.0.0 (alle Interfaces, öffentlich erreichbar) und 127.0.0.1 (nur der Server selbst kann zugreifen). Mit -p 127.0.0.1:8001:8001 ist Port 8001 am Server verfügbar, aber von außen nicht direkt ansprechbar.

Admin-Oberfläche per SSH-Tunnel erreichbar machen

Der SSH-Tunnel leitet einen lokalen Port auf den Server weiter und nutzt dabei, dass Port 8001 dort auf 127.0.0.1 erreichbar ist:

Admin-Laptop:8001  ──SSH──►  Server:127.0.0.1:8001  ──►  Container:8001
ssh -L 8001:localhost:8001 user@server

Danach ist die Admin-Oberfläche auf dem Laptop unter http://localhost:8001 erreichbar — ohne dass Port 8001 öffentlich exponiert wird.

Mit PostgreSQL

docker run -d \
  -p 8000:8000 \
  -p 127.0.0.1:8001:8001 \
  -e ADMIN_PASSWORD=geheim \
  -e DATABASE_URL=postgresql://user:pass@db-host:5432/llm_quota \
  -e OLLAMA_URL=http://ollama:11434 \
  llm-quota

Proxy-Endpunkte (Port 8000)

Alle Endpunkte erfordern einen gültigen API-Key im Authorization-Header.

curl -X POST http://localhost:8000/api/chat \
  -H "Authorization: Bearer sk-xxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"model":"llama3","messages":[{"role":"user","content":"Hallo"}]}'
Endpunkt Methode Beschreibung
/api/generate POST Ollama generate
/api/chat POST Ollama chat
/api/tags GET Verfügbare Modelle
/api/versions GET Ollama-Version
/v1/models GET Modelle (OpenAI-Format)
/v1/chat/completions POST Chat (OpenAI-Format)

Admin-API (Port 8001)

Alle Endpunkte erfordern Authorization: Bearer <ADMIN_PASSWORD>.

Endpunkt Methode Beschreibung
/api/api-keys GET Alle API-Keys auflisten
/api/api-keys POST Neuen API-Key erstellen
/api/api-keys/{id}/deactivate PUT API-Key deaktivieren
/api/api-keys/{id}/quota PATCH Quota eines Keys aktualisieren
/api/settings GET/PUT Ollama-URL und Standard-Modell
/api/ollama-models GET Verfügbare Modelle von Ollama
/api/proxy-info GET Lokaler Proxy-Endpunkt

Tests

cd backend
python -m pytest tests/ -v

Projektstruktur

llm_quota/
├── backend/
│   ├── main.py              # Proxy-Server (Port 8000)
│   ├── admin.py             # Admin-API + Static-File-Serving (Port 8001)
│   ├── database.py          # DB-Verbindung & Session
│   ├── models.py            # SQLAlchemy-Modelle (APIKey, Setting, Usage)
│   ├── schemas.py           # Pydantic-Schemas
│   ├── crud.py              # DB-Operationen, Token-Zählung, Quota-Logik
│   ├── init_db.py           # Tabellen anlegen & Settings seeden
│   ├── setup_admin.py       # Standard-API-Key erstellen
│   ├── requirements.txt     # Produktiv-Dependencies
│   ├── requirements-dev.txt # Test-Dependencies
│   └── tests/
│       ├── conftest.py      # Fixtures
│       ├── test_auth.py     # Authentifizierungs-Tests
│       └── test_quota.py    # Quota-, Token- und Ablauf-Tests
├── frontend/
│   └── src/
│       ├── main.jsx         # React-Admin-UI
│       └── styles.css
├── Dockerfile
├── docker-entrypoint.sh
├── .dockerignore
├── .env.example
├── start.sh                 # Entwicklungs-Startscript
└── .gitignore

Lizenz

MIT

Description
No description provided
Readme 206 KiB
Languages
Python 55.3%
JavaScript 28.4%
CSS 9.8%
Shell 4.9%
Dockerfile 1.1%
Other 0.5%