# OpenClaw on Linux (Ubuntu/Debian): Setup Guide

Canonical: https://clawdocx.com/docs/getting-started-linux
Author: Sam Okafor
Difficulty: BEGINNER
Published: 2026-02-24
Updated: 2026-09-19

> A guide to installing and configuring OpenClaw on Linux: VPS and dedicated hardware, prerequisites, installation, systemd setup, and firewall configuration.

## Linux as an OpenClaw Host

Linux is an excellent choice for running OpenClaw, especially on cloud VPS instances or dedicated servers. With systemd service management, low resource overhead, and rock-solid uptime, a Linux server can keep your agent running indefinitely without intervention.

> **Note**
>
> This guide focuses on Ubuntu 22.04 LTS and Ubuntu 24.04 LTS, which are the most popular choices in the OpenClaw community. The instructions also apply to Debian 12 (Bookworm) with minor adjustments. For other distributions, adapt the package manager commands accordingly.

### VPS vs Dedicated Hardware

| Factor | VPS (Cloud) | Dedicated Hardware |
|--------|-------------|-------------------|
| **Cost** | $5-20/month | One-time hardware cost |
| **Uptime** | 99.9%+ SLA | Depends on your power/internet |
| **Setup time** | 5 minutes | 30+ minutes |
| **Maintenance** | Provider handles hardware | You handle everything |
| **Privacy** | Data on provider's servers | Data stays local |
| **Performance** | Shared resources | Dedicated resources |
| **Best for** | Quick start, remote access | Privacy-focused, power users |

**Recommended VPS providers**: Hetzner (best value), DigitalOcean, Linode, Vultr. A $5-10/month instance with 1 vCPU and 1 GB RAM is sufficient for a single OpenClaw agent.

**Recommended hardware**: Any x86_64 or ARM64 machine running Ubuntu or Debian. A Raspberry Pi 5 works but is not recommended for production use due to SD card reliability.

---

## Step 1: System Prerequisites

### Update Your System

Start with a fresh, updated system:

```bash
sudo apt update && sudo apt upgrade -y
```

### Install Required Packages

Install the essential build tools and dependencies:

```bash
sudo apt install -y curl wget git build-essential ca-certificates gnupg
```

### What Node.js Version Does OpenClaw Need?

The install docs list the supported runtimes as "Node 24.16+ or 26.1+", and recommend Node 26. Use the NodeSource repository to get one:

```bash
curl -fsSL https://deb.nodesource.com/setup_26.x | sudo -E bash -
```

```bash
sudo apt install -y nodejs
```

Verify the installation:

```bash
node --version && npm --version
```

Ubuntu's own `nodejs` package is usually older than the supported range for the latest release listed as of September 19, 2026, which is why the NodeSource step comes first.

### Install pnpm (Optional)

```bash
npm install -g pnpm
```

---

## Step 2: Create a Dedicated User

Running OpenClaw as root is a security risk. Create a dedicated user account:

```bash
sudo adduser --system --group --home /home/openclaw --shell /bin/bash openclaw
```

This creates a system user with:
- Home directory at `/home/openclaw`
- A dedicated group named `openclaw`
- Bash as the default shell
- No password login (use `sudo su - openclaw` to switch)

Grant the user necessary permissions:

```bash
sudo usermod -aG sudo openclaw
```

> **Warning**
>
> Adding the `openclaw` user to the sudo group is optional and only needed if your skills require elevated permissions. For maximum security, do not add sudo access and instead grant specific permissions as needed.

Switch to the new user for the rest of the installation:

```bash
sudo su - openclaw
```

---

## Step 3: Install OpenClaw

Run the documented installer script as the `openclaw` user:

```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```

If you prefer a global package install, the docs give an npm and a pnpm path. npm 12 blocks unapproved package lifecycle scripts by default, hence the flag:

```bash
npm install -g openclaw@latest --allow-scripts=openclaw
```

```bash
pnpm add -g --allow-build=openclaw openclaw@latest
```

Then run onboarding, which is also where the managed service gets installed:

```bash
openclaw onboard --install-daemon
```

### What Does Onboarding Actually Ask?

`openclaw onboard` is "Guided setup that establishes inference first: it detects existing AI access, waits for your provider choice, verifies that connection, persists only the working route, and then starts OpenClaw to configure the rest." The documented phases are:

### Step 1: Security notice and agent naming

The wizard opens with a security notice, then names your first agent. Use --agent-name <name> to set it non-interactively when no roster exists.

