---
title: "Deploy OpenClaw · Quick Start"
description: "Personal AI assistant gateway with web UI, Telegram and Discord"
category: "AI/ML"
url: https://railway.com/deploy/openclaw-quick-start
---

# Deploy OpenClaw · Quick Start

Personal AI assistant gateway with web UI, Telegram and Discord

**[Deploy OpenClaw · Quick Start on Railway](https://railway.com/template/openclaw-quick-start)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/openclaw-quick-start/manifest.json

- **Creator:** withSeismic
- **Category:** AI/ML

## Template content

### openclaw

- **Image:** ghcr.io/openclaw/openclaw:latest
- **Start command:** `sh -c 'set -e; S="${OPENCLAW_STATE_DIR:-/data/.openclaw}"; P="${OPENCLAW_GATEWAY_PORT:-8080}"; mkdir -p "$S" "${OPENCLAW_WORKSPACE_DIR:-/data/workspace}"; N=0; [ -f "$S/openclaw.json" ] || N=1; A=skip; [ -n "$GEMINI_API_KEY" ] && A=gemini-api-key; [ -n "$OPENROUTER_API_KEY" ] && A=openrouter-api-key; [ -n "$OPENAI_API_KEY" ] && A=openai-api-key; [ -n "$ANTHROPIC_API_KEY" ] && A=apiKey; if [ $N = 1 ] || { [ $A != skip ] && ! openclaw config get agents.defaults.model.primary >/dev/null 2>&1; }; then echo "[railway] onboarding: auth-choice=$A"; openclaw onboard --non-interactive --accept-risk --mode local --auth-choice $A --secret-input-mode ref --gateway-auth token --gateway-token-ref-env OPENCLAW_GATEWAY_TOKEN --gateway-bind lan --gateway-port "$P" --skip-channels --skip-search --skip-skills --skip-ui --skip-health --no-install-daemon; fi; if [ $N = 1 ]; then openclaw config set --batch-json "[{\"path\":\"gateway.publicOrigin\",\"value\":\"\${OPENCLAW_PUBLIC_ORIGIN}\"},{\"path\":\"gateway.trustedProxies\",\"value\":[\"100.64.0.0/10\"]}]"; fi; exec tini -s -- node /app/docker-entrypoint.mjs node /app/openclaw.mjs gateway --allow-unconfigured --bind lan --port "$P" --ambient-channels'`
- **Health check:** /startupz
- **Public domain:** Yes

## Documentation

# Deploy and Host OpenClaw on Railway

OpenClaw (formerly Clawdbot and Moltbot) is an open-source personal AI assistant. It runs as a gateway that you chat with from its web Control UI, Telegram, Discord and other channels. This template runs the official OpenClaw image behind a generated token, keeps all state on a volume, and is set up on first boot, so you can go from deploy to chatting in a few minutes.

## About Hosting OpenClaw

- **Official image, tracking upstream.** One service from `ghcr.io/openclaw/openclaw:latest`. Nothing is built from source and there is no wrapper app in front of the gateway.
- **Token-protected gateway.** `OPENCLAW_GATEWAY_TOKEN` is generated at deploy. Authenticated HTTP routes return `401` when the token is missing or wrong, and WebSocket connections fail with `token mismatch`. Each new browser also needs a one-time device approval before it can use the gateway.
- **Browser origin locked to your domain.** The Control UI only accepts connections from the service's own HTTPS origin. Railway's proxy range is trusted, so WebSocket connections through Railway's edge work.
- **Everything durable on a volume.** Config, sessions, paired devices, agent databases and the agent workspace live under `/data`. Redeploys keep them, and the same token keeps working.
- **Set up on first boot.** The start command runs OpenClaw's headless onboarding: workspace files, token auth, and a default model if you supplied a key. Provider keys stay in Railway variables and are never written to the volume.
- **Upgrade migrations still run.** The start command keeps the image's own entrypoint, which runs `openclaw doctor --fix` before every gateway start.
- **Optional channels.** Add a Telegram or Discord bot token and that channel turns on at startup.
- **Healthcheck.** Railway waits for `/startupz`. A broken channel token does not block a deploy, so you can still reach the UI to fix it.

### Getting started

1. **Deploy.** All inputs are optional. If you have one, paste an LLM key (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `OPENROUTER_API_KEY` or `GEMINI_API_KEY`). You can also add `TELEGRAM_BOT_TOKEN` or `DISCORD_BOT_TOKEN`. The first boot takes about a minute.
2. **Copy the token.** In the `openclaw` service, open **Variables** and copy `OPENCLAW_GATEWAY_TOKEN`.
3. **Open the Control UI.** Open the service's public URL, paste the token into **Gateway secret** and connect. The page shows **pairing required** along with a command such as `openclaw devices approve 1b2c...`.
4. **Approve this browser from the container.** Install the [Railway CLI](https://docs.railway.com/cli), run `railway link` and pick this project, then run the command the page showed:
   ```bash
   railway ssh --service openclaw -- openclaw devices approve REQUEST_ID
   ```
   The page connects by itself within a few seconds. To see pending requests, run `railway ssh --service openclaw -- openclaw devices list`. You approve each browser profile once.
5. **Add a model key if you skipped it.** You can add a key under **Models** in the Control UI. Or set one of the key variables in Railway and deploy: if no default model has been chosen yet, the start command sets that provider's default model on the next boot.
6. **Chat.** Open **Chat** in the Control UI and send a message.
7. **Telegram or Discord (optional).** DM your bot. It replies with a pairing code. Approve the code with:
   ```bash
   railway ssh --service openclaw -- openclaw pairing approve telegram CODE
   ```
   Use `discord` in place of `telegram` for Discord. To add other channels, run `openclaw channels add` in an interactive `railway ssh --service openclaw` session.

## Common Use Cases

- A personal assistant you reach from Telegram or Discord, running all the time and not tied to your laptop.
- A browser-based chat and agent workspace (Control UI) for one person or a small trusted team, with each browser approved explicitly.
- Scheduled and recurring agent work (heartbeats, automations) that needs a host that is always on.
- A remote gateway for the OpenClaw CLI on your own machine, reached over `wss://` with the gateway token.

## Dependencies for OpenClaw Hosting

- The official OpenClaw container image (`ghcr.io/openclaw/openclaw:latest`).
- A Railway volume mounted at `/data`.
- Optional: an API key from an LLM provider (Anthropic, OpenAI, OpenRouter or Google Gemini) and bot tokens for the channels you want.

### Deployment Dependencies

- OpenClaw source: https://github.com/openclaw/openclaw
- Container image: https://github.com/openclaw/openclaw/pkgs/container/openclaw
- OpenClaw docs: https://docs.openclaw.ai
- Docker install guide: https://docs.openclaw.ai/install/docker
- Control UI connect and pair: https://docs.openclaw.ai/web/control-ui/connect-and-pair
- Device CLI (`openclaw devices`): https://docs.openclaw.ai/cli/devices
- Channel DM pairing: https://docs.openclaw.ai/channels/pairing
- Telegram channel: https://docs.openclaw.ai/channels/telegram
- Discord channel: https://docs.openclaw.ai/channels/discord
- Health endpoints: https://docs.openclaw.ai/gateway/health
- Railway CLI: https://docs.railway.com/cli
- Railway SSH: https://docs.railway.com/cli/ssh
- Railway volumes: https://docs.railway.com/volumes

### Implementation Details

| Variable | Default | Purpose |
| --- | --- | --- |
| `OPENCLAW_GATEWAY_TOKEN` | generated, 48 characters | Gateway auth. Paste it into **Gateway secret**. The config refers to this variable rather than copying its value. |
| `OPENCLAW_PUBLIC_ORIGIN` | `https://${{RAILWAY_PUBLIC_DOMAIN}}` | Read by `gateway.publicOrigin`, which sets the allowed browser origin. Change it when you add a custom domain. |
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `OPENROUTER_API_KEY`, `GEMINI_API_KEY` | empty | Optional. Checked in that order. The first one set picks the default model during onboarding. |
| `TELEGRAM_BOT_TOKEN`, `DISCORD_BOT_TOKEN` | empty | Optional. The gateway starts with `--ambient-channels`, so a non-empty token turns that channel on. |
| `OPENCLAW_GATEWAY_PORT`, `PORT` | `8080` | One port for HTTP, WebSocket and the Control UI. |
| `OPENCLAW_STATE_DIR` | `/data/.openclaw` | Config, credentials, sessions, devices and databases. |
| `OPENCLAW_WORKSPACE_DIR` | `/data/workspace` | The agent workspace. |
| `OPENCLAW_NO_RESPAWN` | `1` | Restarts stay in-process, as upstream recommends for containers. |
| `RAILWAY_RUN_UID` | `0` | Runs as root, because the Railway volume is root-owned. |

**What the start command does.** It is a short `sh -c` script set in the service's deploy settings:

1. When `/data/.openclaw/openclaw.json` does not exist, it runs `openclaw onboard --non-interactive`. This sets up token auth that points at `OPENCLAW_GATEWAY_TOKEN`, a LAN bind and the agent workspace. If a provider key is set, it also selects that provider's default model, using an env reference rather than storing the key. The script then sets `gateway.publicOrigin` to `${OPENCLAW_PUBLIC_ORIGIN}` and `gateway.trustedProxies` to Railway's `100.64.0.0/10` range.
2. If the config exists but has no default model, and a provider key is now set, it runs onboarding once more for that provider. Your other settings are kept.
3. It hands off to the image's own entrypoint (`tini` → `docker-entrypoint.mjs`). That entrypoint runs `openclaw doctor --fix --non-interactive` and then `openclaw gateway --allow-unconfigured --bind lan --port 8080 --ambient-channels`.

**Healthcheck.** The path is `/startupz`, with a 300 second timeout. `/healthz` (liveness) and `/readyz` (readiness, including channel health) need no auth either. A channel with a bad token makes `/readyz` return 503 while `/startupz` stays 200.

**Resources.** In testing, an idle gateway used about 2 GB of RAM.

**Upgrades.** The image tag is `latest`. Redeploy the service to pull the newest release. On every start, the image's entrypoint runs `openclaw doctor --fix`, which migrates config and state. It keeps a pre-repair capture in `/data/.openclaw.update-captures` and config backups (`openclaw.json.bak*`) next to the config. To hold a version, change the image in the service settings to a release tag such as `ghcr.io/openclaw/openclaw:2026.11.3`. To start from scratch, delete `/data/.openclaw` and redeploy. The next boot runs onboarding again.

**Custom domain.** Add the domain in Railway, then set `OPENCLAW_PUBLIC_ORIGIN` to `https://your.domain` and redeploy. If you don't, the Control UI rejects the new origin.

## Why Deploy OpenClaw on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying OpenClaw on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.


## Similar templates

- [Chat Chat](https://railway.com/deploy/-WWW5r) — Chat Chat, your own unified chat and search to AI platform.
- [Weaviate](https://railway.com/deploy/weaviate-1) — Vector database with hybrid search and an API key-protected API
- [Möbius Personal AI OS](https://railway.com/deploy/mobius-v01-personal-ai-os) — Self-hosted AI agent that builds and runs apps for you, with memory.

Open this page in a browser: https://railway.com/deploy/openclaw-quick-start
