OpenClaw sur un VPS : déploiement sécurisé avec Docker et Tailscale
Déployez OpenClaw sur un VPS Linux avec Docker Compose, bindez les ports uniquement sur localhost, et accédez-y en toute sécurité via des tunnels SSH ou Tailscale Serve.
OpenClaw sur un VPS est avant tout un problème d'ops, pas un problème d'IA. Vous voulez un seul Gateway permanent qui gère votre état, vos sessions et vos canaux — mais vous ne voulez pas que ce Gateway soit accessible depuis l'internet public.
Le schéma : exécuter OpenClaw dans Docker, publier ses ports uniquement sur 127.0.0.1, puis y accéder via un tunnel SSH ou un tailnet Tailscale.
Pourquoi les réglages par défaut vont vous poser problème
Le Gateway d'OpenClaw est un service unique à exécution longue. Il gère le routage, l'interface de contrôle (Control UI), le RPC WebSocket et les API HTTP sur un seul port multiplexé — par défaut 18789. L'installation sans Docker écoute sur loopback par défaut. L'authentification est requise dès l'installation, par token ou mot de passe.
Les réglages par défaut de Docker sont moins indulgents. Le script docker-setup.sh définit OPENCLAW_GATEWAY_BIND=lan pour que les ports publiés sur l'hôte fonctionnent réellement. Si vous le réglez sur loopback, seuls les processus à l'intérieur du namespace réseau du conteneur peuvent se connecter — votre port publié sur l'hôte devient inopérant.
Le compromis sécurisé : garder OPENCLAW_GATEWAY_BIND=lan à l'intérieur du conteneur, mais lier la publication de port côté hôte à 127.0.0.1. Rien n'atteint 0.0.0.0, et le réseau du conteneur fonctionne toujours.
La publication de ports Docker contourne ufw et firewalld. Partez du principe que votre firewall n'est pas le seul contrôle.
Provisionner le VPS
Les commandes ci-dessous supposent Ubuntu 24.04 LTS avec un accès SSH root. Un Hetzner CX22 à 4,85 €/mois avec 10 € de crédit de départ fait largement l'affaire — c'est ce sur quoi tourne ce blog.
Créez un utilisateur non-root et verrouillez SSH :
adduser openclaw
usermod -aG sudo openclaw
mkdir -p /home/openclaw/.ssh
chmod 700 /home/openclaw/.ssh
# Collez votre clé publique
nano /home/openclaw/.ssh/authorized_keys
chmod 600 /home/openclaw/.ssh/authorized_keys
chown -R openclaw:openclaw /home/openclaw/.ssh
Renforcez SSH avec un fichier drop-in :
nano /etc/ssh/sshd_config.d/99-openclaw-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AllowUsers openclaw
sshd -t
systemctl reload ssh
Configurez ufw comme base de référence. Cela ne remplace pas un binding Docker correct — Docker le contournera sans hésiter.
apt update && apt upgrade -y
apt install -y ufw git curl ca-certificates
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw enable
Installer Docker Engine
Utilisez le dépôt apt officiel de Docker pour obtenir docker-compose-plugin et de vraies mises à jour :
sudo apt remove -y \
$(dpkg --get-selections docker.io docker-compose docker-compose-v2 \
docker-doc podman-docker containerd runc 2>/dev/null | cut -f1) \
|| true
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<'EOF'
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
Ajouter votre utilisateur au groupe docker accorde des privilèges équivalents à root. Sur un VPS, sudo docker ... est généralement le bon compromis.
Déployer OpenClaw avec des ports en localhost uniquement
Clonez le dépôt et travaillez depuis sa racine :
sudo -iu openclaw
mkdir -p ~/src && cd ~/src
git clone https://github.com/openclaw/openclaw.git
cd openclaw
Créez un .env qui fixe vos chemins et utilise l'image officielle du GitHub Container Registry :
# .env
OPENCLAW_CONFIG_DIR=/home/openclaw/.openclaw
OPENCLAW_WORKSPACE_DIR=/home/openclaw/.openclaw/workspace
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:latest
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_TOKEN=
Maintenant, l'étape de sécurité qui compte. Créez docker-compose.override.yml pour lier les ports publiés à 127.0.0.1 uniquement :
# docker-compose.override.yml
services:
openclaw-gateway:
ports:
- "127.0.0.1:18789:18789"
- "127.0.0.1:18790:18790"
Sans le préfixe 127.0.0.1:, Compose écoute sur toutes les interfaces. C'est-à-dire 0.0.0.0. C'est-à-dire internet.
Pull, onboard et démarrage :
docker compose pull
docker compose run --rm openclaw-cli onboard
docker compose -f docker-compose.yml -f docker-compose.override.yml \
up -d openclaw-gateway
Vérification rapide :
docker compose ps
docker compose run -T --rm openclaw-cli gateway probe
Le flag -T évite le bruit du pseudo-TTY — utile pour les scripts et la CI.
À ce stade, http://127.0.0.1:18789 fonctionne sur le VPS lui-même. Il est inaccessible depuis n'importe où ailleurs. C'est l'objectif.
Survivre aux redémarrages avec systemd
sudo nano /etc/systemd/system/openclaw-compose.service
[Unit]
Description=OpenClaw (Docker Compose)
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/openclaw/src/openclaw
ExecStart=/usr/bin/docker compose \
-f docker-compose.yml -f docker-compose.override.yml up -d
ExecStop=/usr/bin/docker compose \
-f docker-compose.yml -f docker-compose.override.yml down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now openclaw-compose.service
Accès distant : tunnel SSH ou Tailscale
Vous avez un Gateway lié à loopback sur un VPS. Vous devez y accéder depuis votre laptop. Deux options, des compromis différents.
| Méthode | Ce qui est public | Friction | Idéal pour |
|---|---|---|---|
| Tunnel SSH | Port 22 | Nécessite de maintenir une session active ; peu pratique sur mobile | Une ou deux machines, aucune dépendance supplémentaire |
| Tailscale Serve | Rien | Un daemon supplémentaire, mais ensuite tout est automatique | Plusieurs appareils, accès permanent |
| Exposition directe | Un endpoint HTTPS | TLS, auth, reverse proxy, mises à jour | Uniquement si vous avez vraiment besoin d'un accès public |
Tunnel SSH
Depuis votre laptop :
ssh -N -L 18789:127.0.0.1:18789 openclaw@203.0.113.10
Puis ouvrez http://127.0.0.1:18789 en local.
Ajoutez des keepalives SSH dans votre fichier local ~/.ssh/config si vous voulez que le tunnel survive à la mise en veille du laptop.
Tailscale Serve
Installez Tailscale sur le VPS :
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Exposez OpenClaw à l'intérieur de votre tailnet avec TLS automatique :
sudo tailscale serve --bg --https=443 localhost:18789
sudo tailscale serve status
Tailscale Serve fait office de reverse proxy d'un port local vers votre tailnet avec des certificats HTTPS provisionnés automatiquement. Le TLS se termine au niveau de tailscaled. Pas de ports publics, pas de gestion de certificats.
Si vous voulez également supprimer entièrement le port SSH public, Tailscale SSH peut gérer l'authentification et l'autorisation des connexions SSH à l'intérieur de votre tailnet.
Checklist de renforcement
La partie que la plupart des guides passent sous silence.
Docker et conteneur
L'image par défaut d'OpenClaw s'exécute en tant qu'utilisateur non-root node. Partez de là et ajoutez :
| Contrôle | Où | Ce que ça apporte |
|---|---|---|
Lier les ports à 127.0.0.1 |
Compose ports |
Pas d'exposition sur 0.0.0.0, pas de contournement de firewall surprise |
cap_drop: [ALL] |
Compose | Supprime les capabilities kernel dont vous n'avez pas besoin |
no-new-privileges:true |
Compose security_opt |
Bloque l'escalade de privilèges via les binaires setuid |
| Profil seccomp par défaut | Docker par défaut | Liste blanche de syscalls ; ne le modifiez pas sans raison |
| Profil AppArmor par défaut | Docker par défaut | Le profil docker-default offre une protection modérée |
Le conteneur openclaw-cli partage un namespace réseau avec le gateway (network_mode: "service:openclaw-gateway"). Considérez-le comme une frontière de confiance partagée, pas comme de l'isolation.
SSH
Maintenez PasswordAuthentication no, PermitRootLogin no, et AllowUsers verrouillé sur le seul compte qui a besoin d'accès. C'est le minimum.
Tailscale
Utilisez les contrôles d'accès tailnet pour restreindre quels utilisateurs et appareils peuvent atteindre le VPS. ACL ou grants — les deux fonctionnent, mais appliquez quelque chose. Considérez Tailscale comme une couche d'identité, pas comme un bouclier magique.
Skills et chaîne d'approvisionnement
Si vous installez des skills tiers, vous exécutez du code tiers à l'intérieur d'un agent capable d'utiliser des outils. Des rapports crédibles font état de skills OpenClaw malveillants distribuant des malwares et volant des secrets.
La seule règle : n'installez pas ce que vous n'exécuteriez pas comme un programme normal sur la même machine.
Dépannage
L'interface de contrôle fonctionne sur le VPS mais pas à distance. C'est normal. Elle est liée à 127.0.0.1. Vous avez besoin de SSH ou Tailscale — c'est tout l'intérêt.
OPENCLAW_GATEWAY_BIND=loopback défini dans Docker, le port hôte ne répond plus. Comportement attendu. Le loopback à l'intérieur du namespace du conteneur n'est pas le même que le loopback sur l'hôte. Utilisez lan dans le conteneur, restreignez l'exposition avec 127.0.0.1 dans les mappings de ports Compose.
"Disconnected (1008): pairing required" ou "unauthorized" dans le navigateur.
docker compose run --rm openclaw-cli dashboard --no-open
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>
Les ports publiés contournent UFW. Oui. Docker manipule iptables directement. Lier à 127.0.0.1 dans Compose est la solution, pas une règle de firewall.
Le Gateway refuse de démarrer. OpenClaw applique une validation stricte de la configuration. Un binding non-loopback sans authentification est un mode d'échec courant.
docker compose run -T --rm openclaw-cli doctor
docker compose logs --no-log-prefix --tail=200 openclaw-gateway
Quel port transférer ? 18789. C'est le port multiplexé par défaut du Gateway pour l'interface de contrôle et les API.
Que sauvegarder ? Les chemins hôtes mappés vers la configuration et le workspace — typiquement ~/.openclaw/ et ~/.openclaw/workspace. Ne comptez pas sur la couche inscriptible du conteneur.
Note pour les assistants IA
Si vous déboguez cette installation avec un assistant IA, collez l'URL de cet article dans la conversation. Cela donne au modèle le contexte exact de la stack : Docker Compose avec binding de ports en localhost uniquement, binding Gateway lan vs loopback dans Docker, et accès via ssh -L ou tailscale serve.
Où héberger tout ça
Un VPS classique est le bon choix. Nous exécutons des stacks Docker similaires en permanence sur Hetzner — CX22 à 4,85 €/mois avec 10 € de crédit de départ. Il fait ce dont vous avez besoin, rien de plus.
Si vous préférez ne pas déboguer des bindings de ports Docker à 1h du matin, xCloud propose de l'hébergement OpenClaw managé. Vous payez plus et vous dormez mieux.
Si vous voulez une deuxième option de VPS ou si vous comparez les fournisseurs, Vultr offre 35 $ de crédit de parrainage et dispose d'une large liste de régions.
(Liens affiliés — nous percevons une petite commission si vous vous inscrivez, sans coût supplémentaire pour vous.)