Files
dev-notes/content/gateway-stack.md
2025-12-06 14:35:56 -06:00

310 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 Lets 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 hosts 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 machines 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 hosts own IP (192.168.2.9)**.
Use container names on the `proxy` network for same-host services.
### 7.3 Debugging Backend Connectivity
To simulate Traefiks 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, its 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