### Step 2: Discovery access-level choice

Choose how much discovery access the agent gets.

### Step 3: AI provider detection and selection

OpenClaw detects existing AI access and waits for your provider choice. See the API Key Setup guide for details on obtaining keys. The docs do not name a default or recommended model, so choose on your own cost and capability trade-off.

### Step 4: Live connection verification

The wizard verifies the connection and persists only the working route.

### Step 5: Memory import offer

If there is anything to import, the wizard offers to bring it across.

### Step 6: Standard setup application

Config, workspace and bootstrap files are written. Pass --skip-health if you only want those writes in automation.

### Step 7: Plugin and skill recommendations

The wizard suggests plugins and skills for your setup.

### Step 8: Control UI dashboard handoff

The wizard hands off to the Control UI dashboard, or falls back to the terminal.

> **Note**
>
> `--install-daemon` "starts the managed gateway install path first". Without a daemon flag, a local gateway must already be running (for example `openclaw gateway run`). `openclaw onboard --classic` opens the full step-by-step wizard, and `--flow manual` gives full prompts for port, bind and secret storage.

Messaging channels are configured after onboarding; see the [Messaging Channels Guide](/docs/messaging-channels).

### Verify Installation

After onboarding completes, check that OpenClaw is working:

```bash
openclaw health
```

`openclaw health` fetches "a health snapshot from the running Gateway over WebSocket RPC (no direct channel sockets from the CLI)". It takes `--json`, `--timeout <ms>` (default `10000`) and `--verbose`, which "forces a live probe and expands output across all configured accounts and agents". There is no `--quiet` flag, so parse `--json` rather than grepping prose:

```bash
openclaw health --json
```

---

## Step 4: Set Up systemd Service

The systemd service ensures OpenClaw starts on boot and restarts automatically if it crashes. This is the Linux equivalent of the macOS LaunchAgent.

### Automatic Installation

The easiest approach is to use the built-in service installer. There is no bare `openclaw --install-daemon` flag. `openclaw gateway install` "installs and starts the service"; the `--install-daemon` flag belongs to onboarding, where it "starts the managed gateway install path first".

```bash
openclaw gateway install
```

### What Is the Service Actually Called?

`openclaw-gateway.service`, not `openclaw.service`. The docs name the unit `openclaw-gateway.service`, or `openclaw-gateway-<profile>.service` for a named profile. Get it running and enabled:

```bash
systemctl --user enable --now openclaw-gateway.service
```

Inspect the unit OpenClaw wrote:

```bash
systemctl --user cat openclaw-gateway.service
```

### Manual Installation

If you prefer to write the unit yourself, the Gateway runbook's example uses these directives:

```ini
# ~/.config/systemd/user/openclaw-gateway.service
[Unit]
Description=OpenClaw Gateway
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/openclaw gateway --port 18789
Restart=always
RestartSec=10
TimeoutStopSec=330
RestartPreventExitStatus=78

[Install]
WantedBy=default.target
```

Two of those directives are load-bearing and easy to get wrong:

- `TimeoutStopSec=330` covers the Gateway's maximum 315-second stop drain. systemd's own limit is 330 seconds; launchd's is 20.
- `RestartPreventExitStatus=78` stops a restart loop on config errors. Exit code 78 signals invalid configuration.

Note that there is no `--foreground` flag. `openclaw gateway` (explicitly, `openclaw gateway run`) runs in the foreground already, which is what a `Type=simple` unit wants. Adjust the `ExecStart=` path if your `openclaw` binary lives elsewhere. For a system-wide unit, install it under `/etc/systemd/system/openclaw-gateway.service` and add a `User=` line to `[Service]`.

Save the file and enable it:

```bash
mkdir -p ~/.config/systemd/user
```

```bash
systemctl --user daemon-reload
```

```bash
systemctl --user enable --now openclaw-gateway.service
```

For a system unit instead:

```bash
sudo systemctl daemon-reload && sudo systemctl enable --now openclaw-gateway.service
```

### Enable Lingering

By default, systemd user services stop when the user logs out. Enable lingering so the service runs even when no session is active:

```bash
sudo loginctl enable-linger $(whoami)
```

This is critical for headless servers and VPS instances.

### Verify the Service

```bash
systemctl --user status openclaw-gateway.service
```

You should see `active (running)` in the output. `openclaw gateway status --deep` adds system-level service scanning, and `openclaw doctor --fix` audits and repairs service config drift.

View logs:

```bash
journalctl --user -u openclaw-gateway -f
```

