furtka-gateway/.env.example
Robert Syrnicki e240f071d5
Some checks failed
Build control-plane image / build-image (push) Has been cancelled
feat: ship control-plane standalone, bring your own Traefik/wg-easy
Restructure the deployment model: instead of bundling and owning its own
Traefik + wg-easy, the control-plane now plugs into a Traefik and wg-easy
the operator already runs (as sibling containers, or otherwise reachable).
This avoids duplicating infra self-hosters commonly already have, and
sidesteps having to run a second ACME/DNS setup entirely — the operator's
own Traefik already has a working cert resolver.

- New control_plane/wgeasy_v15.py: a wg-easy v15 REST client, verified live
  against a real running container (auth model, route shapes, and the new
  per-client PresharedKey all differ materially from v14's API). Threaded
  the preshared key through to the box side (furtka/wireguard.py in the
  furtka repo) so v15's handshake actually completes.
- GATEWAY_CERT_RESOLVER is now a real env var instead of a GATEWAY_MODE-
  derived hardcoded "le", so it can mirror whatever resolver name (if any)
  the operator's own Traefik already has configured.
- Root docker-compose.yaml/ops/deploy.sh: control-plane only now. deploy.sh
  asks how the operator's Traefik reaches it (same docker network, joined
  via `docker network connect`, or a separate host) instead of prompting
  for DNS-01 providers and port remaps single-parallel mode needed.
- single-parallel mode is retired outright — nothing needs it once
  furtka-gateway doesn't own a second Traefik/wg-easy to remap ports for.
- The old bundled stack (own Traefik+wg-easy, HTTP-01) moves to
  examples/starter-stack/ as the documented zero-infra on-ramp.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R3jVwAqESRjPdW9P9nvfem
2026-09-19 13:34:29 +02:00

96 lines
4.8 KiB
Text

# Filling this file in by hand? Run `ops/deploy.sh` instead — it prompts
# for the values below, generates the tokens, and renders
# traefik/dynamic/control-plane.yml from its tracked template. Read the
# README's Prerequisites checklist first either way.
# Tenancy switch only — "single" (one operator, the common case) or
# "shared" (multi-tenant, out of scope for most deployments). Has no
# effect on ports, certs, or infrastructure — that's all your own
# Traefik/wg-easy now, configured below.
GATEWAY_MODE=single
# YOUR wg-easy's admin API — reachable at whatever host:port makes sense
# for your setup. If it's a sibling container that joined the same docker
# network as this control-plane (see GATEWAY_TRAEFIK_NETWORK below), this
# is usually http://<its-container-name>:51821.
WG_EASY_URL=http://wg-easy:51821
# "14" or "15" — these are genuinely different, incompatible wg-easy APIs
# (see control_plane/wgeasy.py vs wgeasy_v15.py's module docstrings, each
# independently verified against a real running container). Check your
# wg-easy image's actual tag.
WG_EASY_API_VERSION=14
# v15 only: the admin user's username. v14 has no username concept — see
# WG_EASY_ADMIN_PASSWORD below, used alone in that case.
WG_EASY_ADMIN_USERNAME=
# PLAINTEXT password for wg-easy's admin API — never a hash, on either
# version. v14 sends this as a bare `Authorization` header (no username,
# no session — confirmed by reading the actual pinned image's source,
# which differs from what wg-easy's current docs describe). v15 sends it
# as HTTP Basic auth alongside WG_EASY_ADMIN_USERNAME.
WG_EASY_ADMIN_PASSWORD=
# v15 only: restricts new WireGuard clients to this subnet instead of
# v15's full-tunnel default (0.0.0.0/0, ::/0) — see wgeasy_v15.py's
# restrict_default_allowed_ips(), applied on every control-plane startup.
# Should match your wg-easy's actual WireGuard peer subnet.
GATEWAY_WG_ALLOWED_IPS=10.8.0.0/24
# Host directory YOUR Traefik's file provider already watches (or a new
# one you add as an *additional* providers.file directory in its static
# config — additive, doesn't touch your existing dynamic config). This
# gets bind-mounted into the control-plane container.
GATEWAY_DYNAMIC_DIR_HOST=./dynamic
# Your Traefik's certResolver name — mirrored into every route
# furtka-gateway publishes. Blank means no explicit resolver (`tls: {}`),
# trusting your Traefik to apply its own default cert automatically (e.g.
# a wildcard defaultGeneratedCert). Set this if your Traefik doesn't have
# a default and needs an explicit resolver named per-route.
GATEWAY_CERT_RESOLVER=
# Hostname a Furtka box actually reaches the control-plane API on — needs
# its own A/AAAA record pointing at wherever your Traefik is reachable.
# Not read by docker-compose itself; it's what ops/deploy.sh substitutes
# into traefik/dynamic/control-plane.yml.
GATEWAY_CONTROL_PLANE_HOST=gw.example.com
# Where the control-plane's own API is bound (docker-compose.yaml's port
# publish) and where your Traefik reaches it, respectively. Same value
# for the recommended same-docker-network setup (ops/deploy.sh sets both
# to furtka-gateway-control-plane:8090 automatically, with the bind
# staying loopback-only — see docker-compose.yaml's comment on why this
# is more robust than the compose *service* name "control-plane" once the
# network is joined after the fact via `docker network connect`).
# Different values only for a separate-host setup, where
# GATEWAY_CONTROL_PLANE_BIND must be widened beyond 127.0.0.1 — put real
# access control around that bind address, this file carries a WireGuard
# private key in its registration responses.
GATEWAY_CONTROL_PLANE_BIND=127.0.0.1:8090
GATEWAY_CONTROL_PLANE_TARGET=furtka-gateway-control-plane:8090
# Same-docker-network setup only (the recommended path — see the README's
# Prerequisites checklist): your Traefik's docker network name
# (`docker network ls` / `docker inspect <your-traefik-container>`).
# ops/deploy.sh runs `docker network connect` with this after bringing the
# stack up. Leave blank for a separate-host setup.
GATEWAY_TRAEFIK_NETWORK=
# The one box token a single-tenant deployment accepts at
# /v1/boxes/register, skipping full account/registration-token issuance.
# Generate with: openssl rand -hex 32
GATEWAY_BOX_TOKEN=
# Bearer token required to create accounts via POST /v1/accounts.
# Only meaningful once account endpoints exist (Phase 2+); harmless to set
# now. Generate with: openssl rand -hex 32
GATEWAY_ADMIN_TOKEN=
# Optional: override the control-plane image `docker stack deploy` pulls
# (Swarm ignores docker-compose.yaml's `build:` key — see README's Swarm
# caveats). Defaults to the `latest` tag CI publishes on every push to
# master; pin to a specific commit-sha tag for a reproducible deploy.
# Not read by plain `docker compose up`, which always builds locally.
GATEWAY_CONTROL_PLANE_IMAGE=