Une seule porte d'entrée pour chaque outil interne : un modèle d'auto-hébergement
Comment faire tourner tableaux de tâches, dashboards, un coffre de mots de passe et le reste derrière un reverse proxy : DNS wildcard, conteneurs sous systemd, accès à deux verrous, renommages sûrs.

Chaque équipe d'exploitation accumule de petits outils. Un tableau de tâches, un serveur de dashboards, une console de conteneurs, un coffre de mots de passe, une ou deux applications web internes que quelqu'un a écrites. Chacun commence sa vie sur son propre port, avec son propre certificat et sa propre idée de l'authentification, et au bout d'un an personne ne sait avec certitude lesquels sont exposés, lesquels sont à jour, ni lesquels ont encore un certificat valide. Voici le modèle que nous utilisons pour faire tourner tout un ensemble d'outils internes comme un seul service bien tenu : une seule porte d'entrée, une seule façon de démarrer, une seule politique d'accès.
La forme de la stack
Le modèle a quatre couches, et chacune a un seul travail :
- DNS : un nom wildcard, tel que
*.tools.example.com, pointant vers un seul hôte. - Reverse proxy : Traefik sur cet hôte, qui termine le TLS et route chaque hostname vers le bon conteneur.
- Conteneurs : chaque outil dans son propre conteneur Podman sur un réseau de conteneurs privé, sans aucun port publié sur l'hôte en dehors de celui du proxy.
- Supervision : systemd démarre, redémarre et ordonne tout, pour que la stack survive à un redémarrage sans intervention humaine.
Avec cela en place, ajouter un outil est une courte checklist plutôt qu'un projet : démarrer un conteneur sur le réseau, ajouter une route, terminé. Pas de nouveau trou dans le firewall, pas de nouvel enregistrement DNS, pas de nouvelle demande de certificat.
DNS : un wildcard, puis on l'oublie
Un enregistrement wildcard signifie que tasks.tools.example.com, grafana.tools.example.com et vault.tools.example.com se résolvent tous vers l'hôte du proxy sans que personne ne touche plus au DNS. Associez-le à un certificat wildcard pour le même nom, et chaque nouvel outil naît avec un TLS valide.
Gardez le wildcard sur un sous-domaine dédié. Vous ne voulez pas que anything.example.com atterrisse sur votre hôte d'outillage.
Le proxy : des routes sous forme de fichiers lisibles
Traefik peut découvrir les routes à partir des labels des conteneurs ou de simples fichiers de configuration. Pour une petite stack à longue durée de vie, nous préférons les fichiers : faciles à relire, faciles à mettre sous contrôle de version, et ils ne changent pas parce que quelqu'un a redémarré un conteneur avec d'autres labels. Une route pour un gestionnaire de tâches ressemble à ceci :
http:
routers:
tasks:
rule: "Host(`tasks.tools.example.com`)"
entryPoints: [websecure]
service: tasks
middlewares: [mgmt-only]
tls: {}
services:
tasks:
loadBalancer:
servers: [{ url: "http://tasks:3456" }]
middlewares:
mgmt-only:
ipAllowList:
sourceRange: ["192.0.2.0/24"]
Le middleware est la partie importante. Le proxy est le seul et unique endroit où vous décidez qui peut atteindre un outil, donc placez la décision là.
Accès : deux verrous, pas un
Les outils internes ont leurs propres identifiants, et leur qualité varie. Ne vous y fiez pas seuls. Placez deux contrôles devant eux :
- Une liste d'autorisation des sources au niveau du proxy, limitée aux réseaux depuis lesquels votre équipe travaille vraiment. Développez chaque CIDR avant de l'écrire et relisez-le ensuite. Une longueur de préfixe mal tapée peut transformer la plage d'un bureau en une large partie d'internet :
python3 -c "import ipaddress,sys; n=ipaddress.ip_network(sys.argv[1],strict=False); print(n, n[0], '->', n[-1], n.num_addresses)" 192.0.2.0/24
- Un middleware d'authentification (basic auth sur TLS au minimum, ou forward authentication vers votre fournisseur d'identité) pour les outils qui ne doivent pas être joignables même depuis l'intérieur sans un second identifiant.
Le coffre de mots de passe mérite une réflexion particulière. Un serveur compatible Bitwarden tel que Vaultwarden stocke le contenu du coffre chiffré par les clients, de sorte que le serveur ne le détient jamais sous forme lisible. C'est une propriété forte, mais elle ne supprime pas le besoin de restreindre qui peut atteindre le serveur.
Des conteneurs sous systemd
Lancer des conteneurs à la main fonctionne jusqu'au premier redémarrage. Podman s'intègre à systemd via Quadlet : vous décrivez le conteneur dans un petit fichier unit et systemd le traite comme n'importe quel autre service.
# /etc/containers/systemd/tasks.container
[Unit]
Description=Task manager
After=network-online.target
[Container]
Image=docker.io/vikunja/vikunja:<pinned-tag>
Network=tools.network
Volume=/srv/tools/tasks:/app/vikunja/files:Z
[Service]
Restart=always
[Install]
WantedBy=multi-user.target
Après systemctl daemon-reload, systemctl start tasks le lance, et il démarre au boot à partir de là. Figez les tags d'images au lieu de suivre latest, pour qu'une mise à niveau soit une décision que vous prenez, avec un dump et un retour arrière prêts, plutôt que quelque chose qui vous arrive au prochain redémarrage.
Gardez SELinux en enforcing. Étiquetez chaque volume pour le conteneur qui le possède (:Z pour un volume privé, :z pour un volume que plusieurs conteneurs doivent partager).
Renommer sans rien casser
Tôt ou tard un outil déménage : un nouvel hôte, un nouveau domaine, un nom plus propre. Gardez l'ancien nom fonctionnel en faisant répondre le proxy par une redirection permanente vers le nouveau. Utilisez 308 Permanent Redirect plutôt que 301, parce qu'un 308 dit aux clients de répéter la même méthode et le même corps à la nouvelle adresse.
Il y a un piège qui attrape les scripts, pas les navigateurs. Les navigateurs suivent les redirections. Beaucoup de clients en ligne de commande et de bibliothèques ne le font pas, sauf si on leur demande. Un script qui envoie un POST à l'ancien nom reçoit un 308, ne le suit pas, et passe à la suite. Rien n'a été créé, rien n'a échoué bruyamment, et si le script vérifie seulement que quelque chose a répondu, il rapporte un succès. Avec curl, utilisez -L pour suivre, et vérifiez toujours le code de statut et le corps :
curl -s -o out.json -w '%{http_code}\n' -X POST https://tasks.tools.example.com/api/v1/...
Un corps de réponse contenant les mots « Permanent Redirect » là où vous attendiez du JSON est le signe révélateur. Quand vous renommez, cherchez l'ancien nom dans vos scripts et vos intégrations et mettez-les à jour, et ne gardez la redirection que comme filet de sécurité.
Sauvegardes, supervision et mises à jour
Supervisez chaque route depuis l'extérieur de l'hôte pour la page attendue, pas seulement pour une réponse, et mettez à jour un outil à la fois en gardant l'image précédente jusqu'à ce que la nouvelle ait tourné un moment.
Une checklist pour votre propre outillage
- Pouvez-vous lister chaque outil interne, son hostname et qui peut l'atteindre ?
- Un outil publie-t-il son propre port sur l'hôte ou sur internet, en contournant le proxy ?
- Toutes vos plages de la liste d'autorisation sont-elles aussi étroites que vous le pensez ? Développez-les et regardez.
- Vos conteneurs reviennent-ils d'eux-mêmes après un redémarrage ?
- Vos scripts vérifient-ils les codes de statut, ou seulement que quelque chose a répondu ?
- Quand avez-vous restauré votre coffre de mots de passe pour la dernière fois ?
Une seule porte d'entrée, une seule politique et une seule façon de démarrer transforment un tiroir d'outils épars en un service sur lequel vous pouvez raisonner clairement.
CTA
Si vous souhaitez que les outils de votre équipe tournent ainsi, sur votre propre instance, nos ingénieurs peuvent vous aider. Parler à un ingénieur
Related
Articles liés : Outillage d'exploitation auto-hébergé et infogéré · Le hardening baseline sur chaque hôte
Publié le 24 août 2026.
Toutes les notes de terrain