Réseau
Cette page explique comment les services exécutés dans des démons Docker isolés deviennent accessibles depuis Internet. Elle couvre le système de proxy inverse, les labels Docker pour le routage, les certificats TLS, le DNS et la redirection de ports TCP/UDP.
Pour comprendre comment les services obtiennent leurs adresses IP de bouclage et le système de slots .rediacc.json, consultez Services.
Fonctionnement
Rediacc utilise un système de proxy à deux composants pour router le trafic externe vers les conteneurs :
- Serveur de routes, un service systemd qui découvre les conteneurs en cours d’exécution sur tous les démons Docker des dépôts. Il inspecte les labels des conteneurs et génère la configuration de routage, servie comme un point d’accès YAML.
- Traefik, un proxy inverse qui interroge le serveur de routes toutes les 5 secondes et applique les routes découvertes. Il gère le routage HTTP/HTTPS, la terminaison TLS et la redirection TCP/UDP.
Le flux est le suivant :
Internet → Traefik (ports 80/443/TCP/UDP)
↓ interroge toutes les 5s
Serveur de routes (découvre les conteneurs)
↓ inspecte les labels
Démons Docker (/var/run/rediacc/docker-*.sock)
↓
Conteneurs (liés aux IP de bouclage 127.x.x.x)
Lorsque vous ajoutez les bons labels à un conteneur et le démarrez avec renet compose, il devient automatiquement routable, aucune configuration manuelle du proxy n’est nécessaire.
The route server binary is kept in sync with your CLI version. When the CLI updates the renet binary on a machine, the route server is automatically restarted (~1–2 seconds). This causes no downtime, Traefik continues serving traffic with its last known configuration during the restart and picks up the new config on the next poll. Existing client connections are not affected. Your application containers are not touched.
Labels Docker
Le routage est contrôlé par les labels des conteneurs Docker. Il existe deux niveaux :
Niveau 1 : Labels rediacc.* (automatiques)
Ces labels sont automatiquement injectés par renet compose lors du démarrage des services. Vous n’avez pas besoin de les ajouter manuellement.
| Label | Description | Exemple |
|---|---|---|
rediacc.service_name | Identité du service | myapp |
rediacc.service_ip | IP de bouclage assignée | 127.0.11.2 |
rediacc.network_id | ID du démon du dépôt | 2816 |
rediacc.repo_name | Repository name | marketing |
rediacc.tcp_ports | TCP ports the service listens on | 8080,8443 |
rediacc.udp_ports | UDP ports the service listens on | 53 |
Lorsqu’un conteneur possède uniquement des labels rediacc.* (sans traefik.enable=true), le serveur de routes génère une route automatique en utilisant le nom du dépôt et le sous-domaine de la machine :
{service}.{repoName}.{machineName}.{baseDomain}
Par exemple, un service nommé myapp dans un dépôt appelé marketing sur la machine server-1 avec le domaine de base example.com obtient :
myapp.marketing.server-1.example.com
Chaque dépôt a son propre niveau de sous-domaine, ce qui évite les collisions entre forks et dépôts différents. Lorsque vous forkez un dépôt (p. ex., marketing-staging), le fork obtient automatiquement des routes distinctes. Pour les services avec des domaines personnalisés, utilisez les labels de niveau 2 ou le label rediacc.domain.
Domaine personnalisé via rediacc.domain
Vous pouvez définir un domaine personnalisé pour un service en utilisant le label rediacc.domain dans votre docker-compose.yml. Les noms courts et les domaines complets sont pris en charge :
labels:
# Nom court, résolu en cloud.example.com en utilisant le baseDomain de la machine
- "rediacc.domain=cloud"
# Domaine complet, utilisé tel quel
- "rediacc.domain=cloud.example.com"
Une valeur sans points est traitée comme un nom court et le baseDomain de la machine est automatiquement ajouté. Une valeur avec des points est utilisée comme domaine complet.
Lorsque machineName est configuré, les services avec domaine personnalisé obtiennent deux routes : une sur le domaine de base (cloud.example.com) et une sur le sous-domaine de la machine (cloud.server-1.example.com).
Niveau 2 : Labels traefik.* (définis par l’utilisateur)
Ajoutez ces labels à votre docker-compose.yml lorsque vous souhaitez un routage par domaine personnalisé, le TLS ou des points d’entrée spécifiques. Définir traefik.enable=true indique au serveur de routes d’utiliser vos règles personnalisées au lieu de générer une route automatique.
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=8080"
Ceux-ci utilisent la syntaxe standard des labels Traefik v3.
Astuce : Les services internes uniquement (bases de données, caches, files de messages) ne devraient pas avoir
traefik.enable=true. Ils n’ont besoin que des labelsrediacc.*, qui sont injectés automatiquement.
Exposer des services HTTP/HTTPS
Prérequis
-
Infrastructure configurée sur la machine (Configuration de la machine, Configuration de l’infrastructure) :
# Identifiants partagés (une fois par config, s'applique à toutes les machines) rdc config infra set -m server-1 \ --cert-email admin@example.com \ --cf-dns-token your-cloudflare-api-token # Paramètres spécifiques à la machine rdc config infra set -m server-1 \ --public-ipv4 203.0.113.50 \ --base-domain example.com rdc config infra push -m server-1 -
Enregistrements DNS pointant votre domaine vers l’IP publique du serveur (voir Configuration DNS ci-dessous).
Ajouter des labels
Ajoutez les labels traefik.* aux services que vous souhaitez exposer dans votre docker-compose.yml :
services:
myapp:
image: myapp:latest
environment:
- LISTEN_ADDR=${MYAPP_IP}:8080
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=8080"
database:
image: postgres:17
command: ["-c", "listen_addresses=${DATABASE_IP}"]
# Pas de labels traefik, la base de données est interne uniquement
| Label | Objectif |
|---|---|
traefik.enable=true | Active le routage Traefik personnalisé pour ce conteneur |
traefik.http.routers.{name}.rule | Règle de routage, typiquement Host(\domaine`)` |
traefik.http.routers.{name}.entrypoints | Ports d’écoute : websecure (HTTPS IPv4), websecure-v6 (HTTPS IPv6) |
traefik.http.routers.{name}.tls.certresolver | Résolveur de certificats, utilisez letsencrypt pour Let’s Encrypt automatique |
traefik.http.services.{name}.loadbalancer.server.port | Le port sur lequel votre application écoute à l’intérieur du conteneur |
Le {name} dans les labels est un identifiant arbitraire, il doit simplement être cohérent entre les labels de routeur/service/middleware associés.
Note : Les labels
rediacc.*(rediacc.service_name,rediacc.service_ip,rediacc.network_id) sont injectés automatiquement parrenet compose. Vous n’avez pas besoin de les ajouter à votre fichier compose.
Certificats TLS
Les certificats TLS sont obtenus automatiquement via Let’s Encrypt en utilisant le challenge DNS-01 de Cloudflare. Les identifiants sont configurés une fois par config (partagés entre toutes les machines) :
rdc config infra set -m server-1 \
--cert-email admin@example.com \
--cf-dns-token your-cloudflare-api-token
Les routes automatiques utilisent des certificats wildcard au niveau du sous-domaine du dépôt (*.marketing.server-1.example.com) au lieu de certificats par service. Cela évite les limites de débit de Let’s Encrypt et accélère le démarrage. Les routes avec domaine personnalisé utilisent des wildcards au niveau machine (*.server-1.example.com).
Pour les routes de niveau 2 avec traefik.http.routers.{name}.tls.certresolver=letsencrypt, les SANs de domaine wildcard sont automatiquement injectés en fonction du nom d’hôte de la route.
Le jeton API DNS Cloudflare nécessite la permission Zone:DNS:Edit pour les domaines que vous souhaitez sécuriser.
Redirection de ports TCP/UDP
Pour les protocoles non-HTTP (serveurs de messagerie, DNS, bases de données exposées à l’extérieur), utilisez la redirection de ports TCP/UDP.
Étape 1 : Enregistrer les ports
Ajoutez les ports requis lors de la configuration de l’infrastructure :
rdc config infra set -m server-1 \
--tcp-ports 25,143,465,587,993 \
--udp-ports 53
rdc config infra push -m server-1
Ceci crée des points d’entrée Traefik nommés tcp-{port} et udp-{port}.
Plain TCP Example (Database)
To expose a database externally without TLS passthrough (Traefik forwards raw TCP):
services:
postgres:
image: postgres:17
command: -c listen_addresses=${POSTGRES_IP} -c port=5432
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.mydb.entrypoints=tcp-5432"
- "traefik.tcp.routers.mydb.rule=HostSNI(`*`)"
- "traefik.tcp.services.mydb.loadbalancer.server.port=5432"
Port 5432 is pre-configured (see below), so no --tcp-ports setup is needed.
Security note: Exposing a database to the internet is a risk. Use this only when remote clients need direct access. For most setups, keep the database internal and connect through your application.
Après avoir ajouté ou supprimé des ports, relancez toujours
rdc config infra pushpour mettre à jour la configuration du proxy.
Étape 2 : Ajouter des labels TCP/UDP
Utilisez les labels traefik.tcp.* ou traefik.udp.* dans votre fichier compose :
services:
mail-server:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
labels:
- "traefik.enable=true"
# SMTP (port 25)
- "traefik.tcp.routers.mail-smtp.entrypoints=tcp-25"
- "traefik.tcp.routers.mail-smtp.rule=HostSNI(`*`)"
- "traefik.tcp.routers.mail-smtp.service=mail-smtp"
- "traefik.tcp.services.mail-smtp.loadbalancer.server.port=25"
# IMAPS (port 993), passthrough TLS
- "traefik.tcp.routers.mail-imaps.entrypoints=tcp-993"
- "traefik.tcp.routers.mail-imaps.rule=HostSNI(`mail.example.com`)"
- "traefik.tcp.routers.mail-imaps.tls.passthrough=true"
- "traefik.tcp.routers.mail-imaps.service=mail-imaps"
- "traefik.tcp.services.mail-imaps.loadbalancer.server.port=993"
Concepts clés :
HostSNI(\*`)` correspond à n’importe quel nom d’hôte (pour les protocoles qui n’envoient pas de SNI, comme le SMTP en clair)tls.passthrough=truesignifie que Traefik transmet la connexion TLS brute sans la déchiffrer, l’application gère le TLS elle-même- Les noms des points d’entrée suivent la convention
tcp-{port}ouudp-{port}
Ports pré-configurés
Les ports TCP/UDP suivants ont des points d’entrée par défaut (pas besoin de les ajouter via --tcp-ports). Les points d’entrée ne sont générés que pour les familles d’adresses configurées, les points d’entrée IPv4 nécessitent --public-ipv4, les points d’entrée IPv6 nécessitent --public-ipv6 :
| Port | Protocole | Utilisation courante |
|---|---|---|
| 80 | HTTP | Web (redirection automatique vers HTTPS) |
| 443 | HTTPS | Web (TLS) |
| 3306 | TCP | MySQL/MariaDB |
| 5432 | TCP | PostgreSQL |
| 6379 | TCP | Redis |
| 27017 | TCP | MongoDB |
| 11211 | TCP | Memcached |
| 5672 | TCP | RabbitMQ |
| 9092 | TCP | Kafka |
| 53 | UDP | DNS |
| 10000–10010 | TCP | Plage dynamique (allocation automatique) |
Configuration DNS
DNS automatique (Cloudflare)
Lorsque --cf-dns-token est configuré, rdc config infra push crée automatiquement les enregistrements DNS nécessaires dans Cloudflare :
| Enregistrement | Type | Contenu | Créé par |
|---|---|---|---|
server-1.example.com | A / AAAA | IP publique de la machine | push-infra |
*.server-1.example.com | A / AAAA | IP publique de la machine | push-infra |
*.marketing.server-1.example.com | A / AAAA | IP publique de la machine | repo up |
Les enregistrements au niveau machine sont créés par push-infra et couvrent les routes avec domaine personnalisé (rediacc.domain). Les enregistrements wildcard par dépôt sont créés automatiquement par repo up et couvrent les routes automatiques pour ce dépôt.
C’est idempotent, les enregistrements existants sont mis à jour si l’IP change, et laissés inchangés s’ils sont déjà corrects.
Le wildcard du domaine de base (*.example.com) doit être créé manuellement si vous utilisez des labels de domaine personnalisés comme rediacc.domain=erp.
DNS manuel
Si vous n’utilisez pas Cloudflare ou gérez le DNS manuellement, créez des enregistrements A (IPv4) et/ou AAAA (IPv6) :
# Sous-domaine de la machine (pour les routes avec domaine personnalisé comme rediacc.domain=erp)
server-1.example.com A 203.0.113.50
*.server-1.example.com A 203.0.113.50
*.server-1.example.com AAAA 2001:db8::1
# Wildcards par dépôt (pour les routes automatiques comme myapp.marketing.server-1.example.com)
*.marketing.server-1.example.com A 203.0.113.50
*.marketing.server-1.example.com AAAA 2001:db8::1
# Wildcard du domaine de base (pour les services avec domaine personnalisé comme rediacc.domain=erp)
*.example.com A 203.0.113.50
Avec Cloudflare DNS configuré, les enregistrements wildcard par dépôt sont créés automatiquement par repo up. Avec plusieurs machines, chaque machine obtient ses propres enregistrements DNS pointant vers sa propre IP.
Middlewares
Les middlewares Traefik modifient les requêtes et les réponses. Appliquez-les via des labels.
HSTS (HTTP Strict Transport Security)
labels:
- "traefik.http.middlewares.myapp-hsts.headers.stsSeconds=15768000"
- "traefik.http.middlewares.myapp-hsts.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.myapp-hsts.headers.stsPreload=true"
- "traefik.http.routers.myapp.middlewares=myapp-hsts"
Mise en tampon pour les gros fichiers
labels:
- "traefik.http.middlewares.myapp-buffering.buffering.maxRequestBodyBytes=536870912"
- "traefik.http.routers.myapp.middlewares=myapp-buffering"
Middlewares multiples
Chaînez les middlewares en les séparant par des virgules :
labels:
- "traefik.http.routers.myapp.middlewares=myapp-hsts,myapp-buffering"
Pour la liste complète des middlewares disponibles, consultez la documentation des middlewares Traefik.
Diagnostics
Si un service n’est pas accessible, connectez-vous au serveur en SSH et vérifiez les points d’accès du serveur de routes :
Vérification de l’état
curl -s http://127.0.0.1:7111/health | python3 -m json.tool
Affiche le statut général, le nombre de routeurs et services découverts, et si les routes automatiques sont activées.
Routes découvertes
curl -s http://127.0.0.1:7111/routes.json | python3 -m json.tool
Liste tous les routeurs HTTP, TCP et UDP avec leurs règles, points d’entrée et services backend.
Allocations de ports
curl -s http://127.0.0.1:7111/ports | python3 -m json.tool
Affiche les mappages de ports TCP et UDP pour les ports alloués dynamiquement.
Problèmes courants
| Problème | Cause | Solution |
|---|---|---|
| Service absent des routes | Conteneur non démarré ou labels manquants | Vérifiez avec docker ps sur le démon du dépôt ; vérifiez les labels |
| Certificat non émis | DNS ne pointant pas vers le serveur, ou jeton Cloudflare invalide | Vérifiez la résolution DNS ; vérifiez les permissions du jeton API Cloudflare |
| 502 Bad Gateway | L’application n’écoute pas sur le port déclaré | Vérifiez que l’application se lie à son {SERVICE}_IP et que le port correspond à loadbalancer.server.port |
| Port TCP non accessible | Port non enregistré dans l’infrastructure | Exécutez rdc config infra set --tcp-ports ... et push-infra |
| Route server running old version | Binary was updated but service not restarted | Happens automatically on provisioning; manual: sudo systemctl restart rediacc-router |
| STUN/TURN relay not reachable | Relay addresses cached at startup | Recreate the service after DNS or IP changes so it picks up the new network config |
Exemple complet
Cet exemple déploie une application web avec une base de données PostgreSQL. L’application est accessible publiquement sur app.example.com avec TLS ; la base de données est interne uniquement.
docker-compose.yml
services:
webapp:
image: myregistry/webapp:latest
environment:
DATABASE_URL: postgresql://app:changeme@${POSTGRES_IP}:5432/webapp
LISTEN_ADDR: ${WEBAPP_IP}:3000
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
# HSTS
- "traefik.http.middlewares.webapp-hsts.headers.stsSeconds=15768000"
- "traefik.http.middlewares.webapp-hsts.headers.stsIncludeSubdomains=true"
- "traefik.http.routers.webapp.middlewares=webapp-hsts"
postgres:
image: postgres:17
environment:
POSTGRES_DB: webapp
POSTGRES_USER: app
POSTGRES_PASSWORD: changeme
command: -c listen_addresses=${POSTGRES_IP} -c port=5432
volumes:
- ./data/postgres:/var/lib/postgresql/data
# Pas de labels traefik, interne uniquement
Rediaccfile
#!/bin/bash
up() {
mkdir -p data/postgres
renet compose -- up -d
}
down() {
renet compose -- down
}
DNS
Créez un enregistrement A pointant app.example.com vers l’IP publique de votre serveur :
app.example.com A 203.0.113.50
Déployer
rdc repo up --name my-app -m server-1 --mount
En quelques secondes, le serveur de routes découvre le conteneur, Traefik récupère la route, demande un certificat TLS, et https://app.example.com est en ligne.