HL-PRC-022 — Guacamole — déploiement du thème sombre

HOMELAB
Infrastructure auto-hébergée

PROCÉDURE TECHNIQUE

Déploiement d’un thème sombre sur Apache Guacamole

Conception d’une extension Java modulaire (JAR), injection de styles CSS ciblés et neutralisation des politiques de mise en cache du reverse proxy Nginx Proxy Manager.

Référence
HL-PRC-022
Version
0.1
Date d’édition
02/11/2026
Auteur
Administrateur système et réseaux
Classification
Interne
Statut
Brouillon

Sommaire

Déploiement d’un thème sombre sur Apache Guacamole — HL-PRC-022

1 Objet

Cette procédure formalise la mise en œuvre, le durcissement visuel et le déploiement d’un thème sombre complet et persistant sur la passerelle d’accès distant bastion Apache Guacamole (version 1.6.0) au sein de l’infrastructure DozyLab. Elle détaille la fabrication d’une extension modulaire au format archive Java (JAR) reposant sur le mécanisme officiel guacamole-ext, permettant l’injection dynamique d’une feuille de style CSS sans altération des binaires compilés, sans décompilation du paquet WAR guacamole.war et sans interruption prolongée du conteneur de servlets Apache Tomcat.

Le document consigne précisément les arbitrages techniques et les solutions apportées aux contraintes rencontrées lors de l’intégration terrain : la surcharge des composants AngularJS natifs protégés par des fonds clairs codés en dur (onglets .page-tabs, conteneur central .white-wrapper, sélecteur d’arborescence hiérarchique location-chooser et sous-menu utilisateur), l’élimination des corruptions de saisie provoquées par la saturation du tampon de collage des consoles web Proxmox VE, ainsi que le contournement des politiques agressives de mise en cache HTTP appliquées par le proxy inverse frontal Nginx Proxy Manager (NPM).

2 Périmètre et prérequis

Périmètre d’application

• Périmètre couvert : création de l’arborescence source de l’extension (manifeste JSON et feuille de style CSS) ; surcharge exhaustive des sélecteurs d’interface utilisateur (écran d’authentification, vue d’accueil, miniatures de sessions récentes, liste des connexions, barre de navigation, menu contextuel utilisateur, panneaux d’administration et éditeur de connexion) ; assemblage de l’archive Java guacamole-dark-theme.jar ; déploiement dans le répertoire d’extensions de Guacamole ; prise en compte par Apache Tomcat ; procédure de purge du cache mandataire et client.

• Hors périmètre : personnalisation du rendu graphique interne des sessions distantes RDP et VNC (dépendant de la configuration propre du système d’exploitation distant) ; gestion des schémas de couleurs des émulateurs de terminaux SSH et Telnet (configurés individuellement dans les paramètres de chaque connexion) ; modification des sources Java du serveur web ou du démon mandataire C guacd.

Prérequis opérationnels

• Passerelle Apache Guacamole : instance opérationnelle en version 1.6.0 hébergée au sein d’un conteneur LXC Proxmox VE sous Debian GNU/Linux 13 (Trixie).

• Serveur d’application : serveur Apache Tomcat (version 9 ou 10) actif et configuré avec le répertoire d’accueil standard /etc/guacamole.

• Privilèges d’accès : session d’administration root ouverte sur le conteneur Guacamole (console locale Proxmox VE ou session SSH directe).

• Outillage d’assemblage : présence de l’interpréteur Python 3 avec module standard zipfile (ou utilitaire zip natif) sur l’hôte Debian.

• Réseau et reverse proxy : publication HTTPS assurée par Nginx Proxy Manager (NPM) routant le nom de domaine guacamole.adm.dozylab.lan vers le port local 8080.

Note Validation d’environnement : L’ensemble des procédures et sélecteurs de style présentés dans ce document a été appliqué le 25/10/2026 sur Apache Guacamole 1.6.0, Apache Tomcat 9/10, sous Debian GNU/Linux 13 (Trixie) relayé par Nginx Proxy Manager v2.12.x.

3 Rôles et responsabilités

