Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
88 lines (87 loc) · 3.85 KB
/
Copy pathdocker-compose.yml
File metadata and controls
88 lines (87 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# CPA Usage: usage analytics, request monitor, and quota for CLIProxyAPI, with a built-in usage
# collector that stores request history in ./data.
#
# docker compose up -d --build
# open http://127.0.0.1:18320 (local)
# open https://cpa-usage.<tailnet>.ts.net (tailnet, via the tailscale sidecar below)
#
# Settings come from .env (see .env.example).
services:
proxy-usage:
build: .
image: proxy-usage:local
container_name: proxy-usage
restart: unless-stopped
stop_grace_period: 15s
ports:
# Loopback by default: the tailnet reaches the app through the tailscale sidecar over the
# compose network, not this port. Set BIND_ADDR=0.0.0.0 to also expose it on the LAN.
- "${BIND_ADDR:-127.0.0.1}:${PORT:-18320}:18320"
environment:
PORT: "18320"
HOST: "0.0.0.0"
DATA_DIR: /data
# CLIProxyAPI on the Docker host. host.docker.internal works on Docker Desktop and OrbStack, and
# on Linux via the host-gateway mapping below. CLIProxyAPI must allow this connection: set
# `management.allow-remote: true` if it rejects the container as non-local.
CPA_URL: "${CPA_URL:-http://host.docker.internal:8317}"
# Management key used by the collector (the same key you sign in with).
CPA_MANAGEMENT_KEY: "${CPA_MANAGEMENT_KEY:-}"
CPA_TLS_INSECURE: "${CPA_TLS_INSECURE:-false}"
RETENTION_DAYS: "${RETENTION_DAYS:-0}"
COLLECTOR_MODE: "${COLLECTOR_MODE:-auto}"
AUTO_ENABLE_USAGE_STATISTICS: "${AUTO_ENABLE_USAGE_STATISTICS:-true}"
# Requests CLIProxyAPI rejected before reaching a credential, read from its log (empty = on
# unless COLLECTOR_MODE=off).
COLLECT_ROUTING_FAILURES: "${COLLECT_ROUTING_FAILURES:-}"
ROUTING_FAILURE_POLL_MS: "${ROUTING_FAILURE_POLL_MS:-5000}"
PRICE_SYNC_INTERVAL_HOURS: "${PRICE_SYNC_INTERVAL_HOURS:-24}"
LOG_LEVEL: "${LOG_LEVEL:-info}"
# Extra hostnames to accept besides localhost, IPs, *.ts.net and *.local (comma separated).
ALLOWED_HOSTS: "${ALLOWED_HOSTS:-}"
# UI published with `npm run publish:ui` goes live without a restart; the UI baked into the
# image is served until ./web holds one.
UI_DIR: /app/web
volumes:
# Usage history (SQLite). Keep it: deleting it deletes your history.
- ./data:/data
- ./web:/app/web:ro
extra_hosts:
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:18320/healthz"]
interval: 15s
timeout: 3s
retries: 3
# Tailscale sidecar: joins the tailnet as its own machine (TS_HOSTNAME) and uses Tailscale Serve
# (tailnet only, never Funnel) to proxy https://<TS_HOSTNAME>.<tailnet>.ts.net to the app at
# http://proxy-usage:18320 on the compose network. It has its own network namespace, so the app
# can be restarted or recreated independently and local access never depends on Tailscale.
# Remove this service if you don't use Tailscale.
tailscale:
image: tailscale/tailscale:stable
container_name: proxy-usage-tailscale
hostname: ${TS_HOSTNAME:-cpa-usage}
restart: unless-stopped
depends_on:
proxy-usage:
condition: service_started
environment:
# Only used for the first join; afterwards the node identity lives in ./tailscale/state.
TS_AUTHKEY: ${TS_AUTHKEY:-}
TS_AUTH_ONCE: "true"
TS_HOSTNAME: ${TS_HOSTNAME:-cpa-usage}
TS_STATE_DIR: /var/lib/tailscale
TS_SERVE_CONFIG: /config/serve.json
TS_USERSPACE: "true"
TS_ENABLE_HEALTH_CHECK: "true"
TS_LOCAL_ADDR_PORT: 127.0.0.1:9002
volumes:
- ./tailscale/state:/var/lib/tailscale
- ./tailscale/serve.json:/config/serve.json:ro
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://127.0.0.1:9002/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s