Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
143 lines (125 loc) · 7.28 KB
/
Copy path.env.example
File metadata and controls
143 lines (125 loc) · 7.28 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Root .env.example - deploy operator checklist.
# Copy to `.env` on each deploy host and fill every required value.
#
# Variable types:
# - Non-secret: safe to commit or place in `.env` when host-local review is easier.
# - Secret: never commit real values. Application/runtime secrets normally live
# in `secrets/<env>/`; only host/Compose helper secrets that must be
# interpolated by Compose are shown here.
#
# One host serves one environment; this file holds everything host-specific.
# --- Required host-local deploy inputs --------------------------------
# Type: non-secret | Consumer: deploy recipes | Purpose: the environment this host
# runs. `just stack prod up` / `just stack staging up` refuse to run when it does not match.
ENVIRONMENT=prod
# Type: non-secret | Consumer: hand-run `docker compose` | Purpose: give a bare
# compose command in this directory the same identity the deploy recipes use.
# Without them Compose names the project after the directory and loads compose.yaml
# alone, which raises a second, secretless copy of the stack alongside the running
# one. Match the project to ENVIRONMENT (r9lab_prod or r9lab_staging), and append
# the telemetry overlays this host actually runs (`:compose.telemetry.yml`, then
# `:compose.telemetry.gpu.yml`) so a hand-run `up` does not orphan those services.
# The deploy recipes pass -p and -f explicitly and those take precedence, so these
# two never change what `just stack prod up` / `just stack staging up` do.
COMPOSE_PROJECT_NAME=r9lab_prod
COMPOSE_FILE=compose.yaml:compose.deploy.yaml
# Type: non-secret | Consumer: every service | Purpose: the four public origins.
API_PUBLIC_URL=https://api.example.org
APP_PUBLIC_URL=https://app.example.org
SITE_PUBLIC_URL=https://example.org
DOCS_PUBLIC_URL=https://docs.example.org
# Type: non-secret | Consumer: every R9lab service | Purpose: the published image tag
# to run, `0.4.0` for a release or `sha-<short sha>` for a manual publish. Change it
# with `just stack <env> tag YES <tag>`, which pulls the images before writing it.
IMAGE_TAG=0.4.0
# Type: non-secret | Consumer: backend auth | Purpose: OAuth public client IDs.
GOOGLE_OAUTH_CLIENT_ID=replace-me
GITHUB_OAUTH_CLIENT_ID=replace-me
# Type: non-secret | Consumer: backend email | Purpose: outbound email identity.
# Use `smtp` for SMTP relays, or `microsoft_graph` for Microsoft 365 Graph mail.
# Compose requires the shared identity fields below. Backend startup validation
# enforces the provider-specific fields and matching secret files.
EMAIL_PROVIDER=smtp
EMAIL_FROM="R9lab <noreply@r9lab.io>"
EMAIL_REPLY_TO=info@r9lab.io
# Type: non-secret | Consumer: backend email | Purpose: required when EMAIL_PROVIDER=smtp.
SMTP_HOST=smtp.example.org
SMTP_USERNAME=relab@example.org
# Secret file required for SMTP: secrets/<env>/smtp_password
# Type: non-secret | Consumer: backend email | Purpose: required when EMAIL_PROVIDER=microsoft_graph.
# MICROSOFT_GRAPH_TENANT_ID=replace-me
# MICROSOFT_GRAPH_CLIENT_ID=replace-me
# MICROSOFT_GRAPH_SENDER_USER=relab@example.org
# Secret file required for Microsoft Graph: secrets/<env>/microsoft_graph_client_secret
# Type: non-secret | Consumer: backend bootstrap | Purpose: initial superuser identity.
BOOTSTRAP_SUPERUSER_EMAIL=admin@example.org
# Application/runtime secrets go in `secrets/<env>/`, not in this file.
# Create missing secret files with:
# just deploy-secrets-template prod
# just deploy-secrets-template staging
# --- Optional host-local deploy inputs --------------------------------
# Type: non-secret | Consumer: every R9lab service | Purpose: where the images come
# from. A fork publishes its own (its www, app and docs images carry its own URLs)
# and points this at its namespace.
# IMAGE_REGISTRY=ghcr.io/cmlplatform
# Type: secret | Consumer: telemetry | Purpose: optional central monitoring.
# Setting OTEL_EXPORTER_OTLP_ENDPOINT is the on/off switch for the whole telemetry path.
# It turns on the API's own OpenTelemetry exporter (traces, metrics, logs with trace
# context) AND auto-includes compose.telemetry.yml, which ships every other
# container's stdout to the same collector.
#
# The endpoint and token come from the monitoring stack operator
# (github.com/CMLPlatform/monitoring). One token, two consumers: compose folds it into
# the SDK's header format for the API, and Alloy reads it directly.
#
# All three values must be set together (`just deploy-secrets-check` enforces it), and
# the endpoint must be https:// — a plaintext endpoint would ship the token and every
# container log in cleartext with no error anywhere.
#
# TELEMETRY_EDGE_KEY is a second, weaker credential: the Cloudflare WAF-skip rule for
# otel. matches it (infra/cloudflare-zone, TF_VAR_telemetry_edge_key must carry the
# same value), so the bearer token itself never appears in a Cloudflare ruleset
# expression. Rotate the key together with the zone rule; the token rotates with the
# collector, independently.
#
# NOTE: both values reach the api and alloy containers as plain environment variables,
# so anyone in this host's docker group can read them via `docker inspect`. That group
# is already root-equivalent on the host; noted so it is a decision, not a surprise.
#
# Signals are labelled project=r9lab (set by the deploy recipes) and env=ENVIRONMENT,
# which is what the central stack's ProjectTelemetrySilent rule keys on.
# OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.cml-relab.org
# OTLP_AUTH_TOKEN=<bearer token>
# TELEMETRY_EDGE_KEY=<edge key>
# OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
#
# On a host with an NVIDIA card, add GPU metrics (utilisation, VRAM, temperature, power,
# throttle reasons and XID faults). Needs the nvidia container runtime. Only 1/true/yes
# turn it on; 0/false/unset leave it off.
# GPU_METRICS=1
# Type: non-secret | Consumer: backup | Purpose: local restic repository path.
# One value for every stack on this host. Two environments co-located on one
# machine would therefore share ${BACKUP_HOST_DIR}/restic; that fails closed (the
# second environment's restic password will not open the first's repository) but
# means only one of them gets backups. Give each host a single environment, or
# set an absolute per-environment path here. The deploy scripts read this value
# literally: no ${VAR} expansion, so it must be a literal path, not an interpolated one.
BACKUP_HOST_DIR=./backups
# Type: non-secret | Consumer: postgres | Purpose: existing cluster superuser.
# Only needed when the database volume comes from a cluster whose superuser is
# not named `postgres` — the healthcheck runs `pg_isready -U $POSTGRES_USER`,
# so a wrong name leaves postgres permanently unhealthy.
# POSTGRES_SUPERUSER=postgres
# Type: non-secret | Consumer: backend | Purpose: per-user upload ceilings.
# The quota ledger counts real rows, so an instance whose existing corpus
# already exceeds a limit blocks that owner from uploading entirely. Raise
# before first start on an instance with a large existing dataset.
MAX_UPLOAD_FILES_PER_USER=5000
MAX_UPLOAD_BYTES_PER_USER_MB=3072
# The `lab` tier; each must be >= its contributor counterpart or the API refuses to start.
MAX_UPLOAD_FILES_PER_LAB_USER=20000
MAX_UPLOAD_BYTES_PER_LAB_USER_MB=51200
# Type: non-secret | Consumer: backend | Purpose: ClamAV upload scanning.
# `up` starts ClamAV (the `scanning` profile) unless this is false. Set false only as
# an accepted risk.
MALWARE_SCAN_ENABLED=true