The journal only carries what the unit writes to stdout and stderr. OpenClaw's own log file defaults to `/tmp/openclaw/openclaw-YYYY-MM-DD.log` (`/tmp/openclaw/openclaw-<profile>-YYYY-MM-DD.log` for named profiles), and you can redirect it in `~/.openclaw/openclaw.json`:

```json
{
  "logging": {
    "file": "/path/to/openclaw.log"
  }
}
```

Separately, Gateway lifecycle mutations "append best-effort key-value audit records to `<state-dir>/logs/gateway-restart.log`".

---

## Step 5: Configure the Firewall

If your server is accessible from the internet (especially on a VPS), you must configure the firewall to protect your OpenClaw instance.

### Install and Enable UFW

```bash
sudo apt install -y ufw
```

Set default policies:

```bash
sudo ufw default deny incoming
```
```bash
sudo ufw default allow outgoing
```

### Allow SSH

Before enabling the firewall, make sure SSH is allowed or you will lock yourself out:

```bash
sudo ufw allow ssh
```

### Allow the Gateway Port (Optional)

The Gateway multiplexes "WebSocket + HTTP (Control UI, hooks, etc.)" onto a single port. The documented default is **18789**, with precedence `--port` > `OPENCLAW_GATEWAY_PORT` > `gateway.port` > `18789`. If you genuinely need it reachable off-host:

```bash
sudo ufw allow 18789/tcp
```

> **Danger**
>
> The Gateway does have built-in auth, and it is required: "Gateway auth is required by default - with no valid auth path configured, the Gateway refuses WebSocket connections (fail-closed)." The `gateway.auth.mode` values are `token` ("shared bearer token (recommended for most setups)"), `password` and `trusted-proxy`. That is a reason to configure auth properly, not a reason to open the port: the docs say the `lan`, `tailnet` and `custom` bind modes "expand the attack surface. Only use with gateway auth ... and a real firewall", advise preferring Tailscale Serve over LAN binds, and say to "never expose the Gateway unauthenticated on `0.0.0.0`". Non-loopback Control UI deployments also require `gateway.controlUi.allowedOrigins`; allowing all origins is "an explicit allow-all policy, not a hardened default".

In most cases, leave `gateway.bind` on its `loopback` default and reach the box over Tailscale or an SSH tunnel instead of punching a hole in the firewall.

### Enable the Firewall

```bash
sudo ufw enable
```

Check the status:

```bash
sudo ufw status verbose
```

---

## Step 6: Remote Access

### Option A: SSH (Simplest)

If your server has a public IP or you are on the same network:

```bash
ssh openclaw@your-server-ip
```

For VPS instances, use the IP address provided by your hosting provider.

### Option B: Tailscale (Recommended for Home Servers)

Tailscale creates a secure mesh VPN, allowing you to access your server from anywhere without exposing ports to the internet.

Install Tailscale:

```bash
curl -fsSL https://tailscale.com/install.sh | sh
```

```bash
sudo tailscale up
```

Follow the authentication link printed in the terminal. Once connected, your server gets a stable Tailscale IP (e.g., `100.x.y.z`) that you can use from any device on your Tailscale network.

### Option C: Cloudflare Tunnel (Advanced)

For exposing the dashboard securely without opening ports:

```bash
curl -fsSL https://pkg.cloudflare.com/cloudflared-stable-linux-amd64.deb -o cloudflared.deb && sudo dpkg -i cloudflared.deb
```

Configure a tunnel pointing to `localhost:18789`, the default Gateway port. This gives you a custom domain with Cloudflare's authentication layer in front of the Gateway's own. If the Control UI will be reached on a non-loopback origin, set `gateway.controlUi.allowedOrigins` and consider `gateway.publicOrigin`, documented as an "optional externally reachable HTTPS origin".

---

## Step 7: Verify Everything Works

Run the comprehensive diagnostic:

```bash
openclaw doctor
```

Send a test message through your configured messaging channel and confirm the agent responds.

### Monitoring the Agent

Set up basic monitoring to ensure your agent stays healthy:

**Check logs for errors:**

```bash
journalctl --user -u openclaw-gateway --since '1 hour ago' --priority err
```

**Monitor resource usage:**

```bash
systemctl --user status openclaw-gateway | grep Memory
```

**Set up a simple health check cron:**

`openclaw health` has no `--quiet` flag, so branch on `--json` output instead of prose:

