Install OpenClaw Gateway on exe.dev for Remote Access

Deploy OpenClaw Gateway on an exe.dev virtual machine with HTTPS proxy for remote access. Includes automated setup via Shelley and manual installation steps.

Read this when

  • You want a cheap always-on Linux host for the Gateway
  • You want remote Control UI access without running your own VPS

Goal: An OpenClaw Gateway deployed on an exe.dev virtual machine, exposed at https://<vm-name>.exe.xyz.

This setup targets exe.dev's standard exeuntu image. On other distributions, translate the package names as needed.

What you need

  • An exe.dev account
  • ssh exe.dev access to exe.dev VMs (optional, for manual configuration)

Beginner quick path

  1. Navigate to https://exe.new/openclaw
  2. Provide your auth key or token when prompted
  3. Select "Agent" beside your VM and let Shelley complete provisioning
  4. Go to https://<vm-name>.exe.xyz/ and sign in with the shared secret you set (token auth is the default; password auth is available after changing gateway.auth.mode)
  5. Accept pending device pairing requests via openclaw devices approve <requestId>

Automated install with Shelley

Shelley, the agent on exe.dev, can set up OpenClaw directly from a prompt:

Set up OpenClaw (https://docs.openclaw.ai/install) on this VM. Use the non-interactive and accept-risk flags for openclaw onboarding. Add the supplied auth or token as needed. Configure nginx to forward from the default port 18789 to the root location on the default enabled site config, making sure to enable Websocket support. Set gateway.controlUi.allowedOrigins to the exact https://<vm-name>.exe.xyz origin, and set gateway.trustedProxies to ["127.0.0.1"] because nginx connects to the Gateway over loopback and overwrites X-Forwarded-For. Pairing is done by "openclaw devices list" and "openclaw devices approve <request id>". Make sure the dashboard shows that OpenClaw's health is OK. exe.dev handles forwarding from port 8000 to port 80/443 and HTTPS for us, so the final "reachable" should be <vm-name>.exe.xyz, without port specification.

Manual installation

Create the VM

From your device:

ssh exe.dev new

Then establish the connection:

ssh <vm-name>.exe.xyz

Tip

Leave this VM stateful. OpenClaw keeps openclaw.json, per-agent auth-profiles.json, sessions, and channel/provider state in ~/.openclaw/, with the workspace under ~/.openclaw/workspace/.

Install prerequisites (on the VM)

sudo apt-get update
sudo apt-get install -y git curl jq ca-certificates openssl

Install OpenClaw

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

Configure nginx to proxy to port 8000

Modify /etc/nginx/sites-enabled/default:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 8000;
    listen [::]:8000;

    server_name _;

    location / {
        proxy_pass http://127.0.0.1:18789;
        proxy_http_version 1.1;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Standard proxy headers
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeout settings for long-lived connections
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Replace client-supplied forwarding headers rather than appending to them. OpenClaw only trusts forwarded IP metadata from proxies you explicitly list, and append-style X-Forwarded-For chains are considered a security concern.

Trust nginx and allow the public browser origin

Set the exact public origin and restrict trust to the loopback nginx hop:

openclaw config set gateway.controlUi.allowedOrigins '["https://<vm-name>.exe.xyz"]' --strict-json
openclaw config set gateway.trustedProxies '["127.0.0.1"]' --strict-json
openclaw gateway restart

For public hostnames, the browser origin check fails closed. The proxy allowlist lets OpenClaw rely on nginx's overwritten X-Forwarded-For value instead of assuming every request came from the loopback proxy. Only include proxies you control in this list.

Access OpenClaw and approve devices

Open https://<vm-name>.exe.xyz/ (refer to the Control UI output from onboarding). If authentication is requested, enter the shared secret configured on the VM.

Token auth is the default here, so run openclaw gateway auth-token --show in an interactive terminal to fetch the configured token. When no token exists, create one with openclaw doctor --generate-gateway-token and restart the Gateway. For password auth, use gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD instead.

Approve devices using openclaw devices list and openclaw devices approve <requestId>. When unsure, rely on Shelley from your browser.

Remote channel setup

For remote hosts, a single config patch call beats multiple SSH sessions to config set. Store actual tokens in the VM environment or ~/.openclaw/.env, and keep only SecretRefs in openclaw.json. The complete SecretRef contract is in Secrets management.

On the VM, ensure the service environment contains the required secrets:

cat >> ~/.openclaw/.env <<'EOF'
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
DISCORD_BOT_TOKEN=...
OPENAI_API_KEY=sk-...
EOF

From your local machine, generate a patch file and send it to the VM:

// openclaw.remote.patch.json5
{
  secrets: {
    providers: {
      default: { source: "env" },
    },
  },
  channels: {
    slack: {
      enabled: true,
      mode: "socket",
      botToken: { source: "env", provider: "default", id: "SLACK_BOT_TOKEN" },
      appToken: { source: "env", provider: "default", id: "SLACK_APP_TOKEN" },
      groupPolicy: "open",
      requireMention: false,
    },
    discord: {
      enabled: true,
      token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },
      dmPolicy: "disabled",
      dm: { enabled: false },
      groupPolicy: "allowlist",
    },
  },
  agents: {
    defaults: {
      model: { primary: "openai/gpt-5.6-sol" },
      models: {
        "openai/gpt-5.6-sol": { params: { fastMode: true } },
      },
    },
  },
}
ssh <vm-name>.exe.xyz 'openclaw config patch --stdin --dry-run' < ./openclaw.remote.patch.json5
ssh <vm-name>.exe.xyz 'openclaw config patch --stdin' < ./openclaw.remote.patch.json5
ssh <vm-name>.exe.xyz 'openclaw gateway restart && openclaw health'

Use --replace-path when a nested allowlist should match the patch value exactly, such as swapping a Discord channel allowlist:

ssh <vm-name>.exe.xyz 'openclaw config patch --stdin --replace-path "channels.discord.guilds[\"123\"].channels"' < ./discord.patch.json5

Full channel configuration details are in Discord and Slack.

Remote access

exe.dev manages authentication for remote access. By default, HTTP traffic on port 8000 forwards to https://<vm-name>.exe.xyz with email auth.

Updating

openclaw update

For channel changes and manual recovery, see Updating.

876 words · updated Aug 14, 2026