############################################################ # Auto Tournament – Example .env # # Copy this file to `.env` at the repo root and adjust values. # The API reads `.env` via dotenv on startup. # # Docker Compose: The docker-compose.yml files use env_file to load # all variables from .env into the container automatically. ############################################################ ############################## # ---- Core server settings -- ############################## # Environment: development or production (optional; defaults to development) # NODE_ENV=development # API port (behind Caddy/Docker this is usually 3000) PORT=3000 # Signs sessions and sign-in cookies. Leave it empty and the API makes a # random one and keeps it in the data folder. To set your own: # openssl rand -base64 32 SESSION_SECRET= ############################## # ---- License terms --------- ############################## # Auto Tournament is free for non-commercial use under the PolyForm # Noncommercial License 1.0.0. Commercial use needs a license # (https://autotournament.gg/pricing); every game server counts. # # The first admin to sign in accepts the terms once in the browser: they pick # non-commercial or commercial use and type I AGREE. The admin pages open # after that. Players, public pages and running matches are never affected. # # For an install nobody clicks through (automation, CI), accept here instead. # Setting this means you have read the license and accept it, on behalf of # whoever runs this instance. It also accepts later versions of the terms, # so remove it if you want to review a change in the browser. # noncommercial — personal use, hobby, learning, events nobody earns from # commercial — you need a license; add the key below or in # Settings > License # AT_ACCEPT_LICENSE=noncommercial # Optional: your Auto Tournament license key (starts with ATL1.). Saved at # startup when it differs from the saved key, so this wins over a key pasted # in Settings > License. A missing or invalid key never blocks anything. # With a key, this server checks in with autotournament.gg once a day: the # key's id, a random instance id, the server count, the version and match # counts. Nothing is sent without a key. See Settings > License. # LICENSE_KEY= ######################## # ---- Database -------- ######################## # Option A: Single DATABASE_URL (preferred in Docker) # DATABASE_URL=postgresql://postgres:postgres@postgres:5432/auto_tournament # Option B: Individual DB settings (for local dev without DATABASE_URL) DB_HOST=127.0.0.1 DB_PORT=5432 DB_USER=postgres DB_PASSWORD=postgres DB_NAME=auto_tournament ############################################### # ---- Machine access (bots, scripts, CI) ----- ############################################### # API tokens let a machine call the admin API without a browser session — a # Discord bot, a cron job, a deploy script. Human admins keep using Steam/SSO; # these are only for integrations. # # Present a token as either header: # Authorization: Bearer # X-API-Token: # # Three variables decide scope: # API_TOKENS — full admin. Anything an admin can do, including # creating matches, starting tournaments and RCON. # API_TOKENS_READONLY — GET/HEAD/OPTIONS only. Enough for scoreboards, # brackets and match state. Prefer this one: most bots # never need to write. # API_TOKENS_INTEGRATOR — the integrations API only (/api/integrations/*), # e.g. an event website pushing its teams. The label # is the integrator's "source": its team externalIds # live under it, so keep it stable. docs/WEBHOOKS.md # # Format: comma- or space-separated entries, each `label:secret` or a bare # `secret`. The label only appears in logs, so you can tell which integration # made a call. Secrets are never logged. # # Generate one with: # openssl rand -hex 32 # # Minimum secret length is 16 characters; shorter entries are ignored with a # warning at startup. # # LEAVE THESE UNSET unless you actually have an integration. A token in # API_TOKENS is a full admin credential for your instance. # # Full guide, including a worked Discord bot: docs/API.md # # API_TOKENS=discord-bot:replace-with-openssl-rand-hex-32 # API_TOKENS_READONLY=scoreboard:replace-with-openssl-rand-hex-32 # API_TOKENS_INTEGRATOR=ntlan:replace-with-openssl-rand-hex-32 ############################## # ---- Game catalog ----------- ############################## # A fresh install has no games. The admin installs them from the catalog # (Modules page, or /welcome/games): game packs and signed code modules such # as CS2, from our GitHub or from the offline copy inside the image. # Where the catalog feed lives – optional (default: catalog.json in # Auto-Tournament/packs on GitHub) # CATALOG_URL=https://raw.githubusercontent.com/Auto-Tournament/packs/main/catalog.json # Never fetch the feed; offer only what the image carries (air-gapped LANs). # The CS2 module then also uses its bundled map list instead of maps.json – optional # CATALOG_OFFLINE=false # Install the image's game packs on first boot: "all" or a comma-separated # list of slugs – optional (default: none) # PREINSTALL_PACKS= # Extra Ed25519 public keys (base64, comma-separated) that may sign code # modules, for your own module builds – optional. Anyone who can set this can # already put code in DATA_DIR/modules, so it grants nothing new. # MODULE_TRUSTED_KEYS= # At boot, update modules installed from the catalog to the newer release the # image carries, within their major version – optional (default: true) # MODULE_AUTO_UPDATE=true # Whether something brings the app back when it exits (Docker's restart # policy), so the Modules page can offer "Restart now" – optional (default: # true inside the Docker image, false elsewhere) # AT_RESTART_SUPERVISED=true ############################### # ---- CS2 server integration - ############################### # Token used by CS2 servers to authenticate webhooks and match load requests. # This must match the token configured in MatchZy Enhanced on your game servers. # Example (simple random token): # SERVER_TOKEN=$(openssl rand -base64 24 | tr -d '=+/') SERVER_TOKEN=your-server-token-here # Accept game events that arrive with NO X-Auto-Tournament-Token — a migration shim. # # Event ingest (POST /api/events) used to be unauthenticated. Servers # that MAT configured send the token already, because the webhook config sets # `at_remote_log_header_key`/`_value` alongside the URL. A server set up by # hand, or by a much older MAT, may not — and the symptom is a match whose score # stops moving, which is a horrible thing to diagnose mid-tournament. # # Set this to true to buy time, reconnect your servers so they re-fetch # /api/servers/:id/bootstrap, then unset it. It only accepts a *missing* token, # never a wrong one — but while it is on, anyone who can reach this API can # forge match events. MAT warns about it on every boot. # # ALLOW_UNAUTHENTICATED_EVENTS=false # Webhook base URL for MatchZy Enhanced to send events to the API. # This should point to your API server (NOT the frontend dev server). # Examples: # - Local dev: http://localhost:3000 # - Production: http://your-server-ip:3069 or https://your-domain.com # If not set, auto-detects as http://localhost:{PORT} # API_BASE_URL=http://localhost:3000 # Days to keep the round backups Ready Up servers send (one per round, 10-60 KB # each, used for "restore to round N" and failover) after a match ends. # Live and recent matches keep every backup. 0 keeps them forever. # FLEET_BACKUP_RETENTION_DAYS=14 # Demos Ready Up servers stream over the fleet link while they record. # Largest demo accepted (bytes), stream rate per server (bytes/minute; the # socket budget of a demo-streaming server is raised by this much), and days # after which an unfinished stream is deleted. # FLEET_DEMO_MAX_BYTES=2147483648 # FLEET_DEMO_BYTES_PER_MINUTE=67108864 # FLEET_DEMO_STREAM_EXPIRE_DAYS=7 # Every fleet server's socket budget (bytes/minute). # FLEET_BYTES_PER_MINUTE=8388608 # How often the automatic scaler checks the Ready Up servers on csm machines # (milliseconds). 0 turns its timer off (the test suite does this; passes then # run only through POST /api/fleet/autoscale/run). Turn scaling itself on or # off on the Servers page. # FLEET_AUTOSCALE_INTERVAL_MS=15000 ###################################### # ---- Ready Up compatibility page ---- ###################################### # A public page at /compatibility showing whether the Ready Up plugin suite # works on the latest CS2 build, fed by the Ready Up CI. Off unless one of # these is set; almost every instance leaves both unset. docs/API.md has the # endpoints and the document format. # Token the Ready Up CI sends as `Authorization: Bearer ` to # POST /api/compat/events – optional. At least 16 characters; it grants that # one endpoint and nothing else. Generate one with: openssl rand -hex 32 # COMPAT_INGEST_TOKEN= # URL of a compat.json to poll every 5 minutes as a fallback to the push – # optional. A failed or invalid fetch keeps the last good result. # COMPAT_FEED_URL= ############################# # ---- Auth providers (SSO) - ############################# ## Shared auth settings # Public base URL of MAT frontend, used for OAuth redirects (Steam, Discord, etc.). # Required when you enable any auth provider. # IMPORTANT: # - Use http:// for local development (e.g., http://localhost:5173 for Vite dev, or :3069 for Docker) # - Use https:// for production (e.g., https://your-domain.com) # The secure cookie flag is automatically set based on this URL (https:// = secure cookies) FRONTEND_BASE_URL=http://localhost:3069 # # It is also the address handed to other machines: `csm link ` commands, # and the ws_url Ready Up servers and csm hosts connect to after enrolling # (https:// here -> wss://). A localhost value is ignored for that, and the # request's own address is used instead. A machine that reaches the platform on # a LAN address (192.168.x, 10.x, a .lan name...) is handed that address back, # so `csm link http://:3069 ...` keeps csm and its game servers on the # LAN while browsers use the public URL. # Behind your own reverse proxy (TLS terminator, Cloudflare Tunnel, NPM...), # the container's Caddy passes the proxy's X-Forwarded-Proto/-Host/-For on to # the API only when the proxy's address is trusted. Private ranges (Docker # networks, LAN) are trusted by default. If your proxy connects from a public # address, list it here (Caddy trusted_proxies syntax); otherwise the API sees # plain http and hands out ws:// fleet URLs, which csm refuses. # TRUSTED_PROXIES=private_ranges 203.0.113.10/32 ## First admin and sign-in # # Nothing here is needed to sign in. On a fresh install the server logs a # one-time setup code: # # [SETUP] Open https://your-domain/setup and enter this code: XXXX-XXXX-... # # (docker logs auto-tournament). /setup creates a local admin account # (username + password, optional two-step verification), then takes you to # Settings -> Sign-in, where you set up how players sign in: Steam, Discord, # Google, GitHub, Twitch. The code works once and expires after 24 hours; # restart the container for a new one while no admin exists. # # Locked out? docker exec auto-tournament reset-admin prints a code (1 hour) # that sets a new password for a local admin or creates one. # # Secrets saved in the UI are stored encrypted (AES-256-GCM) with a key derived # from SECRETS_KEY, or from SESSION_SECRET when SECRETS_KEY is unset. Changing # that value makes the saved secrets unreadable; enter them again afterwards. # SECRETS_KEY=a-long-random-string # # Upgrading from an install that set providers here? The variables below are # still read, once: at start-up each one fills its setting in the database if # that setting is empty, and the log says "[SETUP] imported X from # environment; you can remove it from .env". After that Settings -> Sign-in is # the source of truth and the variable is ignored (even if you clear the # setting in the UI). New installs do not need any of them. # # AUTH_STEAM_ENABLED, STEAM_API_KEY # AUTH_DISCORD_ENABLED, DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET # AUTH_GOOGLE_ENABLED, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET # AUTH_GITHUB_ENABLED, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET # AUTH_TWITCH_ENABLED, TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET # ADMIN_STEAM_IDS -> Settings -> Sign-in -> Admin Steam IDs (made admin at # every start; may also run raw console commands on # Ready Up servers) # ADMIN_EMAILS -> Settings -> Sign-in -> Admin emails (admin at sign-in # with a provider-verified address) ## OpenID Connect – optional # Any OpenID Connect server (Keycloak, Authentik, Authelia, Zitadel, Microsoft # Entra ID, Okta, ...). Set it up on Settings -> Sign-in -> OpenID Connect; these # are imported once at the first start, like the other providers: # AUTH_OIDC_ENABLED=true # OIDC_ISSUER_URL=https://sso.example.com/realms/auto-tournament # OIDC_CLIENT_ID=auto-tournament # OIDC_CLIENT_SECRET=your-client-secret # OIDC_LABEL=NTLAN # the button reads "Sign in with NTLAN" # # Redirect URI to register: FRONTEND_BASE_URL + /api/auth/oidc/callback # Sign-in providers do not grant admin on their own (except through the admin # emails). Someone new gets an account of their own when registration is open # (Settings -> Players & Access); admin access follows that account's admin flag. ############################ # ---- Logging & debug ---- ############################ # Log level: trace | debug | info | warn | error | fatal # When LOG_LEVEL=debug, DB verbose and DB values logging are enabled automatically. LOG_LEVEL=info # Set to false to disable per-request HTTP logs (still logs 4xx/5xx) – optional # LOG_HTTP_REQUESTS=true # Per-query DB logs (SQL, params, row counts). Auto-enabled when LOG_LEVEL=debug. # LOG_DB_VERBOSE=true # When DB verbose is on, also log result rows (redacted). Auto-enabled when LOG_LEVEL=debug. # Set LOG_DB_VALUES=false to disable even in debug. # LOG_DB_VALUES=false # Enable verbose RCON success logs – optional # LOG_RCON_VERBOSE=false ################################ # ---- CORS / WebSockets ------- ################################ # Allowed CORS origin(s) for Socket.IO and API (comma-separated) – optional # In Docker with Caddy, this is usually handled at the proxy layer. # CORS_ORIGIN=* ##################################### # ---- Optional: simulation mode ---- ##################################### # Allow enabling "simulation" features in production (advanced) – optional # AT_ENABLE_SIMULATION_IN_PROD=false ########################### # ---- Misc / tooling ---- ########################### # Playwright base URL for E2E tests – optional (defaults to http://localhost:3069 in tests) # PLAYWRIGHT_BASE_URL=http://localhost:3069 # Steam ID to use for the test admin in Playwright/tests/scripts – optional # TEST_STEAM_ID=76561198000000001