Aller au contenu Skip to main content

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.
MachineIP publiqueIP WireGuardRôle
VPS Proxy<IP_VPS_PROXY>10.100.0.1Nginx, TLS (Let’s Encrypt)
VPS Auth<IP_VPS_AUTH>10.100.0.3Authelia (Docker)
Serveur domestiqueaucune (derrière NAT)10.100.0.2Services (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:#fff

1. 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:#fff

Sur le VPS Proxy (10.100.0.1 — serveur WireGuard)

Fichier /etc/wireguard/wg0.conf :

[Interface]
Address = 10.100.0.1/24
ListenPort = 51820
PrivateKey = <VPS_PROXY_PRIVATE_KEY>
# Forwarding entre les peers
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = 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/32

Sur le VPS Auth (10.100.0.3 — Authelia)

Fichier /etc/wireguard/wg0.conf :

[Interface]
Address = 10.100.0.3/24
PrivateKey = <VPS_AUTH_PRIVATE_KEY>
[Peer]
PublicKey = <VPS_PROXY_PUBLIC_KEY>
Endpoint = <IP_VPS_PROXY>:51820
AllowedIPs = 10.100.0.1/32
PersistentKeepalive = 25

Note : AllowedIPs est 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/24
PrivateKey = <HOME_PRIVATE_KEY>
[Peer]
PublicKey = <VPS_PROXY_PUBLIC_KEY>
Endpoint = <IP_VPS_PROXY>:51820
AllowedIPs = 10.100.0.1/32
PersistentKeepalive = 25

Après activation sur les trois machines, vérifiez la connectivité :

Fenêtre de terminal
# Depuis le VPS Proxy : ping les deux peers
ping -c 3 10.100.0.2 # serveur domestique
ping -c 3 10.100.0.3 # VPS Auth

2. 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.yml

Exemple 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/Paris

Extrait 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_factor

3. 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érification
location /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
  1. Le client DNS résout sonarr.mon-domaine.com vers l’IP publique du VPS Proxy.
  2. Nginx (VPS Proxy) reçoit la requête et appelle Authelia via WireGuard (auth_request10.100.0.3:9091).
  3. Si l’utilisateur n’est pas authentifié → redirection vers auth.mon-domaine.com (qui pointe aussi vers le VPS Proxy, qui proxifie vers 10.100.0.3).
  4. L’utilisateur s’authentifie (2FA) auprès d’Authelia sur le VPS Auth.
  5. Une fois authentifié → Nginx proxifie la requête vers 10.100.0.2 (serveur domestique via WireGuard).
  6. 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.