Reverse proxy
Point d'entrée unique du serveur : toutes les requêtes venant d'Internet passent par SWAG, qui les filtre avec CrowdSec et les authentifie avec Authelia avant de les transmettre aux services.
Composants
| Composant | Rôle |
|---|---|
| SWAG | Nginx, certificat wildcard Let's Encrypt (validation DNS DuckDNS), mods dashboard et bouncer CrowdSec |
| CrowdSec | Analyse les journaux de SWAG et de l'hôte, décide des blocages |
| Authelia | Authentification unique devant les services |
Les trois conteneurs sont sur le réseau Docker externe proxy, partagé avec tous les services publiés.
Stack
proxy:
external: true
services:
crowdsec:
image: docker.io/crowdsecurity/crowdsec:latest
container_name: crowdsec
environment:
- TZ=Europe/Paris
- GID=1000
- CUSTOM_HOSTNAME=<HOSTNAME>
- COLLECTIONS=crowdsecurity/nginx crowdsecurity/http-cve crowdsecurity/whitelist-good-actors
volumes:
- <APPDATA>/crowdsec/config:/etc/crowdsec
- <APPDATA>/crowdsec/data:/var/lib/crowdsec/data
- <APPDATA>/swag/config/log/nginx:/var/log/swag:ro
- <APPDATA>/swag/config/crowdsec/ban.html:/var/lib/crowdsec/lua/templates/ban.html:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/log:/var/log/host:ro
- <APPDATA>/Nextcloud/Data:/var/log/nextcloud-data:ro
networks: [proxy]
restart: unless-stopped
security_opt:
- no-new-privileges=true
swag:
image: lscr.io/linuxserver/swag:latest
container_name: swag
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
- "81:81"
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Paris
- URL=<DOMAINE>
- SUBDOMAINS=wildcard
- VALIDATION=duckdns
- DUCKDNSTOKEN=<TOKEN_DUCKDNS>
- ONLY_SUBDOMAINS=false
- EMAIL=<EMAIL>
- DOCKER_MODS=linuxserver/mods:swag-dashboard|ghcr.io/linuxserver/mods:swag-crowdsec
- CROWDSEC_LAPI_URL=http://crowdsec:8080
- CROWDSEC_API_KEY=<CLE_BOUNCER>
- CROWDSEC_SITE_KEY=<TURNSTILE_SITE_KEY>
- CROWDSEC_SECRET_KEY=<TURNSTILE_SECRET_KEY>
- CROWDSEC_CAPTCHA_PROVIDER=turnstile
volumes:
- <APPDATA>/swag/config:/config
networks: [proxy]
authelia:
image: authelia/authelia
container_name: authelia
restart: unless-stopped
environment:
- TZ=Europe/Paris
- AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/config/secrets/smtp_password
volumes:
- <APPDATA>/authelia/config:/config
- <APPDATA>/authelia/data:/data
- <APPDATA>/authelia/secrets:/config/secrets:rw
networks:
proxy:
aliases: [authelia]
Publier un nouveau service
Le conteneur du service doit être sur le réseau proxy. Ensuite, dans <APPDATA>/swag/config/nginx/proxy-confs/ :
Dans le fichier copié :
- vérifier que $upstream_app correspond au nom du conteneur et $upstream_port à son port interne ;
- décommenter les lignes Authelia pour protéger le service.
Sans sample fourni par SWAG, partir d'un sample existant et l'adapter. Ne pas redéclarer les directives déjà présentes dans proxy.conf (voir Dépannage).
SWAG recharge nginx automatiquement quand un proxy-conf change.
Exemple de proxy-conf écrit à la main : Dawarich
SWAG ne fournit pas de modèle pour Dawarich. Fichier <APPDATA>/swag/config/nginx/proxy-confs/dawarich.subdomain.conf :
listen 443 ssl;
listen [::]:443 ssl;
server_name dawarich.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
#include /config/nginx/authelia-server.conf;
location / {
#include /config/nginx/authelia-location.conf;
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app dawarich_app;
set $upstream_port 3000;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
location /cable {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app dawarich_app;
set $upstream_port 3000;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
location /api {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app dawarich_app;
set $upstream_port 3000;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
proxy_buffer_size 16k;
proxy_busy_buffers_size 32k;
}
}
| Élément | Rôle |
|---|---|
| server_name dawarich.* | Sous-domaine, quel que soit le domaine principal |
| ssl.conf | Certificat wildcard et réglages TLS de SWAG |
| client_max_body_size 0 | Pas de limite de taille : les imports d'historique dépassent largement la limite par défaut de nginx |
| resolver.conf et set $upstream_app | Résolution du nom du conteneur au moment de la requête : nginx démarre même si Dawarich est arrêté |
| location /cable | Connexion WebSocket (Action Cable) pour les mises à jour en direct ; les en-têtes nécessaires sont déjà dans proxy.conf |
| location /api | API des applications de suivi, avec des tampons agrandis pour les réponses volumineuses |
Protéger un service par Authelia
Il faut décommenter les deux lignes :
- include /config/nginx/authelia-server.conf; dans le bloc server : déclare l'échange avec Authelia ;
- include /config/nginx/authelia-location.conf; dans chaque location à protéger.
Une location sans cette seconde ligne reste accessible sans Authelia : c'est ainsi qu'on laisse une API ouverte aux applications mobiles tout en protégeant l'interface.
Ici, les deux lignes sont commentées : Dawarich n'est protégé que par son propre identifiant.
CrowdSec
Voir la page CrowdSec.
Authelia
Voir la page Authelia.