No description
  • Python 98.7%
  • Dockerfile 1.3%
Find a file
Pandi 52d64b73ea
Some checks are pending
Build and Push Docker Image / build-and-push (push) Waiting to run
Tests / pytest (push) Waiting to run
fix(compose): no private LAN address in the published compose file
The example compose pointed at the maintainer host with a concrete RFC1918
address, while the README documented host.docker.internal. Anyone cloning the
repo would proxy against a host they cannot reach, and the address of a private
setup stood in a public repo. Now ${OLLAMA_BASE_URL:-http://host.docker.internal:11434},
same default as the README. Safe for the running deployment: its container is
configured by the app definition (checked via docker inspect), not by this file.
2026-11-02 10:31:50 +01:00
.github/workflows test: cover the cloud usage parser and run the suite in CI 2026-10-30 16:01:09 +01:00
.gitignore fix(proxy): avoid 0.0%/0.0x placeholders when no GPU time data yet 2026-08-14 21:10:31 +02:00
analyzer.py fix(analyzer): read HISTORY_SIZE instead of documenting a knob nobody read 2026-11-01 09:08:07 +01:00
collector.py refactor: drop two dead symbols, one duplicate default, one deprecated call 2026-10-30 18:41:21 +01:00
docker-compose.yml fix(compose): no private LAN address in the published compose file 2026-11-02 10:31:50 +01:00
Dockerfile Initial commit: Ollama Cloud Usage Monitor + Proxy 2026-07-11 19:58:19 +02:00
logo.svg fix(proxy): avoid 0.0%/0.0x placeholders when no GPU time data yet 2026-08-14 21:10:31 +02:00
main.py fix(config): read the debounce knob under both names 2026-10-31 09:07:30 +01:00
README.md fix(analyzer): read HISTORY_SIZE instead of documenting a knob nobody read 2026-11-01 09:08:07 +01:00
requirements.txt Initial commit: Ollama Cloud Usage Monitor + Proxy 2026-07-11 19:58:19 +02:00
test_cloud_failover.py feat: fail over cloud models across API keys 2026-10-30 12:24:37 +01:00
test_history_size.py fix(analyzer): read HISTORY_SIZE instead of documenting a knob nobody read 2026-11-01 09:08:07 +01:00
test_parse_page.py test: cover the cloud usage parser and run the suite in CI 2026-10-30 16:01:09 +01:00
test_proxy_auth.py feat(auth): opt-in bearer token for the proxy and usage endpoints 2026-10-30 15:07:14 +01:00
test_proxy_stream.py refactor(proxy): one pass-through path, one stream path, one summary text 2026-10-30 18:51:42 +01:00

ollama-usage-monitor

Transparent proxy for Ollama that sits between your client (Open WebUI, Hermes, etc.) and your local Ollama instance. It intercepts nothing by default — every /api/chat and /api/generate request passes through untouched.

But it also fetches your ollama.com cloud usage (session + weekly limits) and lets you check it via chat keywords or HTTP endpoints — without burning a single token.

Client  --/api/chat--> Usage Monitor (port 9462) --/api/chat--> Ollama (local)
                           |
                           | GET /api/usage  (every OLLAMA_DEBOUNCE_SECONDS)
                           v
                      ollama.com (cloud API)

What it tracks

Field Example Meaning
Tier pro Your ollama.com plan
Session 16.6% (332/2000) Requests used this session (resets ~2h)
Weekly 20.4% (1020/5000) Requests used this week (resets ~4d)
Burn rate 15.88/h Average requests per hour
Models deepseek-v4-flash: 82.5% Breakdown by model
Recommendation ok / caution / limit Should you worry?

Chat Keywords

Send any of these as the only content of a chat message to any model via the proxy:

Keyword Description
usage Detailed usage data with model breakdown, burn rate, alerts
summary Compact usage summary (tier, session, weekly, recommendation)
history Last 20 usage snapshots
refresh Force immediate refresh from ollama.com
info / help Show all available commands and endpoints

Keywords are stripped from the chat history — the model never sees them.

HTTP Endpoints

Endpoint Description
GET /health Health check
GET /usage Full usage data with analysis
GET /usage/raw Raw usage data without analysis
GET /usage/summary Human-readable summary
GET /usage/history Last 20 usage snapshots
GET /info Available commands and endpoints
POST /usage/refresh Force refresh usage data

Quick Start

services:
  ollama-usage-monitor:
    image: mrschnirschuh/ollama-usage-monitor:latest
    container_name: ollama-usage-monitor
    environment:
      - OLLAMA_COOKIE=your_ollama_com_cookie
      - OLLAMA_BASE_URL=http://host.docker.internal:11434
      # Optional, recommended: require a bearer token on every endpoint but /health
      - PROXY_TOKEN=${PROXY_TOKEN:-}
      # Optional: restrict which browser origins may call the proxy (default '*')
      - CORS_ORIGINS=https://openwebui.example.com
      - OLLAMA_DEBOUNCE_SECONDS=30
      - LOG_LEVEL=INFO
    ports:
      - '9462:9462'
    restart: unless-stopped
    volumes:
      - ollama-usage-data:/data

volumes:
  ollama-usage-data:

Security

The proxy forwards cloud requests with server-side credentials: for *:cloud models it replaces the caller's Authorization header with a key from OLLAMA_CLOUD_KEYS and sends the request to OLLAMA_CLOUD_URL. Every call is billed to your account.

Without PROXY_TOKEN, anyone who can reach the port gets those keys forwarded for them.

Auth is opt-in so existing deployments keep working after an image pull:

PROXY_TOKEN Behaviour
unset / empty unchanged — no auth, but a loud WARNING line at startup
set every endpoint except GET /health requires Authorization: Bearer <PROXY_TOKEN>, otherwise 401 {"detail":"Unauthorized"} and no upstream call

Clients just send it as their API key (Open WebUI: Connection → API Key, Hermes: api_key). Use HTTPS or a private network in front of the port — a bearer token on plain HTTP is readable on the wire. CORS_ORIGINS (comma-separated) narrows which browser origins may call the proxy; the default * is logged as a warning.

Environment Variables

Variable Default Description
OLLAMA_COOKIE — ollama.com session cookie (required)
OLLAMA_BASE_URL http://host.docker.internal:11434 Upstream Ollama URL
OLLAMA_CLOUD_KEYS — Comma-separated ollama.com API keys. When set, *:cloud models bypass the local Ollama and go straight to OLLAMA_CLOUD_URL; on 401/402/403/429 the next key from a different account takes the request. Empty = old behaviour (everything through the local Ollama)
OLLAMA_CLOUD_URL https://ollama.com Upstream for cloud models when keys are set
OLLAMA_DEBOUNCE_SECONDS 30 Min seconds between ollama.com fetches (legacy name DEBOUNCE_SECONDS still works)
LOG_LEVEL INFO Log level (DEBUG, INFO, WARNING, ERROR)
PORT 9462 Proxy listen port
HISTORY_SIZE 100 Number of snapshots kept in the history file; older ones are dropped. Invalid or empty values are ignored with a warning
PROXY_TOKEN — Opt-in bearer token. Set it and every endpoint except GET /health requires Authorization: Bearer <PROXY_TOKEN>. Empty = no auth (logged as a warning at startup)
CORS_ORIGINS * Comma-separated browser origins allowed to call the proxy; * is logged as a warning

Cloud key failover exists because Ollama's concurrency limit is per account (measured: ~13 concurrent requests per key, 429 too many concurrent requests beyond it). Two keys of the same account share one pool and gain nothing — the second key must belong to another account. Self-check: python3 test_cloud_failover.py.