# traefik — ОСК reverse proxy / SNI router Replaces **nginx-proxy-manager** on serverweb. One `:443` entrypoint that does **both**: - **TLS pass-through (Layer 4)** for the Windows services that use Windows-Integrated auth — TLS terminates at the backend, native Kerberos/NTLM/Negotiate is preserved (NPM/openresty cannot do this): - `workfolders.osk.team` → serverfile `192.168.0.11:443` (Work Folders) - `mail.osk.team`, `autodiscover.osk.team` → servermail `192.168.0.6:443` (Exchange 2019) - `kdcproxy.osk.team` → serverwsus `192.168.0.7:443` (KDC proxy) - **TLS termination + Let's Encrypt** for the web dashboards: - `start.osk.team` (flame), `portainer.osk.team`, `traefik.osk.team` (dashboard) ## Files | File | Purpose | |------|---------| | `docker-compose.yaml` | Traefik v3 service, binds 80/443, mounts config + acme | | `traefik.yml` | static config (entrypoints, providers, ACME) | | `dynamic/passthrough.yml` | the TCP SNI-passthrough routers → Windows hosts | | `dynamic/web.yml` | HTTP routers (dashboards) + dashboard basic-auth | Config files (`traefik.yml`, `dynamic/`) are the source of truth in git, but must be **placed on the host** at `/mnt/containers/traefik/container-data/` and mounted by **absolute path**. Portainer GitOps runs compose with paths relative to its own container (`/data/compose//…`), which the Docker daemon can't resolve — so relative `./` bind mounts silently become empty dirs (`is a directory` crash loop). Keep the host copies in sync with this repo; Traefik's `watch: true` still hot-reloads `dynamic/` when the host files change. `acme.json` is **not** in git (private keys) and persists on the host. ## One-time host prep (serverweb) ```bash mkdir -p /mnt/containers/traefik/container-data/acme touch /mnt/containers/traefik/container-data/acme/acme.json chmod 600 /mnt/containers/traefik/container-data/acme/acme.json mkdir -p /mnt/containers/traefik/container-data/dynamic ``` Then copy the config from this repo onto the host (re-copy whenever they change): ```bash scp traefik.yml root@serverweb:/mnt/containers/traefik/container-data/traefik.yml scp dynamic/*.yml root@serverweb:/mnt/containers/traefik/container-data/dynamic/ ``` ## Before deploying — edit 1. `traefik.yml`: set the real ACME `email`. 2. `dynamic/web.yml`: set a real `dash-auth` hash (`htpasswd -nbB admin 'pass'`), and confirm the portainer backend (add portainer to `reverseproxy-nw`, or point at `https://192.168.0.8:9443`). ## Deploy (Portainer GitOps) - Decommission NPM first (it owns 80/443): stop/remove the `nginx-proxy-manager` stack. **Do not** delete its data yet (rollback insurance). - Add a new Portainer **Git** stack, compose path `traefik/docker-compose.yaml`, same repo. Deploy. - Test while the edge still points 443 → serverfile: from inside the LAN, hit each SNI name against serverweb and confirm routing/cert. - **Flip the edge** last: - `TCP/80 → serverweb 192.168.0.8` (ACME http-01 + OWA http→https) - `TCP/443 → serverweb 192.168.0.8` (was → serverfile) - `UDP/443 → serverfile 192.168.0.11` (SMB over QUIC — unchanged, bypasses Traefik) ## Recommended consolidation Once Traefik fronts 443, **retire the `kdcproxy` `:8443` hack**: route `kdcproxy.osk.team` through Traefik on 443 (passthrough above) and revert the client GPO `KdcProxy\ProxyServers\CORP.LOCAL` back to `` (no port). Then the edge `TCP/8443` forward can be removed. ## Caveats - **SNI required.** Passthrough routes only by SNI; any client not sending SNI can't be routed (all modern Outlook/ActiveSync/Work Folders do send it). - **Passthrough backends keep their own certs.** Traefik's LE only covers the dashboards it terminates — **serverfile's Work Folders LE cert still renews on serverfile** (the Sept-3 expiry is unchanged), and Exchange/KDC-proxy keep theirs. - **Exchange cert** on servermail must cover `mail.osk.team` + `autodiscover.osk.team` (and any other published names). - **QUIC** stays a direct edge forward to serverfile; Traefik does not touch UDP/443. - The dashboards' LE certs need public `:80` reachability for http-01. If they are internal-only, use a DNS-01 challenge or a default cert instead.