---
name: openclaw-cloudflare-secure-b5c8befedcf7
description: Securely expose an OpenClaw Gateway WebUI on a VPS via Cloudflare Zero Trust Access + Cloudflare Tunnel (cloudflared), including DNS cutover for custom hostnames and optional cleanup of Tailscale Serve.
---

# OpenClaw WebUI: Cloudflare Access + Tunnel (VPS)

Use this when you want an easy public URL (e.g. `openclaw.example.com`) that is **NOT** directly exposed, protected by **Cloudflare Access allowlist**, and delivered via **Cloudflare Tunnel** to a local service (commonly `http://127.0.0.1:18789`).

## Assumptions

- OpenClaw WebUI is reachable locally on the VPS at `http://127.0.0.1:18789` (or your chosen local port).
- You control DNS for the zone in Cloudflare (e.g. `example.com`).
- You have a Cloudflare API token available to the agent/VPS as `CLOUDFLARE_API_TOKEN`.
  - Recommended token perms (least privilege): **Zone:DNS:Edit** + **Zone:Zone:Read** for the target zone.
  - This is the key reason this setup is “agent-friendly”: the agent can securely create subdomains / manage DNS records without giving it full Cloudflare account access.
- You can access Cloudflare Zero Trust UI to create:
  - an **Access Application** for the hostname
  - an **Allow** policy for specific emails
  - a **Block** policy for Everyone
  - a **Tunnel** and its **token**

## Quick start (copy/paste)

### 0) Optional: disable Tailscale Serve

If you used Tailscale Serve earlier and want to remove it:

```bash
sudo tailscale serve reset
```

### 1) Install and start cloudflared tunnel service (token-based)

In Cloudflare Zero Trust:
- Networks → Connectors → Tunnels → Create tunnel → Cloudflared
- Copy the token from the command `cloudflared service install <TOKEN>`

On the VPS:

```bash
./scripts/install_cloudflared.sh
sudo ./scripts/tunnel_service_install.sh '<TOKEN>'
```

Verify:

```bash
sudo systemctl is-active cloudflared
sudo systemctl status cloudflared --no-pager -l | sed -n '1,80p'
```

### 2) DNS cutover: point hostname to the tunnel

This uses the bundled DNS helper (`./scripts/cf_dns.py`). It will:
- find and delete any existing A/AAAA/CNAME for that hostname
- create a proxied CNAME to `<TUNNEL_UUID>.cfargotunnel.com`

Prereq:

```bash
export CLOUDFLARE_API_TOKEN='...'
```

### 2b) (Optional) Create/update a subdomain / DNS record (agent-friendly)

Use this when you want the agent (with least-privilege DNS token) to create records programmatically:

```bash
./scripts/dns_create_record.sh --zone example.com --type A --name openclaw --content 1.2.3.4 --proxied true
./scripts/dns_create_record.sh --zone example.com --type CNAME --name openclaw --content target.example.net --proxied true
```

```bash
./scripts/dns_point_hostname_to_tunnel.sh \
  --zone example.com \
  --hostname openclaw.example.com \
  --tunnel-uuid <TUNNEL_UUID>
```

### 3) In Cloudflare Zero Trust UI: bind hostname → service

In the tunnel:
- Add Public Hostname:
  - Hostname: `openclaw.example.com`
  - Service: `http://127.0.0.1:18789`

### 4) Cloudflare Access policy

In Zero Trust:
- Access → Applications → Add → Self-hosted
  - Public hostname: `openclaw.example.com`
- Policies:
  1) Allow: include specific emails (your allowlist)
  2) Block: include Everyone

## Notes / gotchas

- If the Tunnel “route traffic” wizard errors with “record already exists”, it’s just DNS collision. Either:
  - delete the existing DNS record and let the wizard recreate it, OR
  - keep DNS as-is and set the Public Hostname mapping inside the Tunnel.
- Keep the hostname **proxied** (orange cloud). Access/Tunnel require proxy.

## Rollback

- DNS: point the hostname back to an origin A record (or remove the record).
- VPS: `sudo systemctl disable --now cloudflared`.


---
Source attribution: kbarbel640-del
Original project: https://github.com/kbarbel640-del/skills/blob/e7e336ac628c3e3bd771aff1aaa469c93778f94a/skills/jskoiz/openclaw-cloudflare-secure/SKILL.md
License: MIT
License information: https://opensource.org/license/mit
Original upstream instructions; downloaded from Dave AI.

## Upstream license notice

MIT License

Copyright (c) 2026 clawdbot

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



# Dave AI resource metadata

Creator / publisher: kbarbel640-del
Original project: https://github.com/kbarbel640-del/skills/blob/e7e336ac628c3e3bd771aff1aaa469c93778f94a/skills/jskoiz/openclaw-cloudflare-secure/SKILL.md
Attribution basis: Source repository record

Fields of work: Development & Engineering, Product Management
Roles: Backend Developer, DevOps / SRE, Technical Product Manager
Specialties: DevOps
Tools: Tailscale
Country applicability: Country not specified
Classification basis: Source catalog labels
Instruction SHA-256: 5bd182ca39d0fdab9eb1d12ecb7c078af321d23403c75a6f720e9b073e8e3126