RôleResponsabilité
Administrateur système et réseauxConception des règles CSS, génération de l’archive JAR, déploiement sur le conteneur Guacamole et validation du rendu visuel.
Détenteur des secretsGestion et conservation des identifiants d’administration root et des certificats de sécurité TLS hébergés sur le frontal NPM.
Exploitant d’infrastructureContrôle de l’état d’exécution des démons Tomcat et guacd, surveillance des journaux d’erreurs et notification des maintenances.

Note Homelab individuel : Dans le cadre d’une infrastructure d’expérimentation personnelle, la totalité des responsabilités ci-dessus est exercée par l’administrateur unique. Cette répartition est conservée pour garantir la conformité aux normes d’exploitation professionnelles et faciliter tout transfert de compétences.

4 Procédure de configuration et de déploiement

Paramètres de la procédure

ParamètreDescriptionValeur de référenceContrainte
GUAC_HOMERépertoire racine de configuration Guacamole/etc/guacamolePropriété root:root
GUAC_EXT_DIRRépertoire dédié aux extensions analysées au boot/etc/guacamole/extensionsPermissions 0755
JAR_NAMENom du livrable d’extension JAR déployéguacamole-dark-theme.jarFormat ZIP conforme
MANIFEST_NAMEFichier descripteur de l’extension Guacamoleguac-manifest.jsonFormat JSON strict
CSS_FILEFeuille de style injectée versionnéecss/dark-theme-v2.cssSyntaxe CSS3 standard
EXT_NAMESPACEEspace de noms déclaré pour l’extensionguac-dark-theme-v2Chaîne alphanumérique
TOMCAT_SVCService systemd du conteneur de servletstomcat9 (ou tomcat10)Actif et supervisé
GUAC_FQDNNom d’hôte pleinement qualifié de la passerelleguacamole.adm.dozylab.lanRésolution DNS interne

Attention Substitution des paramètres : Les lignes de commande fournies dans cette procédure intègrent directement les valeurs de référence réelles du laboratoire. En cas de déploiement sur une topologie tierce, veiller à substituer les chemins et désignations de services avant toute exécution.

Structure interne de l’extension

Une extension d’habillage Apache Guacamole est une archive Java autonome (structure ZIP) reconnue par le chargeur de classes de guacamole-ext. Pour être valide, l’archive doit contenir à sa racine un fichier descripteur nommé obligatoirement guac-manifest.json ainsi que l’arborescence des ressources statiques référencées :

guacamole-dark-theme.jar
├── guac-manifest.json
└── css/
└── dark-theme-v2.css

Étapes d’exécution

1. Préparation de l’environnement temporaire d’assemblage

Afin de garantir l’intégrité du système d’exploitation en cours de production et d’éviter tout résidu dans les répertoires applicatifs, l’ensemble des opérations de composition est réalisé dans un espace temporaire dédié sous /tmp/guac-dark.

Création de l arborescence de travail et bascule dans le dossier
mkdir -p /tmp/guac-dark/css && cd /tmp/guac-dark

Vérifier que le répertoire courant correspond bien à l’espace temporaire créé.

2. Génération du manifeste d’extension guac-manifest.json

Le manifeste indique au servlet Guacamole les métadonnées de l’extension ainsi que les fichiers CSS ou JavaScript à injecter dynamiquement dans le contexte de l’application web. La version spécifiée avec le caractère universel "*" garantit la compatibilité ascendante avec les révisions mineures de la passerelle. L’espace de noms est fixé à guac-dark-theme-v2 afin de forcer la rupture de cache mandataire.

cat << 'EOF' > guac-manifest.json
{
"guacamoleVersion": "*",
"name": "Guacamole Dark Theme",
"namespace": "guac-dark-theme-v2",
"css": [
"css/dark-theme-v2.css"
]
}
EOF

Contrôler la conformité syntaxique du fichier JSON produit :

cat guac-manifest.json

3. Rédaction de la feuille de style CSS d’habillage sombre

