wg-easy + Traefik docker-compose stack (Phase 1) plus a stdlib-only control-plane API for box registration, WireGuard peer provisioning via wg-easy, and per-box route publish/unpublish backed by Traefik's file provider (Phase 2, single-tenant mode). SQLite holds accounts/boxes/routes so a later multi-tenant shared instance is the same schema with more rows, not a reshape. wg-easy's actual REST API was verified against its source rather than assumed: it has no bearer-token auth (session-cookie login via POST /api/auth/password) and no way to accept an externally-generated public key (it always mints the keypair itself, private key included) — both corrected from the original plan during implementation. |
||
|---|---|---|
| control_plane | ||
| tests | ||
| traefik | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yaml | ||
| pyproject.toml | ||
| README.md | ||
furtka-gateway
WireGuard (wg-easy) + Traefik reverse-proxy that lets a Furtka box — typically sitting behind NAT/CGNAT with no public IP — expose individual apps to the internet under a real domain with automatic TLS.
A Furtka box becomes a WireGuard peer of this gateway. The gateway's Traefik
reverse-proxies public HTTPS traffic over that tunnel to whichever apps the
box owner has explicitly published. Only apps whose Furtka manifest.json
declares internet.viable: true can be published at all, and publishing is
always an explicit per-app opt-in on the box side — the gateway never exposes
anything on its own.
Supports two deployment modes from the same codebase:
single— the common case: one person/operator runs this on their own VPS with their own domain's A/AAAA records pointed at it, for their own Furtka box(es).shared— one larger, multi-tenant instance (operated by the Furtka project) for people who don't want to run their own. Same schema, same code;singleis just the one-account case.
See docker-compose.yaml and control_plane/ for the moving parts. Status:
Phase 1 (scaffold) — wg-easy + Traefik + a stub control-plane exposing
only /healthz, enough to manually prove the wiring end-to-end before the
real control-plane (accounts/boxes/routes) lands.
Local dev
cp .env.example .env
# edit .env: set GATEWAY_PUBLIC_HOST to a real hostname you control (or a
# LAN-reachable IP for a first smoke test), and a PASSWORD_HASH for wg-easy
# (see https://github.com/wg-easy/wg-easy for how to generate one).
docker compose up -d
curl http://127.0.0.1:8090/healthz
Traefik's dashboard/API and wg-easy's own UI are intentionally not published
on a host port — reach them via docker compose exec / port-forwarding
during development. Neither should ever be reachable from the internet in a
real deployment; only the control-plane (8090, bound to 127.0.0.1) and
Traefik's 80/443 entrypoints are meant to be exposed.