docs/install/hetzner.md
Run a persistent OpenClaw Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior.
If you want “OpenClaw 24/7 for ~$5”, this is the simplest reliable setup. Hetzner pricing changes; pick the smallest Debian/Ubuntu VPS and scale up if you hit OOMs.
Security model reminder:
See Security and VPS hosting.
~/.openclaw + ~/.openclaw/workspace on the host (survives restarts/rebuilds)That mounted ~/.openclaw state includes openclaw.json, per-agent
agents/<agentId>/agent/auth-profiles.json, and .env.
The Gateway can be accessed via:
This guide assumes Ubuntu or Debian on Hetzner.
If you are on another Linux VPS, map packages accordingly.
For the generic Docker flow, see Docker.
.env and docker-compose.ymldocker compose up -dConnect as root:
```bash
ssh root@YOUR_VPS_IP
```
This guide assumes the VPS is stateful.
Do not treat it as disposable infrastructure.
Verify:
```bash
docker --version
docker compose version
```
This guide assumes you will build a custom image to guarantee binary persistence.
```bash
mkdir -p /root/.openclaw/workspace
# Set ownership to the container user (uid 1000):
chown -R 1000:1000 /root/.openclaw
```
```bash
OPENCLAW_IMAGE=openclaw:latest
OPENCLAW_GATEWAY_TOKEN=
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_CONFIG_DIR=/root/.openclaw
OPENCLAW_WORKSPACE_DIR=/root/.openclaw/workspace
GOG_KEYRING_PASSWORD=
XDG_CONFIG_HOME=/home/node/.openclaw
```
Leave `OPENCLAW_GATEWAY_TOKEN` blank unless you explicitly want to
manage it through `.env`; OpenClaw writes a random gateway token to
config on first start. Generate a keyring password and paste it into
`GOG_KEYRING_PASSWORD`:
```bash
openssl rand -hex 32
```
**Do not commit this file.**
This `.env` file is for container/runtime env such as `OPENCLAW_GATEWAY_TOKEN`.
Stored provider OAuth/API-key auth lives in the mounted
`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
```yaml
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE}
build: .
restart: unless-stopped
env_file:
- .env
environment:
- HOME=/home/node
- NODE_ENV=production
- TERM=xterm-256color
- OPENCLAW_GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND}
- OPENCLAW_GATEWAY_PORT=${OPENCLAW_GATEWAY_PORT}
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
- GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD}
- XDG_CONFIG_HOME=${XDG_CONFIG_HOME}
- PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports:
# Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel.
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
- "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789"
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"${OPENCLAW_GATEWAY_BIND}",
"--port",
"${OPENCLAW_GATEWAY_PORT}",
"--allow-unconfigured",
]
```
`--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
- [Bake required binaries into the image](/install/docker-vm-runtime#bake-required-binaries-into-the-image)
- [Build and launch](/install/docker-vm-runtime#build-and-launch)
- [What persists where](/install/docker-vm-runtime#what-persists-where)
- [Updates](/install/docker-vm-runtime#updates)
**Prerequisite:** Ensure your VPS sshd config allows TCP forwarding. If you
have hardened your SSH config, check `/etc/ssh/sshd_config` and set:
```
AllowTcpForwarding local
```
`local` allows `ssh -L` local forwards from your laptop while blocking
remote forwards from the server. Setting it to `no` will fail the tunnel
with:
`channel 3: open failed: administratively prohibited: open failed`
After confirming TCP forwarding is enabled, restart the SSH service
(`systemctl restart ssh`) and run the tunnel from your laptop:
```bash
ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP
```
Open:
`http://127.0.0.1:18789/`
Paste the configured shared secret. This guide uses the gateway token by
default; if you switched to password auth, use that password instead.
The shared persistence map lives in Docker VM Runtime.
For teams preferring infrastructure-as-code workflows, a community-maintained Terraform setup provides:
Repositories:
This approach complements the Docker setup above with reproducible deployments, version-controlled infrastructure, and automated disaster recovery.
<Note> Community-maintained. For issues or contributions, see the repository links above. </Note>