docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# llm-proxy: Postgres, the backend and the frontend, from the published images.
#
# No .env file is needed: every setting is written here. Edit the values in this
# file, then run `docker compose up -d`. CHANGE ME marks what to change before the
# first start; the file also starts as it is, but its placeholders are public. A
# setting that has a default is written with that default; a setting that is off or
# computed by default is a commented-out example. The minimal version of this stack
# is docker-compose.minimal.yml.
#
# Only the proxied API (host port 8080) and the web interface (host port 8081) are
# published. Three networks keep each listener to the containers that need it: `web`
# joins the frontend and the backend's web API, `db` the backend and Postgres,
# `metrics` the backend's /metrics and a scraper, which an operator attaches to it.
# The web API and /metrics listen only on their network's address (the backend's
# alias there), so a container on another network cannot reach them. The web API
# trusts X-Real-IP only because the frontend alone can reach it.
services:
postgres:
image: postgres:17-alpine
networks: [db]
environment:
# The user and database names are also in the backend's connection URL and in
# the healthcheck below: keep them to letters, digits and _ - .
POSTGRES_USER: llmproxy
# CHANGE ME (e.g. openssl rand -hex 24). It must match PGPASSWORD in the
# backend. Postgres takes it only on its first start, with an empty volume.
POSTGRES_PASSWORD: change-me-db-password
POSTGRES_DB: llmproxy
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "llmproxy", "-d", "llmproxy"]
interval: 5s
timeout: 3s
retries: 10
backend:
# The backend and the frontend are released together: keep one version for both.
image: yoonaowo/llm-proxy-backend:0.8.4
environment:
# The password travels as PGPASSWORD, which the driver reads when the URL
# carries none, so it needs no URL encoding.
LLMPROXY_DATABASE_URL: postgres://llmproxy@postgres:5432/llmproxy?sslmode=disable
# CHANGE ME: the same value as POSTGRES_PASSWORD above.
PGPASSWORD: change-me-db-password
# CHANGE ME (openssl rand -hex 32), best before adding vendor accounts: at least
# 32 bytes. It encrypts the vendor accounts' OAuth credentials in the database.
# The placeholder works but is public, and the backend warns while it is set.
# Keep the key apart from database backups: changing or losing it means signing
# every vendor account in again.
LLMPROXY_CREDENTIALS_KEY: change-me-credentials-key-at-least-32-bytes
# The proxied LLM API: the one backend listener published.
LLMPROXY_LISTEN_ADDR: ":8080"
# The web API (/api/*) on the `web` network only, /metrics on the `metrics`
# network only; no ports entry publishes either. A scraper must join
# `metrics` and scrape http://backend-metrics:9090/metrics.
LLMPROXY_WEB_ADDR: "backend-web:8081"
LLMPROXY_METRICS_ADDR: "backend-metrics:9090"
# Paths upstream requires. Nothing is written under LLMPROXY_RUNTIME_DIR, and
# LLMPROXY_AUTH_DIR holds only a vendor sign-in's hand-off file, for about a
# second: the vendor accounts are in Postgres.
LLMPROXY_RUNTIME_DIR: /var/lib/llmproxy/runtime
LLMPROXY_AUTH_DIR: /var/lib/llmproxy/auths
# The first administrator's login. While no administrator exists, the backend
# creates it and prints a one-time password in its log. Empty disables this.
LLMPROXY_BOOTSTRAP_ADMIN_EMAIL: admin@example.com
# Where clients reach the proxied API; shown on the Connect page. Behind a
# reverse proxy: https://llm-proxy.example.com.
LLMPROXY_PUBLIC_API_URL: http://localhost:8080
# false only because this stack serves the web interface over plain http, where
# a Secure cookie would not be sent back. Behind TLS, set it to "true".
LLMPROXY_COOKIE_SECURE: "false"
# "false" turns the email-and-password form off (an OIDC-only installation).
LLMPROXY_LOCAL_LOGIN: "true"
# Parallel password hashes (about 19 MiB each); unset: the CPU count.
# LLMPROXY_PASSWORD_HASH_CONCURRENCY: "4"
# The process log's format: "text" (key=value lines) or "json" (one object per line).
LLMPROXY_LOG_FORMAT: text
# "on" fetches upstream's model catalogue from the internet at start and every
# three hours; "off" keeps the one compiled into the build.
LLMPROXY_MODEL_CATALOG_UPDATES: "on"
# The price catalog (oh-my-pi's model catalog; "off": manual prices only) and
# how often it is checked (at least 5m).
LLMPROXY_PRICES_CATALOG_URL: https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/catalog/src/models.json
LLMPROXY_PRICES_CATALOG_INTERVAL: 6h
# OIDC sign-in, off while LLMPROXY_OIDC_ISSUER is unset. To turn it on, uncomment
# the lines below: the session key, client id, secret and redirect URL are then
# required.
# CHANGE ME with OIDC: seals the sign-in cookie; at least 32 bytes
# (openssl rand -base64 48).
# LLMPROXY_SESSION_KEY: change-me-session-key-at-least-32-bytes
# The identity provider's issuer URL.
# LLMPROXY_OIDC_ISSUER: https://idp.example.com/realms/example
# LLMPROXY_OIDC_CLIENT_ID: llm-proxy
# CHANGE ME with OIDC: the client secret from the identity provider.
# LLMPROXY_OIDC_CLIENT_SECRET: change-me-oidc-client-secret
# https://<web interface host>/api/auth/oidc/callback
# LLMPROXY_OIDC_REDIRECT_URL: http://localhost:8081/api/auth/oidc/callback
# A group every federated user must be in; unset admits anyone.
# LLMPROXY_OIDC_REQUIRED_GROUP: /llm-users
# "true" creates an account for an unknown user at the first sign-in.
# LLMPROXY_OIDC_ALLOW_SIGNUP: "true"
# Rules a signed-up user starts with, comma-separated.
# LLMPROXY_OIDC_DEFAULT_POLICY: chatgpt:*
# group=rule,rule;group=rule - when set, groups own federated users' rules.
# LLMPROXY_OIDC_GROUP_POLICY: /llm-users=chatgpt:*;/llm-claude=claude:*,chatgpt:*
# The ID token claim that holds the groups.
LLMPROXY_OIDC_GROUPS_CLAIM: groups
# The sign-in button's label; unset leaves it to the frontend.
# LLMPROXY_OIDC_DISPLAY_NAME: Example SSO
networks:
web:
aliases: [backend-web]
db: {}
metrics:
aliases: [backend-metrics]
ports:
# Host port of the proxied API. Behind a reverse proxy on the same host:
# - "127.0.0.1:8080:8080"
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
# On SIGTERM, requests in flight get 30 s to finish (streams included), then
# writing the queued usage records up to 5 s; give it that long before SIGKILL.
stop_grace_period: 45s
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/healthz"]
interval: 10s
timeout: 3s
retries: 5
frontend:
# The same version as the backend image.
image: yoonaowo/llm-proxy-frontend:0.8.4
environment:
# The backend's web listener, on the `web` network.
BACKEND_ORIGIN: http://backend:8081
# Addresses/CIDRs of your reverse proxy, comma-separated, trusted for
# X-Forwarded-For; unset trusts none.
# REAL_IP_FROM: 172.16.0.0/12
networks: [web]
ports:
# Host port of the web interface. Behind a reverse proxy on the same host:
# - "127.0.0.1:8081:8080"
- "8081:8080"
depends_on:
backend:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/healthz"]
interval: 10s
timeout: 3s
retries: 5
networks:
web:
db:
metrics:
volumes:
pgdata: