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 conteneur termix-guacd (image guacamole/guacd) est un composant interne de Termix pour le bureau à distance, pas le produit Guacamole qui était prévu au début.


Sommaire

§Contenu
1Pourquoi un portail d’accès plutôt qu’un client sur chaque poste
2Ce qu’est Termix — et les deux moteurs qui le composent
3 Ce qu’un portail ne remplace pas
4Préparer l’hôte et déployer la pile
5Le fichier docker-compose.yml, ligne par ligne
6Le réglage qui décide de tout : l’adresse du moteur de rendu
7Enregistrer les machines — SSH et bureau à distance
8 Clés et mots de passe : où ils vivent vraiment
9Exporter, sauvegarder, restaurer
10Le pare-feu : une seule règle, deux ports de sortie
11Diagnostic
12Piè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

ApportDétail
Une seule porteUne 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 à installerUn navigateur suffit : aucun client sur les postes
Deux protocoles, une règleSSH 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é              │
   │                                                   │
   └───────────────────────────────────────────────────┘
ComposantRôleExposé ?
termixL’interface, la base des connexions, le SSH port 443
termix-guacdLe rendu graphique : bureau à distance, VNC interne uniquement

Deux chemins différents pour deux protocoles. Le SSH est du texte : termix le 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 de termix-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érequisVérification
Docker et Compose v2docker compose version
Un répertoire de travail/opt/termix
Le port d’écoute autorisé par le pare-feuvoir §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-compose avec 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

DirectiveRôleConséquence si modifiée
ports: "443:8080"Publie le 443 de l’hôte vers le 8080 du conteneurLe port de gauche doit être autorisé par le pare-feu
PORT: "8080"Indique à l’application sur quel port écouter à l’intérieurDoit correspondre au port de droite
volumes: termix-dataLa base SQLite y vitSans ce volume, tout est perdu à chaque recréation
networks: termix-netRéseau isolé de la pileLes deux conteneurs s’y voient par leur nom
depends_onOrdre de démarrage voir ci-dessous
container_name: termix-guacdNom explicite du moteur de rendu à reporter dans la configuration — §6
restart: unless-stoppedRedémarrage automatiqueSurvit au redémarrage de l’hôte

depends_on garantit l’ordre de démarrage, pas la disponibilité. Le conteneur termix peut démarrer avant que termix-guacd n’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, localhost désigne termix lui-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 bridge par défaut — c’est l’une des raisons de déclarer un réseau nommé, comme termix-net.


7 · Enregistrer les machines

7.1 Les deux familles de connexions

TypePort de sortieMoteur sollicitéPour
SSH22termix directementMachines Linux, et Windows avec serveur OpenSSH
Bureau à distance3389termix-guacdMachines Windows graphiques

7.2 Ce qu’une connexion enregistre

ChampRemarque
Nom d’affichageChoisir le nom réel de la machine — un libellé approximatif devient vite trompeur
HôteL’adresse interne, jamais une adresse publique
Port22 ou 3389
UtilisateurLe compte distant
AuthentificationMot 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équenceDétail
L’hôte devient aussi sensible que ce qu’il ouvreDurcir srv-docker au niveau des machines qu’il atteint, pas au niveau d’un hôte secondaire
Le 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 totaleIl n’y a pas de demi-mesure : c’est le modèle du bastion, à assumer

8.2 Mot de passe ou clé ?

Mot de passeClé privée
Robustessedépend de sa longueur nettement supérieure
Révocationchanger 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 ls donne 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 codeLe chiffrer avant tout déplacement
Le laisser dans un dossier synchroniséLe ranger là où vivent les secrets
L’envoyer par messagerieLe 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

CommandeEffet
docker compose downArrête et supprime les conteneurs — les volumes survivent
docker compose down -vSupprime aussi les volumes : comptes, connexions, identifiants

-v sur 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émentValeur
Sourcela zone des postes utilisateurs
DestinationSRV_BASTION — 10.0.30.12
ServicePORTS_BASTION — 443

10.2 Une seule règle en sortie

ÉlémentValeur
SourceSRV_BASTION seul — pas toute la zone d’administration
Destinationtoutes les zones internes
ServicePORTS_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.

URLRésultat
http://10.0.30.12part sur le port 80 —
https://10.0.30.12tente 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.

CorrectionEffet
Ajouter le 80 à l’alias et republier le portail dessusL’URL courte fonctionne naturellement
Mandataire inverse sur le 443, avec TLShttps://termix.sio.internal en vrai HTTPS — la solution canonique

Le 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.

ConstatDirection
Ni SSH ni bureau à distanceLe 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ômeVérificationCause fréquente
L’interface ne répond pasdocker compose ps · ss -tlnp | grep 443Conteneur arrêté, ou port déjà pris
Interface injoignable depuis un posteJournal du pare-feuRègle d’entrée absente ou mauvaise destination
guacd n'est pas disponibledocker exec termix getent hosts termix-guacdAdresse du moteur mal renseignée — §6
Une connexion SSH expireJournal du pare-feu, filtré sur la destinationRègle de sortie absente
Une connexion SSH est refuséess -tlnp sur la machine cibleService 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'

4822 ne 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ègeSymptômeCorrection
1localhost comme adresse du moteurBureau à distance indisponible, SSH fonctionneltermix-guacd:4822
2Conteneur renommé, référence non reportéeIdemReporter le nom partout où il est référencé
3URL sans le portPage inaccessiblehttp://10.0.30.12:443
4down -v par réflexeComptes et connexions perdusSauvegarder le volume avant
5Export déposé dans un dépôt ou un partage Clés privées publiéesLe traiter comme une clé privée
6Compose v1 au lieu de v2Syntaxe refuséeInstaller depuis le dépôt officiel
7Règle de sortie oubliéeConnexions qui expirentSRV_BASTION → zones internes, 22 et 3389
8Clé du poste réutiliséePortée d’une compromission maximaleUne clé dédiée au portail
9Connexion enregistrée sous un nom provisoireConfusion en situation d’incidentNommer la machine avant de l’enregistrer
10Expiration applicative prise pour un blocage réseauHeures perdues sur le pare-feuVé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.