✨feature: Add gateway stack documentation
This commit is contained in:
309
content/gateway-stack.md
Normal file
309
content/gateway-stack.md
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
---
|
||||||
|
title: Gateway Documentation
|
||||||
|
section: docs
|
||||||
|
summary: Homelab Gateway — Traefik Reverse Proxy, Authelia SSO, LAN Routing, macvlan IP assignment, and Docker-managed services.
|
||||||
|
tags: [networking, traefik, authelia, infrastructure, docker, home-lab]
|
||||||
|
nav: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
## Homelab Gateway Stack (Traefik + Authelia)
|
||||||
|
|
||||||
|
This document describes the architecture and configuration of the homelab gateway stack — the system responsible for HTTPS termination, reverse proxying, SSO-protected internal services, LAN-to-LAN routing, and stable external exposure.
|
||||||
|
|
||||||
|
This documentation intentionally mirrors the SoloForge Gitea documentation format for consistency across the infrastructure stack.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
|
||||||
|
The Gateway Stack provides:
|
||||||
|
|
||||||
|
- **Reverse proxying via Traefik v3**
|
||||||
|
- **Authentication & SSO via Authelia v4**
|
||||||
|
- **Per-service routing with Docker labels or file-provider YAML**
|
||||||
|
- **macvlan-based static IP assignment (Traefik appears as its own LAN host)**
|
||||||
|
- **Secure exposure of internal services to the outside world**
|
||||||
|
- **ForwardAuth protection for otherwise unauthenticated apps**
|
||||||
|
- **Ability to proxy both Docker-based and remote LAN-based services**
|
||||||
|
|
||||||
|
This system replaces the previous Traefik + YAML editor stack and centralizes the “front door” of the homelab under a configuration that is fully self-documented, reproducible, and Git-tracked.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. System Layout
|
||||||
|
|
||||||
|
### 2.1 Host Machine
|
||||||
|
|
||||||
|
- Bare-metal machine (temporarily — will migrate back into Proxmox)
|
||||||
|
- Debian/Ubuntu-based environment
|
||||||
|
- Docker + Docker Compose v2+
|
||||||
|
- macvlan network configured so Traefik has a **dedicated LAN IP** (`192.168.2.253`)
|
||||||
|
|
||||||
|
### 2.2 Static Network Assignment (macvlan)
|
||||||
|
|
||||||
|
Traefik receives its own IP on the LAN:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker network create -d macvlan \
|
||||||
|
--subnet=192.168.2.0/24 \
|
||||||
|
--gateway=192.168.2.1 \
|
||||||
|
-o parent=eth0 \
|
||||||
|
traefik_macvlan
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rationale:**
|
||||||
|
|
||||||
|
- Makes Traefik behave like a true router on the network
|
||||||
|
- Allows the router to port-forward directly to Traefik instead of the host
|
||||||
|
- Eliminates host→Traefik conflicts
|
||||||
|
- Clean separation once this stack eventually lives in a VM or LXC again
|
||||||
|
|
||||||
|
### 2.3 Directory Structure
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/gateway/
|
||||||
|
├── traefik/
|
||||||
|
│ ├── traefik.yml # Static config
|
||||||
|
│ ├── config/ # File provider configs (GUI writes here)
|
||||||
|
│ ├── cert/ # ACME cert store
|
||||||
|
│ └── logs/ # Traefik logs
|
||||||
|
├── authelia/
|
||||||
|
│ ├── config/ # Authelia configuration.yml + users file
|
||||||
|
│ ├── secrets/ # Env-based secrets, if used
|
||||||
|
│ └── logs/ # Authelia logs
|
||||||
|
├── traefik-gui/
|
||||||
|
│ └── db/ # GUI internal sqlite db
|
||||||
|
└── traefik-stack.yml # Main stack
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Traefik Deployment
|
||||||
|
|
||||||
|
### 3.1 Traefik Service
|
||||||
|
|
||||||
|
Launched via Compose with two network attachments:
|
||||||
|
|
||||||
|
- `traefik_macvlan` → gives Traefik its LAN IP
|
||||||
|
- `proxy` → internal Docker network for app connectivity
|
||||||
|
|
||||||
|
Traefik is responsible for:
|
||||||
|
|
||||||
|
- HTTPS certificates via Let’s Encrypt (DNS-01 with Cloudflare)
|
||||||
|
- Routing per-service via hostnames
|
||||||
|
- Applying Authelia ForwardAuth checks
|
||||||
|
- Proxying internal Docker services and remote LAN machines
|
||||||
|
|
||||||
|
### 3.2 File Provider
|
||||||
|
|
||||||
|
The file provider watches:
|
||||||
|
|
||||||
|
`/traefik/config/`
|
||||||
|
|
||||||
|
Traefik GUI writes dynamic route definitions into this folder.
|
||||||
|
|
||||||
|
### 3.3 Docker Provider
|
||||||
|
|
||||||
|
Configured with:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
providers:
|
||||||
|
docker:
|
||||||
|
endpoint: "unix:///var/run/docker.sock"
|
||||||
|
exposedByDefault: false
|
||||||
|
network: proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
Allows Traefik to auto-discover containers with labels on the `proxy` network.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Authelia (SSO / Authentication)
|
||||||
|
|
||||||
|
### 4.1 Purpose
|
||||||
|
|
||||||
|
Authelia handles:
|
||||||
|
|
||||||
|
- Single-sign-on for internal apps
|
||||||
|
- Multi-factor auth (optional)
|
||||||
|
- Protecting services with ForwardAuth (even those without native authentication)
|
||||||
|
- Login portal at `auth.keithsolomon.net`
|
||||||
|
|
||||||
|
### 4.2 Configuration Notes
|
||||||
|
|
||||||
|
- Config lives at `/authelia/config/configuration.yml`
|
||||||
|
- Secrets (session, storage encryption, reset-password JWT) supplied via environment variables
|
||||||
|
- SMTP notifier is required — missing credentials cause Authelia to crash-loop
|
||||||
|
- Logging set to stdout during debugging, file logging available once stable
|
||||||
|
|
||||||
|
### 4.3 ForwardAuth Middleware
|
||||||
|
|
||||||
|
Exposed to Traefik via labels:
|
||||||
|
|
||||||
|
`traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth`
|
||||||
|
|
||||||
|
Any protected service adds:
|
||||||
|
|
||||||
|
`traefik.http.routers.<service>.middlewares=authelia@docker`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. LAN Services & Routing
|
||||||
|
|
||||||
|
### 5.1 Dockerized Services (local to gateway)
|
||||||
|
|
||||||
|
Containers running on the same host as Traefik should:
|
||||||
|
|
||||||
|
1. Join the `proxy` network
|
||||||
|
2. Use Traefik Docker labels
|
||||||
|
3. NOT be accessed via the host IP (192.168.2.9) when Traefik is on macvlan
|
||||||
|
- macvlan cannot reliably reach the host’s bridge interfaces
|
||||||
|
|
||||||
|
Example (Sonarr):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.http.routers.sonarr.rule=Host(`sonarr.keithsolomon.net`)"
|
||||||
|
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
|
||||||
|
```
|
||||||
|
|
||||||
|
Traefik will connect to `http://sonarr:8989` over the internal Docker network.
|
||||||
|
|
||||||
|
### 5.2 Remote LAN Services (other machines)
|
||||||
|
|
||||||
|
These should be added via the Traefik GUI (file provider), using the machine’s actual LAN IP:
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
docs:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://192.168.2.51:8083"
|
||||||
|
```
|
||||||
|
|
||||||
|
These are not affected by the macvlan limitation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Gateway Compose Stack
|
||||||
|
|
||||||
|
**Services included:**
|
||||||
|
|
||||||
|
- traefik
|
||||||
|
- authelia
|
||||||
|
- traefik-gui
|
||||||
|
- eventually all internal homelab UIs
|
||||||
|
|
||||||
|
**Networks:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
traefik_macvlan:
|
||||||
|
external: true
|
||||||
|
proxy:
|
||||||
|
name: proxy
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important: .env File**
|
||||||
|
|
||||||
|
Stores secrets such as Authelia session keys and SMTP passwords. Generate strong random hex values for the secrets using `openssl rand -hex 64`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
AUTHELIA_SESSION_SECRET=<hex>
|
||||||
|
AUTHELIA_STORAGE_ENCRYPTION_KEY=<hex>
|
||||||
|
AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET=<hex>
|
||||||
|
AUTHELIA_NOTIFIER_SMTP_PASSWORD=<app-password>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Operational Notes
|
||||||
|
|
||||||
|
### 7.1 Authelia Startup Failures
|
||||||
|
|
||||||
|
Authelia will crash-loop if:
|
||||||
|
|
||||||
|
- SMTP notifier missing password
|
||||||
|
- storage encryption key missing
|
||||||
|
- identity_validation.reset_password.jwt_secret missing
|
||||||
|
- configuration.yml malformed
|
||||||
|
|
||||||
|
Always check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs Authelia
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 macvlan Gotcha (Critical)
|
||||||
|
|
||||||
|
Traefik on macvlan **cannot reach the host’s own IP (192.168.2.9)**.
|
||||||
|
Use container names on the `proxy` network for same-host services.
|
||||||
|
|
||||||
|
### 7.3 Debugging Backend Connectivity
|
||||||
|
|
||||||
|
To simulate Traefik’s point of view:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it --network=proxy alpine sh
|
||||||
|
apk add curl
|
||||||
|
curl -v http://sonarr:8989
|
||||||
|
curl -v http://192.168.2.51:8083
|
||||||
|
```
|
||||||
|
|
||||||
|
If container → hostIP fails, but container → container works, it’s macvlan isolation.
|
||||||
|
|
||||||
|
### 7.4 Traefik Dashboard
|
||||||
|
|
||||||
|
Available at `https://tfk.keithsolomon.net`
|
||||||
|
|
||||||
|
Protected by Authelia.
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
- Routers → status, errors, middlewares
|
||||||
|
- Services → backend URLs
|
||||||
|
- Middlewares → ensure authelia@docker exists
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Future Improvements
|
||||||
|
|
||||||
|
- Migrate gateway stack into Proxmox VM/LXC
|
||||||
|
- Replace Traefik-GUI with a cleaner UI (or maintain YAML by hand)
|
||||||
|
- Add Prometheus metrics for request/latency monitoring
|
||||||
|
- Add fail2ban or rate-limiting middleware
|
||||||
|
- Add OIDC provider configuration to Authelia for full single sign-on
|
||||||
|
- Automate propagation of routes from remote hosts (pull or push model)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TL;DR Cheat Sheet
|
||||||
|
|
||||||
|
**Traefik not routing?**
|
||||||
|
|
||||||
|
- → Check router → check service → check backend URL
|
||||||
|
- → If backend is on the same machine: use container name, not host IP
|
||||||
|
|
||||||
|
**Authelia crash-loop?**
|
||||||
|
|
||||||
|
- → Missing SMTP password
|
||||||
|
- → Missing storage/session/jwt secrets
|
||||||
|
- → Look inside /authelia/logs/authelia.log
|
||||||
|
|
||||||
|
**Adding a remote LAN service?**
|
||||||
|
|
||||||
|
- → Use Traefik GUI
|
||||||
|
- → Backend = `http://192.168.2.X:PORT`
|
||||||
|
- → Protect via Authelia middleware as needed
|
||||||
|
|
||||||
|
**Adding a local Docker service?**
|
||||||
|
|
||||||
|
- → Put it on the `proxy` network
|
||||||
|
- → Add Traefik labels
|
||||||
|
- → Use `loadbalancer.server.port`, not host IP
|
||||||
|
- → Do NOT use `192.168.2.9` when Traefik is on macvlan
|
||||||
Reference in New Issue
Block a user