Edge Stack Guide
The edge stack owns the public reverse proxy and the admin/monitoring entrypoints.
The active Swarm edge stack contains Traefik and Kener. Portainer is an independently scalable administration panel; the retained Compose layout below still keeps it beside the edge services for rollback compatibility.
Source Of Truth
-
Active Swarm:
swarm/stacks/edge/{traefik,kener}.yml, assembled byswarm/scripts/edge/edge.{sh,bat}asedge -
Active Portainer panel:
swarm/stacks/panels/portainer.yml, assembled byswarm/scripts/panels/panels.{sh,bat}aspanel -
Compose files:
runtime/stacks/infrastructure/edge/docker-compose.traefik.ymlruntime/stacks/infrastructure/edge/docker-compose.portainer.ymlruntime/stacks/infrastructure/edge/docker-compose.kener.yml
-
VPS env files:
runtime/environments/vps/infrastructure/edge/traefik/.envruntime/environments/vps/infrastructure/edge/portainer/.envruntime/environments/vps/infrastructure/edge/kener/.env
-
Dev env templates:
runtime/environments/dev/infrastructure/edge/{traefik,portainer,kener}/*.dev.env
-
Launchers:
runtime/scripts/infrastructure/edge-traefik.{sh,bat}runtime/scripts/infrastructure/edge-portainer.{sh,bat}runtime/scripts/infrastructure/edge-kener.{sh,bat}
Dependencies
- Docker external network:
proxy - Docker external network:
platformfor Kener Redis connectivity - Host path:
/var/lib/traefik/letsencrypt/acme.json - Host path:
/var/lib/traefik/registry-auth/registry.htpasswd - Host path:
/var/lib/traefik/dynamic— dynamic config directory, installed byoperations/traefik/install-dynamic-config.sh - Host path:
/var/log/traefik— access log destination, rotated by/etc/logrotate.d/traefik(7 days,copytruncate)
Required Variables
Traefik
LETSENCRYPT_EMAILNETBIRD_ALLOWED_CIDRSADMIN_BASIC_AUTH
TRAEFIK_DASHBOARD_HOST was removed on 2026-08-15 — see Dashboard below.
Portainer
PORTAINER_HOST
Kener
KENER_HOSTKENER_ORIGINKENER_SECRET_KEYKENER_REDIS_URLSMTP_HOSTSMTP_PORTSMTP_USERSMTP_PASSWORDSMTP_FROM_EMAILSMTP_SECURE
Step-By-Step
docker network create proxy || true
docker network create platform || true
sudo mkdir -p /var/lib/traefik/letsencrypt
sudo touch /var/lib/traefik/letsencrypt/acme.json
sudo chmod 600 /var/lib/traefik/letsencrypt/acme.json
sudo mkdir -p /var/lib/traefik/registry-auth
sudo touch /var/lib/traefik/registry-auth/registry.htpasswd
sudo chmod 600 /var/lib/traefik/registry-auth/registry.htpasswdDeploy Traefik and Portainer first:
./runtime/scripts/infrastructure/edge-traefik.sh up
./runtime/scripts/infrastructure/edge-portainer.sh upDeploy Kener after the platform stack is up and Redis is reachable:
./runtime/scripts/infrastructure/edge-kener.sh upRaw compose equivalents:
docker compose --env-file runtime/environments/vps/infrastructure/edge/traefik/.env -f runtime/stacks/infrastructure/edge/docker-compose.traefik.yml up -d
docker compose --env-file runtime/environments/vps/infrastructure/edge/portainer/.env -f runtime/stacks/infrastructure/edge/docker-compose.portainer.yml up -d
docker compose --env-file runtime/environments/vps/infrastructure/edge/kener/.env -f runtime/stacks/infrastructure/edge/docker-compose.kener.yml up -dValidation
./runtime/scripts/infrastructure/edge-traefik.sh ps
./runtime/scripts/infrastructure/edge-portainer.sh ps
./runtime/scripts/infrastructure/edge-kener.sh ps
curl -Ik https://traefik-manager.perspective-v.com
curl -Ik https://portainer.perspective-v.com
curl -Ik https://kener.perspective-v.com
curl -Ik https://kener.perspective-v.com/healthcheckExpected behavior:
traefik-manager.perspective-v.comis NetBird-only and uses Traefik Manager's own login.portainer.perspective-v.comis NetBird-only and uses Portainer login.kener.perspective-v.comis public and uses Kener login.
Dashboard
Traefik's built-in dashboard was disabled on 2026-08-15 (api.dashboard: false) and
replaced by Traefik Manager at
https://traefik-manager.perspective-v.com.
traefik.perspective-v.com now returns 404 and its DNS record should be retired.
The API stays on (api.insecure: true), bound to :8080 inside the container only — it
has no ports: entry, so it is reachable from the proxy overlay and nowhere else. Traefik
Manager reads live routers, services and health from it.
Traefik itself carries no traefik.enable label. Setting one without a loadbalancer port
aborts the entire swarm provider and 404s every site — see the operations README before
adding labels to this service.
Access logging
Enabled 2026-08-15, writing to /var/log/traefik/access.log (previously stdout only) so
Traefik Manager can stream it.
All request and response headers are dropped (fields.headers.defaultMode: drop) — without
that, Authorization and Cookie values are logged verbatim. Traefik cannot redact query
strings, and this estate puts JWTs there (/notifications/hub?access_token=eyJ...), so log
lines remain credential-bearing. Retention is therefore capped at 7 compressed days and the
file is root-only. Do not lengthen retention without revisiting that.