diff --git a/DOCKERHUB.en.md b/DOCKERHUB.en.md index c3fb523..43413af 100644 --- a/DOCKERHUB.en.md +++ b/DOCKERHUB.en.md @@ -1,10 +1,11 @@ # mediaeng/llmproxy -A lightweight reverse proxy for [Ollama](https://ollama.com) that manages API keys with configurable token and request quotas. Incoming requests in OpenAI-compatible format are authenticated, checked against the quota, and forwarded to the configured Ollama server. +A lightweight reverse proxy for [Ollama](https://ollama.com) that manages API keys with configurable token and request quotas. Incoming requests in OpenAI-compatible or Anthropic-compatible format are authenticated, checked against the quota, and forwarded to the configured Ollama server. ## Features - OpenAI-compatible endpoint (`/v1/chat/completions`, `/v1/models`) +- **Anthropic Messages API** (`/v1/messages`) — compatible with Claude Code CLI and Anthropic SDK clients - API key management with daily and monthly token/request limits - Web-based admin interface (port 8001) - Model lock: enforces a specific model for all requests (useful for courses and lab sessions) @@ -17,7 +18,7 @@ A lightweight reverse proxy for [Ollama](https://ollama.com) that manages API ke | Port | Service | |------|---------| -| `8000` | Proxy endpoint (OpenAI API) | +| `8000` | Proxy endpoint (OpenAI and Anthropic API) | | `8001` | Admin API + web interface | All API endpoints require the `ADMIN_PASSWORD` — without a valid token, only the public frontend files (HTML/JS/CSS of the login page) are accessible. The password is therefore the primary protection. @@ -35,6 +36,8 @@ All API endpoints require the `ADMIN_PASSWORD` — without a valid token, only t | `ADMIN_PORT` | `8001` | Admin API port | | `APP_TZ` | `Europe/Berlin` | Timezone for daily/monthly quota resets | | `LOG_FILE` | `logs/usage.log` | Path of the rotating usage log file | +| `ANTHROPIC_DEFAULT_MODEL` | – | Default model for `/v1/messages` (Ollama model name, e.g. `llama3`) | +| `BACKEND_API_KEY` | – | API key for an upstream proxy (forwarded to the backend) | ## Docker Compose – Ollama on the Host (Linux, recommended) @@ -60,6 +63,7 @@ volumes: ADMIN_PASSWORD=changeme OLLAMA_URL=http://localhost:11434 APP_TZ=Europe/Berlin +ANTHROPIC_DEFAULT_MODEL=llama3 ``` ## Docker Compose – Ollama as Container, SQLite @@ -77,8 +81,8 @@ services: environment: ADMIN_PASSWORD: changeme OLLAMA_URL: http://ollama:11434 - APP_TZ: Europe/Berlin + ANTHROPIC_DEFAULT_MODEL: llama3 volumes: - llmproxy-data:/app/backend depends_on: @@ -110,9 +114,9 @@ services: environment: ADMIN_PASSWORD: changeme OLLAMA_URL: http://ollama:11434 - APP_TZ: Europe/Berlin DATABASE_URL: postgresql://llmproxy:secret@db:5432/llmproxy + ANTHROPIC_DEFAULT_MODEL: llama3 depends_on: db: condition: service_healthy @@ -147,9 +151,19 @@ volumes: ## Client Configuration -Configure the proxy as an OpenAI-compatible endpoint: - +**OpenAI-compatible client:** ``` Base URL: http://:8000/v1 API Key: ``` + +**Claude Code CLI:** +```bash +ANTHROPIC_BASE_URL=http://:8000 \ +ANTHROPIC_AUTH_TOKEN= \ +claude +``` + +## Acknowledgements + +The Anthropic Messages API endpoint (`/v1/messages`) was inspired by [free-claude-code](https://github.com/Alishahryar1/free-claude-code) by Ali Khokhar, which pursues a similar approach for routing Claude Code requests to alternative LLM backends. diff --git a/DOCKERHUB.md b/DOCKERHUB.md index 44ada32..b51fd5a 100644 --- a/DOCKERHUB.md +++ b/DOCKERHUB.md @@ -1,10 +1,11 @@ # mediaeng/llmproxy -Ein schlanker Reverse-Proxy für [Ollama](https://ollama.com), der API-Keys mit konfigurierbaren Token- und Request-Quoten verwaltet. Eingehende Anfragen im OpenAI-kompatiblen Format werden authentifiziert, auf Quota geprüft und an den konfigurierten Ollama-Server weitergeleitet. +Ein schlanker Reverse-Proxy für [Ollama](https://ollama.com), der API-Keys mit konfigurierbaren Token- und Request-Quoten verwaltet. Eingehende Anfragen im OpenAI-kompatiblen oder Anthropic-kompatiblen Format werden authentifiziert, auf Quota geprüft und an den konfigurierten Ollama-Server weitergeleitet. ## Funktionen - OpenAI-kompatibler Endpunkt (`/v1/chat/completions`, `/v1/models`) +- **Anthropic Messages API** (`/v1/messages`) — kompatibel mit Claude Code CLI und Anthropic-SDK-Clients - API-Key-Verwaltung mit tages- und monatlichen Token-/Request-Limits - Web-basierte Admin-Oberfläche (Port 8001) - Modell-Lock: erzwingt ein bestimmtes Modell für alle Requests (nützlich für Praktika/Kurse) @@ -17,7 +18,7 @@ Ein schlanker Reverse-Proxy für [Ollama](https://ollama.com), der API-Keys mit | Port | Dienst | |------|--------| -| `8000` | Proxy-Endpunkt (OpenAI-API) | +| `8000` | Proxy-Endpunkt (OpenAI- und Anthropic-API) | | `8001` | Admin-API + Web-Oberfläche | Alle API-Endpunkte erfordern das `ADMIN_PASSWORD` — ein Zugriff ohne gültiges Token liefert nur die öffentlichen Frontend-Dateien (HTML/JS/CSS der Login-Seite). Das Passwort ist damit die primäre Schutzmaßnahme. @@ -35,6 +36,8 @@ Alle API-Endpunkte erfordern das `ADMIN_PASSWORD` — ein Zugriff ohne gültiges | `ADMIN_PORT` | `8001` | Port der Admin-API | | `APP_TZ` | `Europe/Berlin` | Zeitzone für Tages-/Monats-Reset der Quoten | | `LOG_FILE` | `logs/usage.log` | Pfad der rotierenden Nutzungs-Logdatei | +| `ANTHROPIC_DEFAULT_MODEL` | – | Standard-Modell für `/v1/messages` (Ollama-Modellname, z. B. `llama3`) | +| `BACKEND_API_KEY` | – | API-Key für einen vorgelagerten Proxy (wird an das Backend weitergereicht) | ## Docker Compose – Ollama auf dem Host (Linux, empfohlen) @@ -60,6 +63,7 @@ volumes: ADMIN_PASSWORD=changeme OLLAMA_URL=http://localhost:11434 APP_TZ=Europe/Berlin +ANTHROPIC_DEFAULT_MODEL=llama3 ``` ## Docker Compose – Ollama als Container, SQLite @@ -77,8 +81,8 @@ services: environment: ADMIN_PASSWORD: changeme OLLAMA_URL: http://ollama:11434 - APP_TZ: Europe/Berlin + ANTHROPIC_DEFAULT_MODEL: llama3 volumes: - llmproxy-data:/app/backend depends_on: @@ -110,9 +114,9 @@ services: environment: ADMIN_PASSWORD: changeme OLLAMA_URL: http://ollama:11434 - APP_TZ: Europe/Berlin DATABASE_URL: postgresql://llmproxy:secret@db:5432/llmproxy + ANTHROPIC_DEFAULT_MODEL: llama3 depends_on: db: condition: service_healthy @@ -147,9 +151,15 @@ volumes: ## Client-Konfiguration -Den Proxy als OpenAI-kompatibler Endpunkt konfigurieren: - +**OpenAI-kompatibler Client:** ``` Base URL: http://:8000/v1 API Key: ``` + +**Claude Code CLI:** +```bash +ANTHROPIC_BASE_URL=http://:8000 \ +ANTHROPIC_AUTH_TOKEN= \ +claude +``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e9b2785 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +MIT License + +Copyright (c) 2026 Oliver Hofmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +Portions of this software were inspired by free-claude-code +(https://github.com/Alishahryar1/free-claude-code), +copyright (c) 2026 Ali Khokhar, MIT License. diff --git a/README.md b/README.md index f2e7269..6d1678d 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,13 @@ Ollama bietet von sich aus keine Authentifizierung — wer die API erreicht, kan ## Features -- API-Key-Authentifizierung (Bearer Token oder `sk-`-Prefix) +- API-Key-Authentifizierung (Bearer Token, `sk-`-Prefix, `x-api-key`- und `anthropic-auth-token`-Header) - 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 +- Token-Zählung via tiktoken, Reset-Grenzen in der konfigurierten Zeitzone - Web-Admin-Oberfläche (API-Keys verwalten, Ollama-Einstellungen, Verbrauchsanzeige) - OpenAI-kompatibler `/v1/chat/completions`-Endpunkt mit Streaming und Tool-Use +- **Anthropic Messages API** `/v1/messages` — kompatibel mit Claude Code CLI und Anthropic-SDK-Clients - Rotierende Nutzungs-Logs - SQLite (Standard) oder PostgreSQL - Docker-Image auf DockerHub: `mediaeng/llmproxy` @@ -35,6 +36,7 @@ DATABASE_URL=sqlite:///./test.db OLLAMA_URL=http://localhost:11434 APP_TZ=Europe/Berlin LOG_FILE=logs/usage.log +ANTHROPIC_DEFAULT_MODEL=llama3 ``` | Variable | Standard | Beschreibung | @@ -49,6 +51,8 @@ LOG_FILE=logs/usage.log | `APP_TZ` | `Europe/Berlin` | Zeitzone für tägliche/monatliche Quota-Resets | | `LOG_FILE` | `logs/usage.log` | Pfad der rotierenden Nutzungs-Logdatei | | `ALLOWED_ORIGINS` | `http://localhost:5173` | CORS-Origins (nur für Entwicklung relevant) | +| `ANTHROPIC_DEFAULT_MODEL` | — | Standard-Modell für `/v1/messages` (Ollama-Modellname) | +| `BACKEND_API_KEY` | — | API-Key für einen vorgelagerten Proxy (wird an das Backend weitergereicht) | ## Entwicklung (lokal) @@ -78,6 +82,23 @@ Das Script prüft alle Ports auf Belegung, initialisiert die Datenbank und start Admin-Oberfläche: `http://localhost:5173` +## Claude Code CLI + +Der Proxy stellt einen Anthropic-kompatiblen Endpunkt bereit, über den Claude Code CLI mit lokalen Ollama-Modellen genutzt werden kann. + +```bash +# ANTHROPIC_DEFAULT_MODEL in .env setzen, dann: +./start_claude.sh + +# Oder mit Key als Argument: +./start_claude.sh sk-dein-api-key + +# Oder als Umgebungsvariable: +PROXY_API_KEY=sk-dein-api-key ./start_claude.sh +``` + +Das Script setzt `ANTHROPIC_BASE_URL` und `ANTHROPIC_AUTH_TOKEN` automatisch aus der `.env` und startet `claude`. + ## Produktion (Docker) ### Docker Compose (empfohlen) @@ -168,17 +189,26 @@ Clients konfigurieren dann `https://llm.example.com/v1` als Base URL. ## Proxy-Endpunkte (Port 8000) -Alle Endpunkte erfordern einen gültigen API-Key im `Authorization`-Header. +Alle Endpunkte erfordern einen gültigen API-Key im `Authorization`-Header (`Bearer sk-...`), im `x-api-key`-Header oder im `anthropic-auth-token`-Header. ```bash +# OpenAI-kompatibler Endpunkt curl -X POST http://localhost:8000/v1/chat/completions \ -H "Authorization: Bearer sk-xxxxxx" \ -H "Content-Type: application/json" \ -d '{"model":"llama3","messages":[{"role":"user","content":"Hallo"}]}' + +# Anthropic-kompatibler Endpunkt (z. B. für Claude Code) +curl -X POST http://localhost:8000/v1/messages \ + -H "x-api-key: sk-xxxxxx" \ + -H "anthropic-version: 2023-06-01" \ + -H "Content-Type: application/json" \ + -d '{"model":"llama3","messages":[{"role":"user","content":"Hallo"}],"max_tokens":1024}' ``` | Endpunkt | Methode | Beschreibung | |----------|---------|--------------| +| `/v1/messages` | POST | Chat (Anthropic-Format, Streaming + Tool-Use) | | `/v1/chat/completions` | POST | Chat (OpenAI-Format, Streaming + Tool-Use) | | `/v1/models` | GET | Modelle (OpenAI-Format) | | `/api/generate` | POST | Ollama generate (nativ) | @@ -226,7 +256,8 @@ llm_quota/ │ └── tests/ │ ├── conftest.py │ ├── test_auth.py -│ └── test_quota.py +│ ├── test_quota.py +│ └── test_anthropic_messages.py ├── frontend/ │ └── src/ │ ├── main.jsx # React-Admin-UI @@ -238,13 +269,19 @@ llm_quota/ ├── docker-entrypoint.sh ├── .dockerignore ├── start.sh # Entwicklungs-Startscript +├── start_claude.sh # Claude Code CLI mit Proxy starten ├── run_dev.py # Entwicklungs-Runner für PyCharm ├── build_push.sh # Docker-Build & Push zu DockerHub +├── LICENSE ├── DOCKERHUB.md # DockerHub-Beschreibung (deutsch) ├── DOCKERHUB.en.md # DockerHub-Beschreibung (englisch) └── .gitignore ``` +## Danksagung + +Der Anthropic-kompatible Endpunkt (`/v1/messages`) wurde durch das Projekt [free-claude-code](https://github.com/Alishahryar1/free-claude-code) von Ali Khokhar inspiriert, das einen ähnlichen Ansatz für das Weiterleiten von Claude-Code-Anfragen an alternative LLM-Backends verfolgt. + ## Lizenz -MIT +MIT — siehe [LICENSE](LICENSE)