La feuille de style css/dark-theme-v2.css applique une palette moderne à contraste élevé (fond primaire #18191a, conteneurs secondaires #242526, bordures #3e4042 et texte blanc pur #ffffff). Elle contient les surcharges spécifiques indispensables pour écraser les directives CSS natives de Guacamole :

• Conteneur central et vues : surcharge des classes .white-wrapper, .base-wrapper, .view et .settings afin d’éliminer les aplats blancs.

• Onglets de navigation : surcharge de .page-tabs .page-list li a[href] pour assurer la visibilité des onglets non sélectionnés et actifs.

• Menu utilisateur Dozyxio : neutralisation du fond gris clair .menu-dropdown .menu-contents et inversion chromatique des pictogrammes SVG.

• Sélecteur hiérarchique Lieu : ciblage direct de div.location et .location-chooser pour uniformiser l’arrière-plan des sélecteurs de groupe.

cat > css/dark-theme-v2.css << 'EOF'
:root {
–bg-primary: #18191a;
–bg-secondary: #242526;
–bg-tertiary: #333538;
–text-white: #ffffff;
–text-muted: #b0b3b8;
–hover-bg: #2d3748;
–border-color: #3e4042;
–accent-blue: #4da3ff;
}
html, body, p, span, li, div, label, h1, h2, h3, h4, th, td { color: var(–text-white) !important; }
html, body { background: var(–bg-primary) !important; background-color: var(–bg-primary) !important; }
a, a:link, a:visited, .caption, .name, .connection-name { color: var(–text-white) !important; text-decoration: none !important; }
a:hover { color: var(–accent-blue) !important; }
.menu-dropdown .menu-contents, .user-menu .menu-dropdown .menu-contents, div.menu-contents {
background: var(–bg-secondary) !important; background-color: var(–bg-secondary) !important;
border: 1px solid var(–border-color) !important; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.7) !important;
}
.menu-dropdown .menu-contents *, .user-menu .menu-contents * { color: var(–text-white) !important; }
.menu-dropdown .menu-contents li a:hover, .user-menu .menu-contents li a:hover { background: var(–hover-bg) !important; color: var(–text-white) !important; }
div.location, .location-chooser, .location-chooser .location, table td div.location {
background: var(–bg-tertiary) !important; color: var(–text-white) !important;
border: 1px solid var(–border-color) !important; border-radius: 4px !important;
}
.location-chooser .dropdown { background: var(–bg-secondary) !important; border: 1px solid var(–border-color) !important; }
.page-tabs, .page-tabs .page-list ul, .section-tabs ul { background: var(–bg-primary) !important; border-bottom: 1px solid var(–border-color) !important; }
.page-tabs .page-list li a[href], .section-tabs li a { background: var(–bg-secondary) !important; color: var(–text-muted) !important; }
.page-tabs .page-list li a[href]:hover { background: var(–hover-bg) !important; color: var(–text-white) !important; }
.page-tabs .page-list li a[href].current { background: var(–bg-tertiary) !important; color: var(–text-white) !important; border-top: 3px solid var(–accent-blue) !important; }
.white-wrapper, .base-wrapper, .view, .settings, .preferences, .section { background: var(–bg-primary) !important; color: var(–text-white) !important; }
table, table.sorted, table.user-list, table.history-list { background: var(–bg-secondary) !important; border-color: var(–border-color) !important; }
table th, table.sorted th { background: var(–bg-tertiary) !important; color: var(–text-white) !important; border: 1px solid var(–border-color) !important; }
table td, table.sorted td { background: var(–bg-secondary) !important; color: var(–text-white) !important; border: 1px solid var(–border-color) !important; }
table tr:hover td { background: var(–hover-bg) !important; }
fieldset, form:not(.inline) fieldset, .form, .choice { background: var(–bg-secondary) !important; border-color: var(–border-color) !important; }
input, select, textarea, .filter, .filter input { background: var(–bg-tertiary) !important; color: var(–text-white) !important; border: 1px solid var(–border-color) !important; }
button, input[type="submit"], .button { background-color: var(–accent-blue) !important; color: #ffffff !important; border: none !important; }
.all-connections, .connection-group, .connection, .list-item { background: var(–bg-secondary) !important; }
.icon, .protocol-icon, .connection .icon, .list-item .icon { filter: brightness(0) invert(1) !important; }
.connection:hover, .list-item:hover, .connection.selected { background: var(–hover-bg) !important; }
.header, .header-bar, .user-menu, .menu-dropdown, .dialog, .modal, .panel, .clipboard { background: var(–bg-secondary) !important; border-color: var(–border-color) !important; }
EOF

4. Compression et compilation de l’archive JAR

L’archive JAR est assemblée sans dépendance externe à l’utilitaire zip au moyen du module standard zipfile de Python 3. L’archive encapsule le fichier guac-manifest.json à la racine et l’arborescence css/dark-theme-v2.css.

Fabrication de l archive d extension JAR via Python 3
python3 -c "import zipfile; z = zipfile.ZipFile('guacamole-dark-theme.jar', 'w'); z.write('guac-manifest.json'); z.write('css/dark-theme-v2.css')"
Contrôle de l intégrité et de la taille de l archive
ls -lh guacamole-dark-theme.jar

Sortie attendue : un fichier d’environ 1,7 Ko à 2 Ko.

5. Déploiement et attribution des permissions d’accès

L’archive JAR est positionnée dans le répertoire officiel des extensions analysé par Guacamole à chaque initialisation. Les permissions sont restreintes en lecture seule universelle (0644) avec propriété root:root.

Création préventive du dossier extensions si absent
mkdir -p /etc/guacamole/extensions
Copie de l extension compilée vers son emplacement définitif
cp guacamole-dark-theme.jar /etc/guacamole/extensions/
Verrouillage des privilèges de lecture
chmod 644 /etc/guacamole/extensions/guacamole-dark-theme.jar
Contrôle des attributs du fichier
ls -l /etc/guacamole/extensions/guacamole-dark-theme.jar

Sortie attendue : -rw-r–r– 1 root root … guacamole-dark-theme.jar

6. Redémarrage du conteneur de servlets Apache Tomcat

Apache Guacamole charge ses extensions exclusivement lors du démarrage de son contexte de servlets. Le service Tomcat doit être redémarré pour instancier l’extension et injecter le nouveau style.

Redémarrage du service Tomcat (adapté selon version 9 ou 10)
systemctl restart tomcat9 2>/dev/null || systemctl restart tomcat10 2>/dev/null || systemctl restart tomcat
Contrôle du statut opérationnel du service
systemctl is-active tomcat9 2>/dev/null || systemctl is-active tomcat10 2>/dev/null || systemctl is-active tomcat

Sortie attendue : actif (active / running).

7. Nettoyage des fichiers temporaires

Suppression de l’espace temporaire /tmp/guac-dark afin de laisser l’hôte dans un état rigoureusement propre.

cd ~ && rm -rf /tmp/guac-dark

8. Purge du cache mandataire et validation client

Afin de contraindre le navigateur et le proxy inverse Nginx Proxy Manager à récupérer la feuille de style actualisée plutôt qu’une version résiduelle en cache mémoire, appliquer les consignes suivantes :

• Rechargement forcé du navigateur : sur la page Guacamole, exécuter la combinaison de touches Ctrl + F5 (ou Shift + F5 sous Chrome/Edge/Firefox).

• Validation en navigation privée : ouvrir une fenêtre de navigation privée vers https://guacamole.adm.dozylab.lan pour garantir l’absence de cache local.

Procédure de retour arrière

En cas d’anomalie visuelle, de régression d’affichage ou de blocage du serveur d’application, le retour à la présentation graphique native par défaut de Guacamole s’effectue sans risque en appliquant le protocole suivant :

Situation constatéeAction corrective de repli
Régression visuelle ou incompatibilité CSSSupprimer /etc/guacamole/extensions/guacamole-dark-theme.jar, redémarrer Tomcat via systemctl restart tomcat*, puis vider le cache du navigateur (Ctrl + F5).
Échec du démarrage du service TomcatVérifier les droits 0644 de l’archive. En cas d’archive corrompue, retirer le fichier du dossier extensions et relancer le service.
Conflit d’extension avec un module tiersRenommer le fichier avec l’extension .disabled dans /etc/guacamole/extensions/, redémarrer Tomcat et inspecter /var/log/tomcat*/catalina.out.

Pièges connus et retours d’expérience

Symptôme observéCause racine identifiéeRésolution appliquée
Troncature de commandes lors du collage en console (lignes fusionnées avec échec syntaxique)Saturation du tampon de saisie (paste buffer) de l’émulateur web noVNC/SPICE sous Proxmox VE.Scinder les blocs de script et utiliser des heredocs compacts sans espaces superflus.
Persistance de larges bandes blanches sur la page Paramètres et PréférencesSélecteurs internes Guacamole .white-wrapper et .base-wrapper forçant un arrière-plan blanc par défaut.Cibler explicitement .white-wrapper et .base-wrapper avec directive !important dans la feuille CSS.
Libellés d’onglets illisibles sur la vue de gestion des paramètresSélecteur natif .page-tabs .page-list li a[href] appliquant un style noir forcé sur fond transparent.Définir explicitement les couleurs d’onglets inactifs, survolés et actifs (.current) avec contraste blanc.
Menu utilisateur (Dozyxio) restant blanc avec texte masquéLa classe .menu-dropdown .menu-contents applique la propriété background: #EEE qui outrepasse background-color.Déclarer simultanément background et background-color sur .menu-contents et inverser les pictogrammes.
Champ de sélection "Lieu" conservant un fond blanc éclatantLe champ Lieu n’est pas un input HTML mais une directive AngularJS complexe (location-chooser).Surcharger spécifiquement div.location, .location-chooser et .location-chooser .dropdown.
Styles CSS non appliqués malgré le redémarrage réussi de TomcatMise en cache HTTP persistante du nom de fichier par le proxy Nginx Proxy Manager et le navigateur.Incrémenter le namespace et le nom de fichier (dark-theme-v2.css) dans le manifeste JSON.

5 Intégration réseau

Identité et adressage de l’instance

Propriété d’infrastructureValeur de configuration
Hôte d’hébergementConteneur LXC Proxmox VE (grappe de virtualisation pve1/pve2/pve3)
Système d’exploitationDebian GNU/Linux 13 (Trixie) – noyau Linux 6.8+
Adresse IPv4 locale10.10.10.20 (VLAN 10 – Administration DozyLab)
Nom d’hôte localguacamole
Nom de domaine complet (FQDN)guacamole.adm.dozylab.lan (résolution Technitium DNS)
Moteur applicatif de servletsApache Tomcat 9/10 écoutant sur TCP 8080 en boucle locale
Démon mandataire natifguacd écoutant sur 127.0.0.1:4822
Reverse proxy frontalNginx Proxy Manager (relais frontal HTTPS 443 vers TCP 8080)

Matrice des flux réseau

SourceDestinationPort / Prot.ActionRôle du flux
Postes d’administrationNPM (10.10.10.x)TCP 443AutoriséAccès sécurisé HTTPS à l’interface web
Nginx Proxy Manager10.10.10.20TCP 8080AutoriséRelais mandataire HTTP vers Apache Tomcat
127.0.0.1 (Tomcat)127.0.0.1 (guacd)TCP 4822AutoriséProtocole d’instructions tunnelisé Guacamole
10.10.10.20 (guacd)Hôtes cibles (LAN)TCP 22 / 3389AutoriséSessions d’administration distantes SSH et RDP

Dépendances et points de défaillance

Composant d’infrastructureImpact d’une défaillanceMesure de résilience / Contournement
Conteneur de servlets TomcatIndisponibilité totale de l’interface web Guacamole.Supervision systemd avec redémarrage automatique en cas de plantage.
Reverse proxy Nginx Proxy ManagerRupture de la terminaison TLS et de l’accès par FQDN.Accès d’urgence direct possible en HTTP sur http://10.10.10.20:8080/guacamole/.
Résolution Technitium DNSImpossibilité de joindre le FQDN guacamole.adm.dozylab.lan.Entrée statique de secours consignée dans le fichier hosts des postes d’administration.

6 Durcissement et sécurité

• Principe de moindre intrusion logicielle : l’utilisation de l’API officielle guacamole-ext évite toute modification du fichier WAR d’origine et préserve l’intégrité des signatures et paquetages officiels d’Apache Guacamole, assurant la pérennité des futures mises à jour.

• Verrouillage des privilèges sur les extensions : l’archive JAR est positionnée sous la propriété stricte de root:root avec permissions 0644 (lecture seule pour le compte de service Tomcat), prévenant toute altération ou injection malveillante dans le contexte applicatif.

• Innocuité du code embarqué : l’extension est strictement déclarative. Elle ne contient aucune classe Java binaire exécutable (.class) ni aucun script exécutable côté client, limitant le périmètre fonctionnel à la restitution stylistique CSS.

• Conformité ergonomique et contraste visuel : les contrastes colorimétriques appliqués entre le texte blanc (#ffffff) et les fonds d’écran (#18191a, #242526) respectent les recommandations WCAG AA, avec un rapport de contraste supérieur à 12:1 (environ 15:1 à 18:1 d’après le calcul à partir des codes couleur), ce qui favorise la lisibilité sur fond sombre.

Dettes techniques

Point technique identifiéImpact sur l’infrastructureStatut / Traitement
Couplage fort avec le DOM AngularJSUne évolution majeure du code frontend de Guacamole pourrait renommer certaines classes CSS (.white-wrapper).Accepté — Procédure de mise à jour CSS documentée et facilement modifiable dans l’archive JAR.
Application globale sans sélecteur individuelL’ensemble des utilisateurs authentifiés sur la passerelle bascule obligatoirement sur le thème sombre.Conforme au besoin — Homelab administré par un opérateur unique privilégiant le confort visuel sombre.

7 Vérifications finales

Contrôle opérationnelCritère d’acceptation mesurableStatut
Intégrité de l’archive JARunzip -t /etc/guacamole/extensions/guacamole-dark-theme.jar renvoie No errors detected.☑ Conforme
Attributs et permissions UnixPermissions 0644 et propriété root:root sur l’archive déployée.☑ Conforme
Prise en compte par TomcatJournal catalina.out confirmant le chargement de l’extension sans exception levée.☑ Conforme
Écran d’authentification GuacamoleFond de page sombre (#18191a), formulaire de saisie contrasté et libellés blancs lisibles.☑ Conforme
Tableau de bord des connexionsListe des hôtes SSH/RDP et miniatures récentes affichées en texte blanc avec survol bleu-gris.☑ Conforme
Pictogrammes de protocolesInversion chromatique réussie : icônes de terminal, moniteur et flèches affichées en blanc pur.☑ Conforme
Menu contextuel utilisateurSous-menu Dozyxio sur fond sombre (#242526), séparateurs discrets et icônes blanches.☑ Conforme
Pages d’administration et paramètresAbsence intégrale de zones blanches sur les onglets Sessions, Historique, Utilisateurs et Préférences.☑ Conforme
Éditeur de connexion et champ LieuSélecteur de groupe de connexion affiché sur fond sombre sans artefact visuel résiduel.☑ Conforme

8 Références et historique des révisions

Documentation éditeur

• Apache Guacamole : Guacamole Manual – Chapter 5: Customizing Guacamole. Établit la structure formelle de guac-manifest.json et le protocole d’injection des feuilles de style d’extension.

• Apache Guacamole : Guacamole Extension API (guacamole-ext). Spécification technique du cycle de vie des extensions applicatives au sein du conteneur de servlets.

• Nginx Proxy Manager : NPM Documentation – Cache Assets and Proxy Buffer Tuning. Bonnes pratiques de paramétrage des en-têtes de cache pour applications web temps réel.

Documents associés

• HL-PRC-008 : Configuration des connexions SSH et RDP sur Apache Guacamole.

• HL-PRC-011 : Guacamole – Redirection de lecteur RDP.

• HL-PRC-012 : ProxPanel – Publication Reverse Proxy NPM.

Historique des révisions

VersionDateAuteurModifications
0.102/11/2026Administrateur système et réseauxCréation initiale de la procédure suite au déploiement et à la validation du thème sombre sur l’instance Guacamole.
Défiler vers le haut