Configurer auth ZeroTrust HTTP (Authelia & Nginx)
Quand j’ai commencé l’auto-hébergement, j’ai rapidement fait face à un dilemme de sécurité : comment accéder à mes services (Home Assistant, *Arrs, Nextcloud) depuis l’extérieur sans ouvrir mon réseau domestique aux quatre vents ?
La méthode classique consiste à ouvrir les ports 80/443 de sa box. J’ai toujours refusé cette approche, car elle exposerait mon IP résidentielle (et donc ma localisation) et augmenterait considérablement ma surface d’attaque.
Dans cet article, je détaille l’architecture que j’ai mise en place : aucun port entrant sur le routeur domestique. J’utilise deux VPS publics séparés — un pour le reverse proxy (Nginx) et un autre dédié à l’authentification (Authelia) — puis je proxifie le trafic via un tunnel WireGuard vers mon LAN. Séparer l’authentification du proxy permet d’isoler la surface d’attaque : si le VPS proxy est compromis, l’attaquant n’a pas accès au service d’authentification.
Architecture cible
- VPS Proxy : héberge Nginx (reverse proxy + TLS) — point d’entrée public.
- VPS Auth : héberge Authelia (authentification / SSO / 2FA) — machine séparée.
- Tunnel VPN (WireGuard) : relie les trois machines entre elles (mesh).
- LAN (privé) : les services (Home Assistant, Sonarr, etc.) tournent ici ; le serveur domestique initie la connexion VPN.
| Machine | IP publique | IP WireGuard | Rôle |
|---|---|---|---|
| VPS Proxy | <IP_VPS_PROXY> | 10.100.0.1 | Nginx, TLS (Let’s Encrypt) |
| VPS Auth | <IP_VPS_AUTH> | 10.100.0.3 | Authelia (Docker) |
| Serveur domestique | aucune (derrière NAT) | 10.100.0.2 | Services (Home Assistant, Sonarr…) |
graph TB
subgraph "Internet"
CLIENT["🌐 Client<br/>navigateur"]
end
subgraph "VPS Proxy"
NGINX["⚙️ Nginx<br/>TLS + Reverse Proxy<br/>10.100.0.1"]
end
subgraph "VPS Auth"
AUTHELIA["🔐 Authelia<br/>SSO / 2FA<br/>10.100.0.3"]
end
subgraph "LAN Domestique (privé)"
HOME["🏠 Serveur domestique<br/>10.100.0.2"]
HA["Home Assistant"]
SONARR["Sonarr"]
NEXT["Nextcloud"]
end
CLIENT -->|"HTTPS (443)"| NGINX
NGINX <-->|"WireGuard<br/>auth_request"| AUTHELIA
NGINX -->|"WireGuard<br/>proxy_pass"| HOME
HOME --- HA
HOME --- SONARR
HOME --- NEXT
style CLIENT fill:#90CAF9,color:#000
style NGINX fill:#FF9800,color:#fff
style AUTHELIA fill:#9C27B0,color:#fff
style HOME fill:#4CAF50,color:#fff1. Tunnel VPN (la colonne vertébrale)
J’ai choisi WireGuard pour sa simplicité et ses performances. Voici des exemples de configuration.
Le tunnel WireGuard relie les machines en étoile. Le VPS Proxy est le seul point central : il est connecté au VPS Auth et au serveur domestique. Le VPS Auth, lui, n’a aucun accès au LAN — il ne communique qu’avec le VPS Proxy.
graph LR
subgraph "VPS Auth"
AUTH["10.100.0.3<br/>🔐 Authelia"]
end
subgraph "VPS Proxy (hub)"
PROXY["10.100.0.1<br/>⚙️ Nginx"]
end
subgraph "LAN"
HOME["10.100.0.2<br/>🏠 Services"]
end
AUTH <-->|"WireGuard<br/>AllowedIPs: 10.100.0.1/32"| PROXY
PROXY <-->|"WireGuard<br/>AllowedIPs: 10.100.0.1/32"| HOME
AUTH x--x|"❌ Aucun accès"| HOME
style PROXY fill:#FF9800,color:#fff
style AUTH fill:#9C27B0,color:#fff
style HOME fill:#4CAF50,color:#fffSur le VPS Proxy (10.100.0.1 — serveur WireGuard)
Fichier /etc/wireguard/wg0.conf :
[Interface]Address = 10.100.0.1/24ListenPort = 51820PrivateKey = <VPS_PROXY_PRIVATE_KEY>
# Forwarding entre les peersPostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEPostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Serveur domestique[Peer]PublicKey = <HOME_PUBLIC_KEY>AllowedIPs = 10.100.0.2/32
# VPS Auth (Authelia)[Peer]PublicKey = <VPS_AUTH_PUBLIC_KEY>AllowedIPs = 10.100.0.3/32Sur le VPS Auth (10.100.0.3 — Authelia)
Fichier /etc/wireguard/wg0.conf :
[Interface]Address = 10.100.0.3/24PrivateKey = <VPS_AUTH_PRIVATE_KEY>
[Peer]PublicKey = <VPS_PROXY_PUBLIC_KEY>Endpoint = <IP_VPS_PROXY>:51820AllowedIPs = 10.100.0.1/32PersistentKeepalive = 25Note :
AllowedIPsest volontairement restreint à10.100.0.1/32. Le VPS Auth ne doit pas pouvoir joindre le serveur domestique (10.100.0.2). Seul le VPS Proxy a accès au LAN.
Sur le serveur domestique (10.100.0.2 — services)
Fichier /etc/wireguard/wg0.conf :
[Interface]Address = 10.100.0.2/24PrivateKey = <HOME_PRIVATE_KEY>
[Peer]PublicKey = <VPS_PROXY_PUBLIC_KEY>Endpoint = <IP_VPS_PROXY>:51820AllowedIPs = 10.100.0.1/32PersistentKeepalive = 25Après activation sur les trois machines, vérifiez la connectivité :
# Depuis le VPS Proxy : ping les deux peersping -c 3 10.100.0.2 # serveur domestiqueping -c 3 10.100.0.3 # VPS Auth2. Authelia (authentification / SSO)
Authelia sert de gardien : il valide les sessions et gère le 2FA. Je l’ai déployé en Docker sur un VPS dédié (10.100.0.3), séparé du reverse proxy. Ce VPS Auth n’a pas besoin d’être exposé publiquement sur le port 9091 : Nginx l’atteint via le tunnel WireGuard.
Arborescence recommandée
/opt/authelia/├── config/│ └── configuration.yml└── docker-compose.ymlExemple docker-compose.yml
version: '3.8'services: authelia: image: authelia/authelia container_name: authelia volumes: - ./config:/config ports: - 9091:9091 restart: always environment: - TZ=Europe/ParisExtrait de configuration.yml (accès)
# ... JWT, session, storage, notifier ...access_control: default_policy: deny rules: # Autoriser l'accès à Authelia lui-même - domain: 'auth.mon-domaine.com' policy: bypass
# Protéger tous les services du domaine avec 2FA - domain: '*.mon-domaine.com' policy: two_factor3. Nginx (le chef d’orchestre)
Nginx tourne sur le VPS Proxy (10.100.0.1). Il gère TLS (Let’s Encrypt), interroge Authelia à distance via WireGuard (10.100.0.3:9091) grâce à auth_request, puis proxifie le trafic vers le serveur domestique (10.100.0.2).
Snippet Authelia (/etc/nginx/snippets/authelia.conf)
# Endpoint interne pour la vérificationlocation /authelia { internal; proxy_pass http://10.100.0.3:9091/api/verify; proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Content-Length ""; proxy_pass_request_body off;}
# Redirection vers le portail d'authentification si non autoriséerror_page 401 =302 https://auth.mon-domaine.com/?rd=$target_url;Exemple de configuration d’un site (Sonarr)
Fichier /etc/nginx/sites-available/sonarr.mon-domaine.com :
server { listen 443 ssl http2; server_name sonarr.mon-domaine.com;
# Certificat (géré par Certbot) ssl_certificate /etc/letsencrypt/live/mon-domaine.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mon-domaine.com/privkey.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# --- Authentification via Authelia --- include /etc/nginx/snippets/authelia.conf; auth_request /authelia;
auth_request_set $user $upstream_http_remote_user; auth_request_set $groups $upstream_http_remote_groups; proxy_set_header Remote-User $user; proxy_set_header Remote-Groups $groups;
set $target_url $scheme://$http_host$request_uri;
location / { # Proxy vers le service sur le LAN via WireGuard proxy_pass http://10.100.0.2:8989;
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}Flux de requête (résumé)
sequenceDiagram
participant C as 🌐 Client
participant N as ⚙️ VPS Proxy<br/>(Nginx)
participant A as 🔐 VPS Auth<br/>(Authelia)
participant H as 🏠 Serveur<br/>domestique
C->>N: HTTPS sonarr.mon-domaine.com
N->>A: auth_request via WireGuard (10.100.0.3)
alt Non authentifié
A-->>N: 401 Unauthorized
N-->>C: 302 Redirect → auth.mon-domaine.com
C->>N: Accès portail Authelia
N->>A: proxy_pass vers Authelia
A-->>C: Page de login (2FA)
C->>A: Credentials + TOTP
A-->>C: Cookie de session validé
C->>N: Requête initiale (avec cookie)
N->>A: auth_request (re-vérification)
end
A-->>N: 200 OK (authentifié)
N->>H: proxy_pass via WireGuard (10.100.0.2)
H-->>N: Réponse du service (Sonarr)
N-->>C: Réponse HTTPS- Le client DNS résout
sonarr.mon-domaine.comvers l’IP publique du VPS Proxy. - Nginx (VPS Proxy) reçoit la requête et appelle Authelia via WireGuard (
auth_request→10.100.0.3:9091). - Si l’utilisateur n’est pas authentifié → redirection vers
auth.mon-domaine.com(qui pointe aussi vers le VPS Proxy, qui proxifie vers10.100.0.3). - L’utilisateur s’authentifie (2FA) auprès d’Authelia sur le VPS Auth.
- Une fois authentifié → Nginx proxifie la requête vers
10.100.0.2(serveur domestique via WireGuard). - Le serveur domestique reçoit la requête et la transmet au service local (ex. Sonarr sur
localhost:8989).
Avantages de cette approche
- Isolation : le réseau domestique reste complètement privé, aucun port entrant.
- Séparation des responsabilités : le proxy et l’authentification sont sur des machines distinctes. Compromettre le VPS Proxy ne donne pas accès aux credentials Authelia.
- Contrôle fin des accès via Authelia (2FA, règles par sous-domaine, groupes d’utilisateurs).
- Portable : le serveur domestique initie la connexion VPN (fonctionne derrière CGNAT ou réseaux mobiles).
- Résilience : chaque composant peut être mis à jour ou redémarré indépendamment.