Mode opératoire — Termix : le portail d’accès du bastion
Document autonome. Partie théorique, puis mise en œuvre appliquée à
srv-docker(10.0.30.12). La méthode vaut pour tout portail d’accès conteneurisé.Dernière mise à jour : 01/10/2026 État au 12/11/2026 :
srv-docker(Debian 12) porte aussi Portainer et le connecteur Pangolin (newt). Le conteneurtermix-guacd(imageguacamole/guacd) est un composant interne de Termix pour le bureau à distance, pas le produit Guacamole qui était prévu au début.
Sommaire
| § | Contenu |
|---|---|
| 1 | Pourquoi un portail d’accès plutôt qu’un client sur chaque poste |
| 2 | Ce qu’est Termix — et les deux moteurs qui le composent |
| 3 | Ce qu’un portail ne remplace pas |
| 4 | Préparer l’hôte et déployer la pile |
| 5 | Le fichier docker-compose.yml, ligne par ligne |
| 6 | Le réglage qui décide de tout : l’adresse du moteur de rendu |
| 7 | Enregistrer les machines — SSH et bureau à distance |
| 8 | Clés et mots de passe : où ils vivent vraiment |
| 9 | Exporter, sauvegarder, restaurer |
| 10 | Le pare-feu : une seule règle, deux ports de sortie |
| 11 | Diagnostic |
| 12 | Pièges et checklists |
1 · Pourquoi un portail d’accès
1.1 Le problème
Une infrastructure cloisonnée n’expose aucune de ses machines. Il faut pourtant les administrer — en SSH pour les Linux, en bureau à distance pour les Windows.
SANS PORTAIL AVEC PORTAIL
──────────── ────────────
un client SSH par poste UNE machine joignable
un client RDP par poste UN portail, dans le navigateur
des clés dispersées partout les accès centralisés
autant de portes que de machines une porte, un journal
1.2 Ce que le portail apporte
| Apport | Détail |
|---|---|
| Une seule porte | Une machine à durcir et à surveiller, au lieu d’autant que de serveurs |
| Traçabilité | Tous les accès laissent une trace au même endroit |
| Rien à installer | Un navigateur suffit : aucun client sur les postes |
| Deux protocoles, une règle | SSH et bureau à distance passent par la même adresse |
Le portail ne rend pas les serveurs plus sûrs — il réduit la surface d’accès à une seule machine, que l’on peut alors durcir sérieusement. Tout l’intérêt est là, et toute la responsabilité aussi : qui compromet le portail atteint tout le reste.
1.3 Le portail est un bastion
C’est le même rôle, vu depuis l’application : le bastion est la machine, le portail est le service qu’elle rend.
┌──────────── zone exposée ────────────┐
│ poste utilisateur ──► 443/tcp │
└───────────────┬──────────────────────┘
▼
srv-docker 10.0.30.12
│ 22 (SSH) · 3389 (bureau à distance)
┌───────────────▼─── zones internes ───┐
│ serveurs web · nœuds de base · AD │
│ (injoignables depuis les postes) │
└──────────────────────────────────────┘
2 · Ce qu’est Termix
Une application web qui ouvre des sessions distantes depuis un navigateur. Elle se déploie en conteneurs et s’appuie sur deux moteurs distincts — c’est le point à comprendre avant tout le reste.
┌─ réseau termix-net ───────────────────────────────┐
│ │
│ termix termix-guacd │
│ ─────── ──────────── │
│ · interface web · moteur de rendu │
│ · SSH en direct · bureau à distance, VNC │
│ · base SQLite · écoute sur 4822 │
│ · publie le 443 NON publié │
│ │
└───────────────────────────────────────────────────┘
| Composant | Rôle | Exposé ? |
|---|---|---|
termix | L’interface, la base des connexions, le SSH | port 443 |
termix-guacd | Le rendu graphique : bureau à distance, VNC | interne uniquement |
Deux chemins différents pour deux protocoles. Le SSH est du texte :
termixle traite directement. Le bureau à distance est de l’image : il faut un moteur capable de la décoder et de la retransmettre au navigateur — c’est le rôle determix-guacd.Conséquence pratique : si le SSH fonctionne mais pas le bureau à distance, le problème est dans le second moteur, pas dans Termix. Cette distinction oriente tout le diagnostic du §11.
2.1 La base de données
Termix stocke ses connexions, ses comptes et ses identifiants dans une base SQLite, dans un volume Docker. Aucun serveur de base de données à déployer à côté.
C’est un vrai avantage d’exploitation : une pile à deux conteneurs au lieu de quatre, pas de mot de passe de base à gérer, et une sauvegarde qui se réduit à un volume. En contrepartie, ce volume concentre tout — voir le §8.
3 · Ce qu’un portail ne remplace pas
Trois confusions à écarter d’emblée.
3.1 Ce n’est pas un pare-feu
Le portail ne décide de rien au niveau réseau. C’est le pare-feu qui autorise le portail à sortir vers les autres zones. Si la règle n’existe pas, aucune connexion ne s’ouvre, quelle que soit la configuration du portail.
3.2 Ce n’est pas un gestionnaire de secrets
Il stocke des identifiants parce qu’il en a besoin, pas parce que c’est sa fonction. Un coffre de secrets dédié chiffre, journalise les accès, fait tourner les secrets et les révoque. Un portail d’accès, non.
3.3 Ce n’est pas une sauvegarde de configuration
Exporter les connexions enregistrées sauvegarde la façon de joindre les machines, pas les machines elles-mêmes.
La confusion la plus coûteuse serait de croire l’infrastructure sauvegardée parce que le portail l’est. Ce sont deux objets sans rapport.
4 · Préparer l’hôte et déployer
4.1 Prérequis
| Prérequis | Vérification |
|---|---|
| Docker et Compose v2 | docker compose version |
| Un répertoire de travail | /opt/termix |
| Le port d’écoute autorisé par le pare-feu | voir §10 |
Compose v1 ou v2 — la distinction compte. Le paquet des dépôts de la distribution fournit souvent la v1, dont la syntaxe est
docker-composeavec un tiret. La documentation de Termix suppose la v2 :docker compose, sans tiret. Installer depuis le dépôt officiel de Docker évite ce décalage.
4.2 Déployer
sudo mkdir -p /opt/termix
cd /opt/termix
sudo nano docker-compose.yml # contenu au §5
sudo docker compose up -d
4.3 Contrôler
sudo docker compose ps
sudo docker compose logs -f termix
sudo ss -tlnp | grep 443
Les deux conteneurs doivent être Up, et termix-guacd idéalement (healthy).
5 · Le fichier de composition
services:
termix:
image: ghcr.io/lukegus/termix:latest
container_name: termix
restart: unless-stopped
ports:
- "443:8080"
environment:
PORT: "8080"
volumes:
- termix-data:/app/data
networks:
- termix-net
depends_on:
- termix-guacd
termix-guacd:
image: guacamole/guacd:1.6.0
container_name: termix-guacd
restart: unless-stopped
networks:
- termix-net
volumes:
termix-data:
driver: local
networks:
termix-net:
driver: bridge
5.1 Chaque directive, et pourquoi
| Directive | Rôle | Conséquence si modifiée |
|---|---|---|
ports: "443:8080" | Publie le 443 de l’hôte vers le 8080 du conteneur | Le port de gauche doit être autorisé par le pare-feu |
PORT: "8080" | Indique à l’application sur quel port écouter à l’intérieur | Doit correspondre au port de droite |
volumes: termix-data | La base SQLite y vit | Sans ce volume, tout est perdu à chaque recréation |
networks: termix-net | Réseau isolé de la pile | Les deux conteneurs s’y voient par leur nom |
depends_on | Ordre de démarrage | voir ci-dessous |
container_name: termix-guacd | Nom explicite du moteur de rendu | à reporter dans la configuration — §6 |
restart: unless-stopped | Redémarrage automatique | Survit au redémarrage de l’hôte |
depends_ongarantit l’ordre de démarrage, pas la disponibilité. Le conteneurtermixpeut démarrer avant quetermix-guacdn’accepte les connexions. Ce n’est pas bloquant — la connexion au moteur se fait à l’ouverture d’une session, pas au démarrage — mais c’est à savoir pour ne pas chercher là où il n’y a rien.
5.2 Le nom du moteur n’est pas anodin
Le conteneur de rendu est nommé termix-guacd alors que la valeur attendue par défaut est
guacd.
Les noms de conteneurs sont uniques sur l’hôte. Un préfixe explicite évite toute collision avec une autre pile. Mais ce choix a une conséquence : le nom doit être reporté partout où il est référencé — et il l’est dans un champ de l’interface d’administration.
C’est exactement l’objet du paragraphe suivant, et la cause d’une panne classique.
6 · Le réglage qui décide de tout
6.1 Le symptôme
À l’ouverture d’une session de bureau à distance :
Le service de bureau à distance (guacd) n'est pas disponible.
Veuillez vous assurer que guacd est en cours d'exécution, accessible
et correctement configuré.
Et pourtant docker compose ps affiche termix-guacd en Up (healthy).
6.2 La cause
Dans Paramètres administrateur → URL GUACD, la valeur était localhost:4822.
┌─ conteneur termix ──────────┐ ┌─ conteneur termix-guacd ─┐
│ │ │ │
│ localhost ──► lui-même │ │ écoute sur 4822 │
│ ne mène nulle │ │ │
│ part d'autre │ │ │
└─────────────────────────────┘ └──────────────────────────┘
│ ▲
└───── termix-guacd:4822 ───────┘
le nom du conteneur
Chaque conteneur possède son propre espace réseau. Depuis l’intérieur de
termix,localhostdésignetermixlui-même — pas l’hôte, pas le voisin. C’est la différence la plus mal comprise entre une machine virtuelle et un conteneur.
6.3 La correction
Paramètres administrateur → URL GUACD → termix-guacd:4822
6.4 Vérifier la résolution entre conteneurs
sudo docker exec termix getent hosts termix-guacd
Attendu : une adresse du réseau de la pile, par exemple 172.19.0.2 termix-guacd.
Docker fournit un résolveur interne à chaque réseau défini par l’utilisateur : les conteneurs d’une même pile se joignent par leur nom de service ou de conteneur, sans jamais coder une adresse IP. Cette résolution ne fonctionne pas sur le réseau
bridgepar défaut — c’est l’une des raisons de déclarer un réseau nommé, commetermix-net.
7 · Enregistrer les machines
7.1 Les deux familles de connexions
| Type | Port de sortie | Moteur sollicité | Pour |
|---|---|---|---|
| SSH | 22 | termix directement | Machines Linux, et Windows avec serveur OpenSSH |
| Bureau à distance | 3389 | termix-guacd | Machines Windows graphiques |
7.2 Ce qu’une connexion enregistre
| Champ | Remarque |
|---|---|
| Nom d’affichage | Choisir le nom réel de la machine — un libellé approximatif devient vite trompeur |
| Hôte | L’adresse interne, jamais une adresse publique |
| Port | 22 ou 3389 |
| Utilisateur | Le compte distant |
| Authentification | Mot de passe ou clé privée — voir §8 |
7.3 Nommer d’abord, enregistrer ensuite
Enregistre une connexion sous le nom définitif de la machine. Renommer une machine après coup laisse une entrée au mauvais nom dans le portail, et c’est cette entrée que l’on consulte en situation d’incident — donc exactement au moment où une confusion coûte cher.
8 · Clés et mots de passe
8.1 Où ils vivent
Les identifiants enregistrés — mots de passe et clés privées — sont stockés dans la base
SQLite du volume termix-data.
Ce volume est un coffre d’identifiants. Qui l’obtient obtient l’accès à toutes les machines enregistrées. Cela a trois conséquences directes :
Conséquence Détail L’hôte devient aussi sensible que ce qu’il ouvre Durcir srv-dockerau niveau des machines qu’il atteint, pas au niveau d’un hôte secondaireLe volume ne se copie pas n’importe où Ni sur un partage, ni dans un dépôt de code — voir §9 La compromission du portail est totale Il n’y a pas de demi-mesure : c’est le modèle du bastion, à assumer
8.2 Mot de passe ou clé ?
| Mot de passe | Clé privée | |
|---|---|---|
| Robustesse | dépend de sa longueur | nettement supérieure |
| Révocation | changer le mot de passe partout | retirer la clé publique du serveur |
| Traçabilité | aucune distinction entre usages | une clé par origine |
Préférer la clé, et une clé dédiée au portail — pas celle du poste de travail. Si le portail est compromis, seule cette clé est à révoquer, et la clé personnelle reste valide.
8.3 Le compte d’accès au portail
Le portail a ses propres comptes, indépendants des comptes des machines. Ils protègent le coffre.
Un mot de passe faible sur le portail annule toute la sécurité en aval. Les trois verrous posés sur une base de données ne valent plus rien si le portail qui les franchit s’ouvre avec un mot de passe deviné.
9 · Exporter, sauvegarder, restaurer
9.1 Sauvegarder le volume
sudo docker run --rm \
-v termix_termix-data:/data:ro \
-v "$PWD":/sauvegarde \
alpine tar czf /sauvegarde/termix-$(date +%F).tar.gz -C /data .
Le nom du volume est préfixé par celui du projet Compose — ici le nom du répertoire,
termix.docker volume lsdonne le nom exact.
9.2 L’export est un fichier de secrets
Termix propose un export de sa base. Ce fichier contient les clés privées et les mots de passe enregistrés — vérifiable sans l’ouvrir :
strings termix-export-*.sqlite | grep -c "PRIVATE KEY"
À traiter comme une clé privée, pas comme une sauvegarde ordinaire.
Ne jamais Faire Le déposer dans un dépôt de code Le chiffrer avant tout déplacement Le laisser dans un dossier synchronisé Le ranger là où vivent les secrets L’envoyer par messagerie Le supprimer après restauration Un fichier de ce type validé une fois dans un dépôt Git y reste définitivement, même supprimé ensuite.
9.3 Restaurer
cd /opt/termix
sudo docker compose down # SANS -v
sudo docker run --rm -v termix_termix-data:/data -v "$PWD":/sauvegarde \
alpine sh -c "rm -rf /data/* && tar xzf /sauvegarde/termix-AAAA-MM-JJ.tar.gz -C /data"
sudo docker compose up -d
9.4 down et down -v
| Commande | Effet |
|---|---|
docker compose down | Arrête et supprime les conteneurs — les volumes survivent |
docker compose down -v | Supprime aussi les volumes : comptes, connexions, identifiants |
-vsur cette pile efface le coffre. Il faut alors recréer le compte d’administration et ressaisir toutes les connexions. La commande est légitime pour repartir de zéro — jamais par réflexe.
10 · Le pare-feu
10.1 Une seule règle en entrée
| Élément | Valeur |
|---|---|
| Source | la zone des postes utilisateurs |
| Destination | SRV_BASTION — 10.0.30.12 |
| Service | PORTS_BASTION — 443 |
10.2 Une seule règle en sortie
| Élément | Valeur |
|---|---|
| Source | SRV_BASTION seul — pas toute la zone d’administration |
| Destination | toutes les zones internes |
| Service | PORTS_ADMIN — 22 et 3389 |
Les deux ports de sortie servent le même portail. Termix ouvre le SSH sur le 22 et le bureau à distance sur le 3389 : un seul bastion, une seule adresse à filtrer, une seule règle à justifier.
10.3 Le portail sert du HTTP en clair sur le 443
Le 443 est par convention le port du HTTPS. Ici il transporte du HTTP en clair, parce que c’est le port que le pare-feu autorise.
Conséquence : aucune URL courte ne fonctionne.
| URL | Résultat |
|---|---|
http://10.0.30.12 | part sur le port 80 — |
https://10.0.30.12 | tente une négociation TLS — |
http://10.0.30.12:443 |
Un cas où une contrainte de sécurité a forcé un choix technique discutable — et il faut savoir le reconnaître plutôt que le masquer.
Correction Effet Ajouter le 80 à l’alias et republier le portail dessus L’URL courte fonctionne naturellement Mandataire inverse sur le 443, avec TLS https://termix.sio.internalen vrai HTTPS — la solution canoniqueLe mandataire inverse résout aussi le problème de fond : chaque port ouvert dans le pare-feu est une ligne à justifier. Un point d’entrée unique en réduit le nombre à un.
11 · Diagnostic
11.1 Le premier tri
Le SSH fonctionne-t-il ? Cette seule question partage le diagnostic en deux.
Constat Direction Ni SSH ni bureau à distance Le portail, le réseau ou le pare-feu SSH , bureau à distance Le moteur de rendu — §6 SSH , bureau à distance La machine cible ou son service de session distante
11.2 Par symptôme
| Symptôme | Vérification | Cause fréquente |
|---|---|---|
| L’interface ne répond pas | docker compose ps · ss -tlnp | grep 443 | Conteneur arrêté, ou port déjà pris |
| Interface injoignable depuis un poste | Journal du pare-feu | Règle d’entrée absente ou mauvaise destination |
guacd n'est pas disponible | docker exec termix getent hosts termix-guacd | Adresse du moteur mal renseignée — §6 |
| Une connexion SSH expire | Journal du pare-feu, filtré sur la destination | Règle de sortie absente |
| Une connexion SSH est refusée | ss -tlnp sur la machine cible | Service arrêté, ou écoute sur la mauvaise adresse |
| Authentification refusée | — | Identifiant périmé, ou clé non déployée sur la cible |
11.3 Le piège transversal
Un message d’« expiration de connexion » affiché par le portail n’est pas une expiration réseau.
Cas réellement rencontré : le portail annonçait une expiration vers le pare-feu. La table de blocage automatique était vide, et le port répondait depuis une autre machine. La cause était un identifiant périmé enregistré dans le portail, après un changement de mot de passe.
Le vocabulaire des messages applicatifs n’est pas celui des couches basses. Vérifier le réseau avec un outil réseau :
# depuis l'hôte du portail, pas depuis le portail
nc -vz 10.0.20.10 22
11.4 Commandes utiles
sudo docker compose ps
sudo docker compose logs --tail 80 termix
sudo docker compose logs --tail 40 termix-guacd
sudo docker exec termix getent hosts termix-guacd
sudo docker network inspect termix_termix-net
sudo ss -tlnp | grep -E ':443|:4822'
4822ne doit PAS apparaître dans la dernière commande : le moteur de rendu n’est pas publié sur l’hôte. S’il l’était, n’importe quelle machine pourrait le solliciter directement.
12 · Pièges et checklists
12.1 Les pièges
| # | Piège | Symptôme | Correction |
|---|---|---|---|
| 1 | localhost comme adresse du moteur | Bureau à distance indisponible, SSH fonctionnel | termix-guacd:4822 |
| 2 | Conteneur renommé, référence non reportée | Idem | Reporter le nom partout où il est référencé |
| 3 | URL sans le port | Page inaccessible | http://10.0.30.12:443 |
| 4 | down -v par réflexe | Comptes et connexions perdus | Sauvegarder le volume avant |
| 5 | Export déposé dans un dépôt ou un partage | Clés privées publiées | Le traiter comme une clé privée |
| 6 | Compose v1 au lieu de v2 | Syntaxe refusée | Installer depuis le dépôt officiel |
| 7 | Règle de sortie oubliée | Connexions qui expirent | SRV_BASTION → zones internes, 22 et 3389 |
| 8 | Clé du poste réutilisée | Portée d’une compromission maximale | Une clé dédiée au portail |
| 9 | Connexion enregistrée sous un nom provisoire | Confusion en situation d’incident | Nommer la machine avant de l’enregistrer |
| 10 | Expiration applicative prise pour un blocage réseau | Heures perdues sur le pare-feu | Vérifier le réseau avec un outil réseau |
12.2 Checklist — mise en service
- Docker et Compose v2 installés
- Fichier de composition déposé dans
/opt/termix - Les deux conteneurs
Up - Port d’écoute visible sur l’hôte, 4822 absent
- Adresse du moteur de rendu = nom du conteneur, pas
localhost - Interface joignable depuis un poste utilisateur
- Compte d’administration créé, mot de passe fort
- Une connexion SSH enregistrée et testée
- Une connexion bureau à distance enregistrée et testée
- Règle de pare-feu d’entrée vérifiée
- Règle de pare-feu de sortie vérifiée
- Sauvegarde du volume effectuée et restaurée une fois pour l’éprouver
12.3 Checklist — avant d’enregistrer une machine
- La machine porte son nom définitif
- Son adresse est fixe
- Le flux est autorisé par le pare-feu
- Authentification par clé dédiée plutôt que par mot de passe
- La clé publique est déployée sur la cible
12.4 Checklist — hygiène périodique
- Connexions obsolètes supprimées
- Identifiants de machines supprimées retirés du portail
- Sauvegarde du volume récente
- Aucun export de la base qui traîne sur le disque
- Image à jour :
docker compose pull && docker compose up -d
Le réflexe à garder. Le portail concentre les accès et les secrets. Avant chaque opération, une seconde question : « est-ce que ce que je m’apprête à faire sortirait des identifiants de cette machine ? » Si oui, c’est qu’il faut chiffrer, ou ne pas le faire.