```bash
# Add to crontab: checks health every 5 minutes, restarts if the snapshot fails
*/5 * * * * openclaw health --json --timeout 5000 >/dev/null 2>&1 || systemctl --user restart openclaw-gateway.service
```

OpenClaw also has its own scheduler, so a host cron entry is only for the case where the Gateway itself is down. Anything the agent should do on a schedule belongs in an automation: `openclaw automations list --all` shows every job including disabled ones, and the command "registers as `openclaw cron` with `openclaw automations` as an alias".

---

## Where Does OpenClaw Put Its Files?

"Everything lives under `$OPENCLAW_STATE_DIR` (default: `~/.openclaw`)", which for the dedicated user on this guide's setup is `/home/openclaw/.openclaw`. The docs describe it as holding "config, channel/provider state, auth profiles, sessions, logs". These are the paths they actually name:

```text
/home/openclaw/.openclaw/
  openclaw.json                              # Main configuration file
  .env                                       # Global environment fallback
  secrets.json                               # Secret values referenced from config
  credentials/oauth.json                     # OAuth credentials
  state/openclaw.sqlite                      # Shared state database
  skills/                                    # Shared managed skills
  agents/<agentId>/agent/auth.json           # Per-agent auth profile
  agents/<agentId>/agent/openclaw-agent.sqlite
  agents/<agentId>/sessions/                 # Per-agent session records
  workspace/                                 # Agent workspace (agents.defaults.workspace)
```

The agent workspace defaults to `OPENCLAW_WORKSPACE_DIR` when set, otherwise `<state-dir>/workspace`. Bootstrap writes these files into it:

```text
/home/openclaw/.openclaw/workspace/
  AGENTS.md              # Operating rules, including a `## Tools` section
  SOUL.md                # Agent personality (optional bootstrap file)
  IDENTITY.md            # Name, role and avatar (optional bootstrap file)
  USER.md                # Context about you (optional bootstrap file)
  BOOTSTRAP.md           # First-run only
  MEMORY.md              # Curated long-term memory (optional)
  BOOT.md                # Optional
  memory/YYYY-MM-DD.md   # Daily memory files
  skills/                # Optional workspace-local skills
```

Worth knowing:

- There is no `data/` or `backups/` directory in the documented layout, and `skills/` is not split into built-in, community and custom folders.
- `TOOLS.md` and `HEARTBEAT.md` are retired. Tool and environment notes "now live in the `## Tools` section of `AGENTS.md`", and `HEARTBEAT.md` "is accepted but a no-op since heartbeat context moved to cron monitor scratch".
- `.env` here is a global fallback. OpenClaw reads env vars from the parent process (shell, launchd/systemd, CI) and additionally loads a `.env` from the current working directory plus the global one at `~/.openclaw/.env`. Neither normally overrides an existing variable. On fresh Ubuntu installs using the default state dir, OpenClaw also reads `~/.config/openclaw/gateway.env` as a compatibility fallback after the global `.env`; if the two disagree it keeps `~/.openclaw/.env` and prints a warning.
- Logs are not under the state directory by default. See the logging note in the service section above.

There is also no `openclaw config edit`. To find the file your editor should open, use `config file`, which "Prints the active config file path, resolved from `OPENCLAW_CONFIG_PATH` or the default location", and edit that file directly:

```bash
openclaw config file
```

Or directly:

```bash
nano ~/.openclaw/openclaw.json
```

---

## Managing the Service

Common systemd commands for managing your OpenClaw instance:

| Command | Description |
|---------|-------------|
| `systemctl --user start openclaw-gateway` | Start the service |
| `systemctl --user stop openclaw-gateway` | Stop the service |
| `systemctl --user restart openclaw-gateway` | Restart the service |
| `systemctl --user status openclaw-gateway` | Check service status |
| `journalctl --user -u openclaw-gateway -f` | Stream the unit's stdout/stderr |
| `journalctl --user -u openclaw-gateway --since today` | View today's journal entries |
| `systemctl --user enable openclaw-gateway` | Enable start on boot |
| `systemctl --user disable openclaw-gateway` | Disable start on boot |

You can also use the OpenClaw CLI commands, which wrap these systemd operations:

```bash
openclaw gateway start
```
```bash
openclaw gateway stop
```
```bash
openclaw gateway restart
```
```bash
openclaw logs --follow
```

---

## Updating OpenClaw on Linux

To update to the latest version:

```bash
openclaw update
```

`openclaw update` is documented as "Update OpenClaw and switch between stable/extended-stable/beta/dev channels." What the docs actually promise:

