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 : déploiement sécurisé avec Docker et Tailscale
Également disponible en English, Deutsch, Español, Nederlands.

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