Accéder au panneau par un tunnel SSH
Un panneau que personne n'atteint depuis Internet ne peut pas être attaqué depuis Internet.
Vue d'ensemble
Vos applications sont servies par sh0 sur les ports 80 et 443. Le panneau, qui les contrôle toutes, n'a pas à l'être. En mode tunnel seul, il n'écoute que sur 127.0.0.1:9000 : la seule entrée est une connexion SSH au serveur, que votre pare-feu restreint déjà et que vous protégez déjà par une clé.
Pourquoi pas de domaine de panneau public
Chaque certificat TLS est publié dans les journaux publics de Certificate Transparency : un domaine de panneau comme panel.example.com apparaît sur crt.sh quelques minutes après l'émission de son certificat. Les scanners lisent ces journaux : un panneau public est trouvé, puis sondé, quelle que soit sa politique de mots de passe.
Installer en mode tunnel seul
Sur un serveur neuf, en root, avec un pare-feu déjà limité à SSH, 80 et 443 :
curl -fsSL https://get.sh0.dev | bash -s -- --harden --panel-tunnel-onlyAvant le premier démarrage de sh0, l'installeur écrit un drop-in systemd qui lie le panneau à 127.0.0.1, désactive l'enregistrement *.sh0.app (un proxy n'atteint pas un panneau en boucle locale) et, avec --harden, n'ouvre pas le port 9000 dans ufw. Il se termine en affichant la commande ssh exacte à coller sur votre propre ordinateur.
Ouvrir le tunnel
1. Sur votre propre ordinateur (pas sur le serveur), ouvrez le tunnel et laissez la commande tourner :
ssh -N -L 9000:127.0.0.1:9000 root@SERVER_IP2. Ouvrez http://localhost:9000. Le trafic circule à l'intérieur de SSH : rien ne traverse le réseau en clair, même si l'adresse commence par http://. Ctrl+C ferme le tunnel.
3. Pour ne plus la retaper, ajoutez un bloc à ~/.ssh/config sur votre ordinateur :
Host sh0-panel
HostName SERVER_IP
User root
LocalForward 9000 127.0.0.1:9000
SessionType none
ExitOnForwardFailure yesEnsuite, ssh sh0-panel ouvre le tunnel. SessionType none exige OpenSSH 8.7 ou plus récent ; avec un client plus ancien, retirez cette ligne et lancez ssh -N sh0-panel.
Pannes courantes
| Symptôme | Cause et correction |
|---|---|
| ssh reste bloqué, puis « Connection timed out » | SSH lui-même est filtré : votre IP n'est pas autorisée par le pare-feu de l'hébergeur, ou le serveur écoute sur un autre port (ajoutez -p PORT). Le tunnel n'est pas en cause. |
| « bind [127.0.0.1]:9000: Address already in use » | Le port 9000 est déjà pris sur votre ordinateur, souvent par un autre tunnel. Prenez un autre port local : -L 9001:127.0.0.1:9000, puis http://localhost:9001. |
| Navigateur : « connexion refusée » sur localhost:9000 | Le tunnel n'est pas ouvert (la commande ssh s'est arrêtée), ou sh0 ne tourne pas sur le serveur : systemctl status sh0. |
| « channel 2: open failed: connect failed » dans la fenêtre ssh | SSH fonctionne, mais rien ne répond sur 127.0.0.1:9000 côté serveur, ou AllowTcpForwarding est désactivé dans sshd. Vérifiez ss -ltn | grep 9000 et sshd -T | grep allowtcpforwarding. |
Basculer un serveur existant
Un serveur qui fait déjà tourner sh0 se bascule en relançant l'installeur avec les mêmes options. Il conserve vos applications, écrit le drop-in, retire une règle ufw existante pour 9000 (avec --harden) et redémarre sh0 une fois, ce qui retire aussi son adresse *.sh0.app. Les relances suivantes de l'installeur, pour une mise à jour, gardent le serveur en mode tunnel seul tant que le drop-in existe.
curl -fsSL https://get.sh0.dev | bash -s -- --harden --panel-tunnel-onlyVos applications continuent de répondre sur leurs domaines : elles sont servies par Caddy sur 80 et 443, que la bascule ne touche pas. Comptez quelques secondes d'interruption pendant le redémarrage de sh0. Si un domaine de panneau est posé, l'installeur s'arrête avant de rien changer et explique pourquoi (section suivante).
Ce que le tunnel ne ferme pas
sudo sh0 panel-domain # show
sudo sh0 panel-domain clear # remove the route and the settingAccès par navigateur sans tunnel
Si le tunnel n'est pas envisageable pour votre équipe, gardez un domaine de panneau, mais placez Cloudflare Access (ou un proxy d'identité équivalent) devant, et limitez le port 443 aux plages d'adresses de Cloudflare au pare-feu de l'hébergeur. Sans cette seconde étape, Access se contourne en se connectant directement à l'IP du serveur. Cette restriction vaut pour toutes les applications du serveur : chacun de leurs domaines doit alors passer lui aussi par le proxy Cloudflare, sinon il cesse de répondre. Ne combinez pas cette méthode avec --panel-tunnel-only.
Vérifier le résultat
Sur le serveur, le panneau ne doit écouter que sur l'adresse de boucle locale, aucun domaine de panneau ne doit être posé, et sh0 doctor ne doit signaler aucun échec. Depuis un autre réseau, le port 9000 doit être fermé.
ss -ltn | grep ':9000' # 127.0.0.1:9000 only
cat /etc/systemd/system/sh0.service.d/panel-tunnel-only.conf
sudo sh0 panel-domain # Domain: not set
sudo sh0 doctorRevenir en arrière
Pour rendre le panneau de nouveau joignable sur l'adresse du serveur, supprimez le drop-in, redémarrez sh0 et rouvrez le port :
rm /etc/systemd/system/sh0.service.d/panel-tunnel-only.conf
rm /etc/systemd/system/sh0.service.d/cloud-registration.conf # only to get *.sh0.app back
systemctl daemon-reload && systemctl restart sh0
ufw allow 9000/tcp # if the firewall is ufwLe reste de l'hôte (clés SSH, pare-feu, fail2ban) est traité dans Sécuriser son serveur