- It restarts the Gateway service after a successful update unless you pass `--no-restart`.
- Package-manager updates that do restart "verify the restarted service reports the expected version before the command succeeds."
- `--channel` sets and persists the update channel after core update success.
- `--dry-run` previews the planned actions "without writing config, installing, syncing plugins, or restarting."

The docs make no claim that `update` backs up your config, so take your own backup of `openclaw.json` before a risky upgrade.

```bash
openclaw update --dry-run
```

If you installed globally with npm and prefer to drive the package manager yourself:

```bash
npm install -g openclaw@latest --allow-scripts=openclaw
```
```bash
systemctl --user restart openclaw-gateway.service
```

---

## Troubleshooting Linux-Specific Issues

### Service fails to start

Check the journal for error details:

```bash
journalctl --user -u openclaw-gateway --no-pager -n 50
```

Common causes:
- Node.js not found in PATH, or below the supported "Node 24.16+ or 26.1+" (fix: add the full path to `ExecStart` in the service file, or upgrade Node)
- Port 18789 already in use (fix: set `gateway.port` in `openclaw.json`, pass `--port`, or stop the conflicting service)
- Invalid configuration, which exits with code 78 (fix: run `openclaw config validate`, which "validates the current config against the active schema without starting the gateway")
- Missing API keys (fix: run `openclaw config file` to locate `openclaw.json`, then add your keys)

### Permission denied errors

If OpenClaw cannot write to its data directory:

```bash
sudo chown -R openclaw:openclaw /home/openclaw/.openclaw
```

### DNS resolution failures

Some minimal VPS images do not have proper DNS configuration:

```bash
echo 'nameserver 1.1.1.1' | sudo tee /etc/resolv.conf
```

### High memory usage

OpenClaw publishes no memory or CPU budget for the Gateway, so there is no documented "normal" to compare against. Measure first with `systemctl --user status openclaw-gateway`, then run `openclaw doctor` before reaching for a cap. systemd's `MemoryMax` and `CPUQuota` will happily throttle or OOM-kill a healthy Gateway mid-turn, so set them only once you know what your own workload needs, and keep `TimeoutStopSec=330` so a restart still gets its full stop drain.

---

## Next Steps

- **[Security Hardening](/docs/security-hardening)**: essential for internet-facing servers
- **[API Key Setup](/docs/api-key-setup)**: configure multiple LLM providers
- **[Cost Optimization](/docs/cost-optimization)**: control API spending
- **[Heartbeat & Cron Configuration](/docs/heartbeat-config)**: schedule recurring tasks
- **[Troubleshooting](/docs/troubleshooting)**: solutions for common issues

## Sources

- [OpenClaw: Where things live on disk](https://docs.openclaw.ai/help/faq/where-things-live-on-disk)
- [OpenClaw: Agent workspace](https://docs.openclaw.ai/concepts/agent-workspace)
- [OpenClaw: Configuration: agent workspace and bootstrap](https://docs.openclaw.ai/gateway/config-agents/workspace-and-bootstrap)
- [OpenClaw: Config](https://docs.openclaw.ai/cli/config)
- [OpenClaw: Gateway](https://docs.openclaw.ai/cli/gateway)
- [OpenClaw: Manage the Gateway service](https://docs.openclaw.ai/cli/gateway/service)
- [OpenClaw: Onboard](https://docs.openclaw.ai/cli/onboard)
- [OpenClaw: Logs](https://docs.openclaw.ai/cli/logs)
- [OpenClaw: Install](https://docs.openclaw.ai/install)
- [OpenClaw: Env vars and .env loading](https://docs.openclaw.ai/help/faq/env-vars)
- [OpenClaw: Configuration: gateway](https://docs.openclaw.ai/gateway/config-gateway)
- [OpenClaw: Gateway ports, already running, and remote mode](https://docs.openclaw.ai/help/faq/gateway-ports-and-remote-mode)
- [OpenClaw: Network exposure](https://docs.openclaw.ai/gateway/security/network-exposure)
- [OpenClaw: Gateway runbook](https://docs.openclaw.ai/gateway)
- [OpenClaw: Run the Gateway](https://docs.openclaw.ai/cli/gateway/running)
- [OpenClaw: Logging](https://docs.openclaw.ai/logging)
- [OpenClaw: Health](https://docs.openclaw.ai/cli/health)
- [OpenClaw: Dashboard](https://docs.openclaw.ai/cli/dashboard)
- [OpenClaw: Update](https://docs.openclaw.ai/cli/update)