๐ŸŽ Get the FREE AI Skills Starter Guide โ€” Subscribe โ†’
BytesAgainBytesAgain
๐Ÿฆ€ ClawHub

openclaw-twoway deployment

by @marshong-86

Deploy OpenClaw with a cloud gateway using Tailscale and SSH tunnel for secure local control, including auto environment check and firewall setup.

Versionv1.0.0
Downloads922
TERMINAL
clawhub install openclaw-two-way-deployment

๐Ÿ“– About This Skill

OpenClaw ไธ‰็ง้ƒจ็ฝฒๆ–นๆกˆๅฎŒๆ•ดๆŠ€่ƒฝ

ๆŠ€่ƒฝไฝฟ็”จ่ฏดๆ˜Ž

่ฟ่กŒ /openclaw-deploy ้€‰ๆ‹ฉ้ƒจ็ฝฒๆ–นๆกˆ๏ผŒ่‡ชๅŠจๅฎŒๆˆ็Žฏๅขƒๆฃ€ๆต‹ใ€้˜ฒ็ซๅข™้…็ฝฎใ€ๆœๅŠก้ƒจ็ฝฒใ€‚


ๆ–นๆกˆไธ€๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + SSH ้šง้“ๆŽงๅˆถๆœฌๅœฐ

ๅฎŒๆ•ดๆžถๆž„ๆต็จ‹ๅ›พ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                              ไบ‘็ซฏๆœๅŠกๅ™จ (Linux)                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚                     OpenClaw Gateway                                  โ”‚   โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                 โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ ้’‰้’‰/้ฃžไนฆ     โ”‚  โ”‚ ๆ ธๅฟƒๅค„็†     โ”‚  โ”‚ AI ๆจกๅž‹ API    โ”‚                 โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                 โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  SSH Server (22)           Tailscale (:18789)         โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚ Tailscale VPN (ๅŠ ๅฏ†)                       โ”‚
              โ”‚ SSH ้šง้“๏ผšlocalhost:2222 โ†’ :18789
              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                              ๆœฌๅœฐ็”ต่„‘ (Windows)                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  SSH Client (ๅŽๅฐ)           OpenClaw CLI / VSCode                   โ”‚   โ”‚
โ”‚  โ”‚                              ่ฟžๆŽฅ๏ผšws://localhost:2222                โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ–ฒ
                                    โ”‚
                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                          โ–ผ                   โ–ผ
                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                   โ”‚ ้’‰้’‰ APP โ”‚        โ”‚ ๆต่งˆๅ™จ   โ”‚
                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๆ•ฐๆฎๆตๅ‘๏ผš 1. ้’‰้’‰/้ฃžไนฆ โ†’ Webhook โ†’ ไบ‘็ซฏ็ฝ‘ๅ…ณ (18789) 2. ไบ‘็ซฏ็ฝ‘ๅ…ณ โ†’ AI ๆจกๅž‹ API โ†’ ่Žทๅ–ๅ›žๅค 3. ไบ‘็ซฏ็ฝ‘ๅ…ณ โ†’ Webhook โ†’ ่ฟ”ๅ›ž้’‰้’‰/้ฃžไนฆ 4. ๆœฌๅœฐ้€š่ฟ‡ SSH ้šง้“่ฎฟ้—ฎไบ‘็ซฏ็ฝ‘ๅ…ณ่ฟ›่กŒ้…็ฝฎ/็›‘ๆŽง


้ƒจ็ฝฒๅ‰ๆฃ€ๆŸฅๆธ…ๅ•

| ๆฃ€ๆŸฅ้กน | ๆœฌๅœฐ | ไบ‘็ซฏ | ้ชŒ่ฏๅ‘ฝไปค | |--------|------|------|----------| | Tailscale ่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | tailscale status | | Tailscale ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | tailscale ip | | Node.js (v18+) | โœ… ๅทฒๅฎ‰่ฃ… | โœ… ๅทฒๅฎ‰่ฃ… | node -v | | SSH ๅฎขๆˆท็ซฏ | โœ… ๅทฒ้…็ฝฎ | โŒ | ssh -V | | SSH ๆœๅŠก็ซฏ | โŒ | โœ… ๅทฒ่ฟ่กŒ | systemctl status sshd | | ้˜ฒ็ซๅข™ 18789 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ufw status / firewall-cmd --list-all | | ้˜ฒ็ซๅข™ 22 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ufw status | | ไบ‘ๅฎ‰ๅ…จ็ป„ 18789 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ไบ‘ๆŽงๅˆถๅฐๆฃ€ๆŸฅ | | ไบ‘ๅฎ‰ๅ…จ็ป„ 22 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ไบ‘ๆŽงๅˆถๅฐๆฃ€ๆŸฅ |

ไบ‘็ซฏๅฎŒๆ•ด้ƒจ็ฝฒ่„šๆœฌ๏ผˆๅซ้˜ฒ็ซๅข™ + ๅฎ‰ๅ…จ็ป„ๆฃ€ๆต‹๏ผ‰

bash #!/bin/bash

plan1-cloud-gateway.sh - ๆ–นๆกˆไธ€๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ

set -e

echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" echo "โ•‘ ๆ–นๆกˆไธ€๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + SSH ้šง้“ โ•‘" echo "โ•‘ ไบ‘็ซฏ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

============== 1. ็ณป็ปŸ็Žฏๅขƒๆฃ€ๆต‹ ==============

echo -e "\n[1/8] ็ณป็ปŸ็Žฏๅขƒๆฃ€ๆต‹..."

if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID echo " ็ณป็ปŸ๏ผš$OS ($PRETTY_NAME)" else echo " โœ— ๆ— ๆณ•่ฏ†ๅˆซ็ณป็ปŸ" exit 1 fi

if [ "$EUID" -ne 0 ]; then echo " โœ— ่ฏทไฝฟ็”จ root ๆƒ้™่ฟ่กŒ" exit 1 fi echo " โœ“ ๆƒ้™ๆฃ€ๆŸฅ้€š่ฟ‡ (root)"

ๆฃ€ๆต‹ SSH ๆœๅŠก

if systemctl is-active --quiet sshd || systemctl is-active --quiet ssh; then echo " โœ“ SSH ๆœๅŠก๏ผš่ฟ่กŒไธญ" else echo " โš  SSH ๆœๅŠกๆœช่ฟ่กŒ๏ผŒๆญฃๅœจๅฏๅŠจ..." systemctl enable --now sshd 2>/dev/null || systemctl enable --now ssh 2>/dev/null || true fi

============== 2. Tailscale ้…็ฝฎ ==============

echo -e "\n[2/8] ้…็ฝฎ Tailscale..."

if ! command -v tailscale &> /dev/null; then echo " ๅฎ‰่ฃ… Tailscale..." if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then curl -fsSL https://tailscale.com/install.sh | sh elif [ "$OS" = "centos" ] || [ "$OS" = "rhel" ] || [ "$OS" = "rocky" ]; then yum install -y yum-utils yum-config-manager --add-repo https://pkgs.tailscale.com/stable/centos/9/tailscale.repo yum install -y tailscale else echo " โœ— ไธๆ”ฏๆŒ็š„็ณป็ปŸ๏ผŒ่ฏทๆ‰‹ๅŠจๅฎ‰่ฃ…๏ผšhttps://tailscale.com/download" exit 1 fi fi

systemctl enable --now tailscaled 2>/dev/null || tailscaled & sleep 3

if tailscale status 2>&1 | grep -q "connected"; then TAILSCALE_IP=$(tailscale ip | head -1) echo " โœ“ Tailscale: ๅทฒ่ฟžๆŽฅ ($TAILSCALE_IP)" else echo " โš  Tailscale ๆœช่ฟžๆŽฅ" echo " ่ฏท่ฟ่กŒไปฅไธ‹ๅ‘ฝไปคๅฎŒๆˆ่ฎค่ฏ๏ผš" echo " tailscale up" AUTH_URL=$(tailscale up 2>&1 | grep -o 'https://login.tailscale.com/a/[a-zA-Z0-9]*' || echo "") if [ -n "$AUTH_URL" ]; then echo " ่ฎค่ฏ้“พๆŽฅ๏ผš$AUTH_URL" fi read -p " ๅฎŒๆˆ่ฎค่ฏๅŽๆŒ‰ๅ›ž่ฝฆ็ปง็ปญ..." TAILSCALE_IP=$(tailscale ip | head -1) echo " โœ“ Tailscale: ๅทฒ่ฟžๆŽฅ ($TAILSCALE_IP)" fi

============== 3. ้˜ฒ็ซๅข™้…็ฝฎ ==============

echo -e "\n[3/8] ้…็ฝฎ้˜ฒ็ซๅข™..."

FIREWALL_CONFIGURED=false

UFW (Ubuntu/Debian)

if command -v ufw &> /dev/null; then echo " ๆฃ€ๆต‹ๅˆฐ UFW ้˜ฒ็ซๅข™..." if ufw status | grep -q "Status: active"; then echo " UFW ๅทฒๅฏ็”จ๏ผŒ้…็ฝฎ่ง„ๅˆ™..." ufw allow 18789/tcp comment "OpenClaw Gateway" 2>/dev/null || ufw allow 18789/tcp ufw allow 22/tcp comment "SSH" 2>/dev/null || ufw allow 22/tcp ufw reload 2>/dev/null || true echo " โœ“ UFW: 18789/tcp, 22/tcp ๅทฒๆ”พ่กŒ" FIREWALL_CONFIGURED=true else echo " UFW ๆœชๅฏ็”จ" fi fi

Firewalld (CentOS/RHEL)

if [ "$FIREWALL_CONFIGURED" = false ] && command -v firewall-cmd &> /dev/null; then echo " ๆฃ€ๆต‹ๅˆฐ Firewalld..." if systemctl is-active --quiet firewalld; then echo " Firewalld ่ฟ่กŒไธญ๏ผŒ้…็ฝฎ่ง„ๅˆ™..." firewall-cmd --permanent --add-port=18789/tcp 2>/dev/null || true firewall-cmd --permanent --add-service=ssh 2>/dev/null || true firewall-cmd --reload 2>/dev/null || true echo " โœ“ Firewalld: 18789/tcp, ssh ๅทฒๆ”พ่กŒ" FIREWALL_CONFIGURED=true else echo " Firewalld ๆœช่ฟ่กŒ" fi fi

iptables (้€š็”จ)

if [ "$FIREWALL_CONFIGURED" = false ] && command -v iptables &> /dev/null; then echo " ๆฃ€ๆต‹ๅˆฐ iptables..." if ! iptables -L INPUT -n 2>/dev/null | grep -q "dpt:18789"; then iptables -I INPUT -p tcp --dport 18789 -j ACCEPT 2>/dev/null || true iptables -I INPUT -p tcp --dport 22 -j ACCEPT 2>/dev/null || true echo " โœ“ iptables: 18789/tcp, 22/tcp ๅทฒๆทปๅŠ " FIREWALL_CONFIGURED=true else echo " ็ซฏๅฃ่ง„ๅˆ™ๅทฒๅญ˜ๅœจ" fi fi

if [ "$FIREWALL_CONFIGURED" = false ]; then echo " โ„น ๆœชๆฃ€ๆต‹ๅˆฐ้˜ฒ็ซๅข™ๅทฅๅ…ท" fi

echo " โš  ้‡่ฆ๏ผšๅฆ‚ไฝฟ็”จไบ‘ๆœๅŠกๅ™จ (้˜ฟ้‡Œไบ‘/่…พ่ฎฏไบ‘/AWS ็ญ‰)๏ผŒ่ฏท็กฎไฟไบ‘ๆŽงๅˆถๅฐๅฎ‰ๅ…จ็ป„ๅทฒๆ”พ่กŒ๏ผš" echo " - 18789/tcp (Tailscale IP: $TAILSCALE_IP)" echo " - 22/tcp (SSH)"

============== 4. Node.js ้…็ฝฎ ==============

echo -e "\n[4/8] ้…็ฝฎ Node.js ็Žฏๅขƒ..."

if command -v node &> /dev/null; then NODE_VER=$(node -v) echo " โœ“ Node.js ๅทฒๅฎ‰่ฃ…๏ผš$NODE_VER" else echo " ๅฎ‰่ฃ… Node.js 22..." if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt-get install -y nodejs elif [ "$OS" = "centos" ] || [ "$OS" = "rhel" ] || [ "$OS" = "rocky" ]; then curl -fsSL https://rpm.nodesource.com/setup_22.x | bash - yum install -y nodejs else echo " โœ— ไธๆ”ฏๆŒ็š„็ณป็ปŸ๏ผŒ่ฏทๆ‰‹ๅŠจๅฎ‰่ฃ… Node.js" exit 1 fi echo " โœ“ Node.js ๅฎ‰่ฃ…ๅฎŒๆˆ๏ผš$(node -v)" fi

npm config set registry https://registry.npmmirror.com 2>/dev/null || true

============== 5. OpenClaw ๅฎ‰่ฃ… ==============

echo -e "\n[5/8] ๅฎ‰่ฃ… OpenClaw..."

if command -v openclaw &> /dev/null; then echo " โœ“ OpenClaw ๅทฒๅฎ‰่ฃ…" openclaw --version else echo " ๅฎ‰่ฃ… OpenClaw..." npm install -g openclaw echo " โœ“ OpenClaw ๅฎ‰่ฃ…ๅฎŒๆˆ" fi

============== 6. ็ฝ‘ๅ…ณ้…็ฝฎ ==============

echo -e "\n[6/8] ้…็ฝฎ OpenClaw ็ฝ‘ๅ…ณ..."

mkdir -p ~/.openclaw

cat > ~/.openclaw/openclaw.json << 'EOF' { "gateway": { "port": 18789, "mode": "local", "bind": "lan" } } EOF

echo " โœ“ ้…็ฝฎๆ–‡ไปถ๏ผš~/.openclaw/openclaw.json"

============== 7. systemd ๆœๅŠก้…็ฝฎ ==============

echo -e "\n[7/8] ๅˆ›ๅปบ systemd ๆœๅŠก..."

cat > /etc/systemd/system/openclaw-gateway.service << 'EOF' [Unit] Description=OpenClaw Gateway Service After=network.target tailscaled.service Wants=tailscaled.service

[Service] Type=simple User=root WorkingDirectory=/root/.openclaw ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789 --bind lan Restart=always RestartSec=5 StartLimitBurst=3 StartLimitIntervalSec=300

Environment=NODE_ENV=production

่ต„ๆบ้™ๅˆถ

LimitNOFILE=65535 Nice=-5 OOMScoreAdjust=-500

[Install] WantedBy=multi-user.target EOF

echo " โœ“ systemd ๆœๅŠก้…็ฝฎๅฎŒๆˆ"

============== 8. ๅฏๅŠจๆœๅŠก ==============

echo -e "\n[8/8] ๅฏๅŠจๆœๅŠก..."

systemctl daemon-reload systemctl enable openclaw-gateway systemctl start openclaw-gateway

echo " ็ญ‰ๅพ…ๆœๅŠกๅฏๅŠจ..." sleep 5

============== ้ชŒ่ฏ ==============

echo -e "\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" if systemctl is-active --quiet openclaw-gateway; then echo "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

echo -e "\nใ€ๆœๅŠกไฟกๆฏใ€‘" echo " ๆœๅŠก็Šถๆ€๏ผš$(systemctl is-active openclaw-gateway)" echo " ๅผ€ๆœบ่‡ชๅฏ๏ผš$(systemctl is-enabled openclaw-gateway)"

echo -e "\nใ€็ฝ‘็ปœไฟกๆฏใ€‘" echo " Tailscale IP: $TAILSCALE_IP" echo " ็ฝ‘ๅ…ณๅœฐๅ€๏ผšws://${TAILSCALE_IP}:18789" echo " ๆŽงๅˆถ้ขๆฟ๏ผšhttp://${TAILSCALE_IP}:18789/"

echo -e "\nใ€็ซฏๅฃ็›‘ๅฌใ€‘" ss -tlnp | grep 18789 || netstat -tlnp | grep 18789 || true

echo -e "\nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" echo " 1. ๅœจๆœฌๅœฐ็”ต่„‘่ฟ่กŒ SSH ้šง้“่„šๆœฌ (start-tunnel.ps1)" echo " 2. ๆˆ–ๅœจๆœฌๅœฐ้…็ฝฎ่ฟœ็จ‹็ฝ‘ๅ…ณ๏ผšopenclaw gateway remote set ws://${TAILSCALE_IP}:18789" echo " 3. ๆŸฅ็œ‹ๆ—ฅๅฟ—๏ผšjournalctl -u openclaw-gateway -f"

echo -e "\nใ€ๆœฌๅœฐ SSH ้šง้“่„šๆœฌใ€‘" echo " ๅœจๆœฌๅœฐ PowerShell ่ฟ่กŒ๏ผš" echo " ssh -N -f -L 2222:${TAILSCALE_IP}:18789 root@${TAILSCALE_IP}" else echo "โ•‘ โœ— ้ƒจ็ฝฒๅคฑ่ดฅ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" echo -e "\nใ€้”™่ฏฏๆ—ฅๅฟ—ใ€‘" journalctl -u openclaw-gateway --no-pager -n 20 exit 1 fi


ๆœฌๅœฐ SSH ้šง้“่„šๆœฌ๏ผˆๆŒไน…่ฟ่กŒ + ๅผ€ๆœบ่‡ชๅฏ๏ผ‰

powershell

plan1-local-tunnel.ps1 - ๆ–นๆกˆไธ€๏ผšๆœฌๅœฐ SSH ้šง้“ๆŒไน…้ƒจ็ฝฒ

param( [string]$CloudIP = "" )

$ErrorActionPreference = "Stop" $TaskName = "OpenClaw-SSH-Tunnel" $LocalPort = 2222 $RemotePort = 18789 $ScriptDir = "$env:USERPROFILE\.openclaw"

Write-Host "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ ๆ–นๆกˆไธ€๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + SSH ้šง้“ โ•‘" -ForegroundColor Cyan Write-Host "โ•‘ ๆœฌๅœฐ SSH ้šง้“ๆŒไน…้ƒจ็ฝฒ โ•‘" Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

1. ๆฃ€ๆŸฅ Tailscale

Write-Host "n[1/6] ๆฃ€ๆŸฅ Tailscale..." -ForegroundColor Yellow try { $tsStatus = tailscale status 2>&1 if ($LASTEXITCODE -eq 0) { $tsIP = (tailscale ip | Select-Object -First 1).Trim() Write-Host " โœ“ Tailscale: ๅทฒ่ฟžๆŽฅ ($tsIP)" -ForegroundColor Green } else { Write-Host " Tailscale ๆœช่ฟ่กŒ๏ผŒๆญฃๅœจๅฏๅŠจ..." -ForegroundColor Yellow tailscale up Start-Sleep -Seconds 5 } } catch { Write-Host " โœ— Tailscale ๆœชๅฎ‰่ฃ…" -ForegroundColor Red Write-Host " ไธ‹่ฝฝ๏ผšhttps://tailscale.com/download" -ForegroundColor Yellow exit 1 }

2. ่Žทๅ–ไบ‘็ซฏ IP

Write-Host "
n[2/6] ้…็ฝฎไบ‘็ซฏ็ฝ‘ๅ…ณ..." -ForegroundColor Yellow if ($CloudIP -eq "") { Write-Host " ่ฏท่พ“ๅ…ฅไบ‘็ซฏ็ฝ‘ๅ…ณ Tailscale IP:" -ForegroundColor Yellow $CloudIP = Read-Host " Cloud IP" if ($CloudIP -eq "") { Write-Host " โœ— ๆœช่พ“ๅ…ฅ IP ๅœฐๅ€" -ForegroundColor Red exit 1 } } Write-Host " ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผš$CloudIP:$RemotePort" -ForegroundColor Green

3. ๆต‹่ฏ•่ฟžๆŽฅ

Write-Host "n[3/6] ๆต‹่ฏ•ไบ‘็ซฏ่ฟžๆŽฅ..." -ForegroundColor Yellow $testResult = Test-NetConnection -ComputerName $CloudIP -Port $RemotePort -WarningAction SilentlyContinue -InformationLevel Quiet if ($testResult) { Write-Host " โœ“ ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผšๅฏ่พพ" -ForegroundColor Green } else { Write-Host " โœ— ๆ— ๆณ•่ฟžๆŽฅไบ‘็ซฏ็ฝ‘ๅ…ณ" -ForegroundColor Red Write-Host " ่ฏทๆฃ€ๆŸฅ๏ผš" -ForegroundColor Yellow Write-Host " 1. ไบ‘็ซฏ Tailscale ๆ˜ฏๅฆ่ฟ่กŒ" -ForegroundColor Yellow Write-Host " 2. ไบ‘็ซฏ็ฝ‘ๅ…ณๆœๅŠกๆ˜ฏๅฆๅฏๅŠจ" -ForegroundColor Yellow Write-Host " 3. ไบ‘ๅฎ‰ๅ…จ็ป„ๆ˜ฏๅฆๆ”พ่กŒ 18789" -ForegroundColor Yellow exit 1 }

4. ๆธ…็†ๆ—ง้šง้“

Write-Host "
n[4/6] ๆธ…็†ๆ—ง้šง้“่ฟ›็จ‹..." -ForegroundColor Yellow $sshProcesses = Get-Process | Where-Object { $_.ProcessName -eq "ssh" } $stopped = 0 foreach ($p in $sshProcesses) { $cmd = (Get-CimInstance Win32_Process -Filter "ProcessId = $($p.Id)" -ErrorAction SilentlyContinue).CommandLine if ($cmd -like "*${LocalPort}*" -or $cmd -like "*${CloudIP}*") { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue $stopped++ } } Write-Host " ๅทฒๅœๆญข $stopped ไธชๆ—ง้šง้“่ฟ›็จ‹" -ForegroundColor Gray

5. ๅˆ›ๅปบๆŒไน…ๅŒ–่„šๆœฌ

Write-Host "n[5/6] ๅˆ›ๅปบๆŒไน…ๅŒ–้…็ฝฎ..." -ForegroundColor Yellow

New-Item -ItemType Directory -Force -Path $ScriptDir | Out-Null

$tunnelScript = @"

OpenClaw SSH ้šง้“ๅฏๅŠจ่„šๆœฌ

$ErrorActionPreference = "SilentlyContinue" $sshArgs = "-N -L ${LocalPort}:${CloudIP}:${RemotePort} root@${CloudIP}"

ๆฃ€ๆŸฅ SSH ่ฟžๆŽฅ

while (
$true) { Start-Process ssh -ArgumentList $sshArgs -WindowStyle Hidden -ErrorAction SilentlyContinue Start-Sleep -Seconds 60

# ๆฃ€ๆŸฅ้šง้“ๆ˜ฏๅฆ้€š็•… $test = Test-NetConnection -ComputerName localhost -Port ${LocalPort} -WarningAction SilentlyContinue -InformationLevel Quiet if (-not $test) { # ้šง้“ๆ–ญๅผ€๏ผŒ้‡ๅฏ SSH ่ฟ›็จ‹ Get-Process | Where-Object { $_.ProcessName -eq "ssh" -and $_.CommandLine -like "*${LocalPort}*" } | Stop-Process -Force } } "@

$scriptPath = "$ScriptDir\start-ssh-tunnel.ps1" $tunnelScript | Out-File -FilePath $scriptPath -Encoding utf8 -Force Write-Host " โœ“ ้šง้“่„šๆœฌ๏ผš$scriptPath" -ForegroundColor Green

6. ๅˆ›ๅปบ่ฎกๅˆ’ไปปๅŠก๏ผˆๅผ€ๆœบ่‡ชๅฏ๏ผ‰

Write-Host "n[6/6] ๅˆ›ๅปบ่ฎกๅˆ’ไปปๅŠก๏ผˆๅผ€ๆœบ่‡ชๅฏ๏ผ‰..." -ForegroundColor Yellow

ๅˆ ้™คๆ—งไปปๅŠก

schtasks /Delete /TN $TaskName /F 2>$null | Out-Null

ๅˆ›ๅปบๆ–ฐไปปๅŠก๏ผˆ็ณป็ปŸๅฏๅŠจๆ—ถ + ็”จๆˆท็™ปๅฝ•ๆ—ถ๏ผ‰

$argument = "-ExecutionPolicy Bypass -WindowStyle Hidden -File "$scriptPath"" schtasks /Create /TN $TaskName /TR "powershell.exe $argument" /SC ONLOGON /RU SYSTEM /F 2>$null

if ($LASTEXITCODE -eq 0) { Write-Host " โœ“ ่ฎกๅˆ’ไปปๅŠก๏ผš$TaskName (ๅผ€ๆœบ่‡ชๅฏ)" -ForegroundColor Green } else { # ้™็บงๆ–นๆกˆ๏ผšๅฝ“ๅ‰็”จๆˆท็™ปๅฝ•ๆ—ถๅฏๅŠจ schtasks /Create /TN $TaskName /TR "powershell.exe $argument" /SC ONLOGON /F 2>$null if ($LASTEXITCODE -eq 0) { Write-Host " โœ“ ่ฎกๅˆ’ไปปๅŠก๏ผš$TaskName (็”จๆˆท็™ปๅฝ•่‡ชๅฏ)" -ForegroundColor Green } else { Write-Host " โš  ่ฎกๅˆ’ไปปๅŠกๅˆ›ๅปบๅคฑ่ดฅ๏ผŒๅฐ†ๆ‰‹ๅŠจๅฏๅŠจ" -ForegroundColor Yellow } }

็ซ‹ๅณๅฏๅŠจ้šง้“

Write-Host "n ็ซ‹ๅณๅฏๅŠจ SSH ้šง้“..." -ForegroundColor Yellow $sshArgs = "-N -L ${LocalPort}:${CloudIP}:${RemotePort} root@${CloudIP}" Start-Process ssh -ArgumentList $sshArgs -WindowStyle Hidden

Start-Sleep -Seconds 3

้ชŒ่ฏ

$tunnelTest = Test-NetConnection -ComputerName localhost -Port $LocalPort -WarningAction SilentlyContinue -InformationLevel Quiet if ($tunnelTest) { Write-Host " โœ“ SSH ้šง้“๏ผšๅทฒๅปบ็ซ‹ (localhost:${LocalPort} -> ${CloudIP}:${RemotePort})" -ForegroundColor Green

Write-Host "nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" -ForegroundColor Green Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

Write-Host "nใ€้šง้“ไฟกๆฏใ€‘" Write-Host " ๆœฌๅœฐ็ซฏๅฃ๏ผšlocalhost:${LocalPort}" Write-Host " ่ฟœ็จ‹ๅœฐๅ€๏ผš${CloudIP}:${RemotePort}" Write-Host " ่ฎกๅˆ’ไปปๅŠก๏ผš$TaskName (ๅผ€ๆœบ/็™ปๅฝ•่‡ชๅฏ)"

Write-Host "nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" Write-Host " 1. ้…็ฝฎ่ฟœ็จ‹็ฝ‘ๅ…ณ๏ผšopenclaw gateway remote set ws://localhost:${LocalPort}" Write-Host " 2. ๆฃ€ๆŸฅ็Šถๆ€๏ผšopenclaw status" Write-Host " 3. ๆŸฅ็œ‹ๆ—ฅๅฟ—๏ผšopenclaw logs --follow" } else { Write-Host " โœ— SSH ้šง้“ๅปบ็ซ‹ๅคฑ่ดฅ" -ForegroundColor Red Write-Host " ่ฏทๆฃ€ๆŸฅ SSH ๅฏ†้’ฅ้…็ฝฎๆˆ–ๆ‰‹ๅŠจ่ฟ่กŒ๏ผš" -ForegroundColor Yellow Write-Host " ssh -N -L ${LocalPort}:${CloudIP}:${RemotePort} root@${CloudIP}" exit 1 }



ๆ–นๆกˆไบŒ๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + ๆœฌๅœฐ่Š‚็‚น

ๅฎŒๆ•ดๆžถๆž„ๆต็จ‹ๅ›พ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ไบ‘็ซฏๆœๅŠกๅ™จ (Linux) โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ OpenClaw Gateway (Remote ๆจกๅผ) โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ ้’‰้’‰/้ฃžไนฆ โ”‚ โ”‚ WebSocket โ”‚ โ”‚ AI ๆจกๅž‹ API โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Webhook โ”‚ โ”‚ ๆœๅŠก็ซฏ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ Tailscale: :18789 (Token ่ฎค่ฏ) โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ Tailscale VPN (ๅŠ ๅฏ†) โ”‚ WebSocket: ws://:18789 โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๆœฌๅœฐ็”ต่„‘ (Windows) โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ OpenClaw Node (ๆœฌๅœฐ่Š‚็‚น) โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ WebSocket โ”‚ โ”‚ ๆœฌๅœฐๆ‰ง่กŒ โ”‚ โ”‚ ่ฟ”ๅ›ž็ป“ๆžœ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ ๅฎขๆˆท็ซฏ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ Tailscale: ๆœฌๅœฐ CLI/VSCode โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ้’‰้’‰ APP โ”‚ โ”‚ ๆต่งˆๅ™จ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๆ•ฐๆฎๆตๅ‘๏ผš
1. ้’‰้’‰/้ฃžไนฆ โ†’ Webhook โ†’ ไบ‘็ซฏ็ฝ‘ๅ…ณ
2. ไบ‘็ซฏ็ฝ‘ๅ…ณ โ†’ WebSocket โ†’ ๆœฌๅœฐ่Š‚็‚น
3. ๆœฌๅœฐ่Š‚็‚น โ†’ ๆ‰ง่กŒไปปๅŠก โ†’ ่ฟ”ๅ›ž็ป“ๆžœ โ†’ ไบ‘็ซฏ็ฝ‘ๅ…ณ
4. ไบ‘็ซฏ็ฝ‘ๅ…ณ โ†’ AI ๆจกๅž‹ API โ†’ ่Žทๅ–ๅ›žๅค โ†’ ่ฟ”ๅ›ž้’‰้’‰/้ฃžไนฆ

้ƒจ็ฝฒๅ‰ๆฃ€ๆŸฅๆธ…ๅ•

| ๆฃ€ๆŸฅ้กน | ๆœฌๅœฐ | ไบ‘็ซฏ | ้ชŒ่ฏๅ‘ฝไปค | |--------|------|------|----------| | Tailscale ่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | tailscale status | | Tailscale ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | tailscale ip | | Node.js (v18+) | โœ… ๅทฒๅฎ‰่ฃ… | โœ… ๅทฒๅฎ‰่ฃ… | node -v | | ้˜ฒ็ซๅข™ 18789 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ufw status | | ไบ‘ๅฎ‰ๅ…จ็ป„ 18789 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ไบ‘ๆŽงๅˆถๅฐๆฃ€ๆŸฅ | | Token ้…็ฝฎ | โœ… ไธ€่‡ด | โœ… ไธ€่‡ด | ๆฃ€ๆŸฅ้…็ฝฎๆ–‡ไปถ |

ไบ‘็ซฏๅฎŒๆ•ด้ƒจ็ฝฒ่„šๆœฌ๏ผˆRemote ๆจกๅผ + Token ่ฎค่ฏ๏ผ‰

#!/bin/bash

plan2-cloud-remote-gateway.sh - ๆ–นๆกˆไบŒ๏ผšไบ‘็ซฏ่ฟœ็จ‹็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ

set -e

echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" echo "โ•‘ ๆ–นๆกˆไบŒ๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + ๆœฌๅœฐ่Š‚็‚น โ•‘" echo "โ•‘ ไบ‘็ซฏ่ฟœ็จ‹็ฝ‘ๅ…ณ้ƒจ็ฝฒ (Remote ๆจกๅผ) โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

============== 1. ็ณป็ปŸ็Žฏๅขƒๆฃ€ๆต‹ ==============

echo -e "\n[1/7] ็ณป็ปŸ็Žฏๅขƒๆฃ€ๆต‹..."

if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID echo " ็ณป็ปŸ๏ผš$OS ($PRETTY_NAME)" else echo " โœ— ๆ— ๆณ•่ฏ†ๅˆซ็ณป็ปŸ" exit 1 fi

if [ "$EUID" -ne 0 ]; then echo " โœ— ่ฏทไฝฟ็”จ root ๆƒ้™่ฟ่กŒ" exit 1 fi echo " โœ“ ๆƒ้™ๆฃ€ๆŸฅ้€š่ฟ‡ (root)"

============== 2. Tailscale ้…็ฝฎ ==============

echo -e "\n[2/7] ้…็ฝฎ Tailscale..."

if ! command -v tailscale &> /dev/null; then echo " ๅฎ‰่ฃ… Tailscale..." if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then curl -fsSL https://tailscale.com/install.sh | sh else echo " โœ— ไธๆ”ฏๆŒ็š„็ณป็ปŸ๏ผŒ่ฏทๆ‰‹ๅŠจๅฎ‰่ฃ…" exit 1 fi fi

systemctl enable --now tailscaled 2>/dev/null || tailscaled & sleep 3

if tailscale status 2>&1 | grep -q "connected"; then TAILSCALE_IP=$(tailscale ip | head -1) echo " โœ“ Tailscale: ๅทฒ่ฟžๆŽฅ ($TAILSCALE_IP)" else echo " โš  Tailscale ๆœช่ฟžๆŽฅ" echo " ่ฟ่กŒ๏ผštailscale up" read -p " ๅฎŒๆˆๅŽๆŒ‰ๅ›ž่ฝฆ..." TAILSCALE_IP=$(tailscale ip | head -1) fi

============== 3. ้˜ฒ็ซๅข™้…็ฝฎ ==============

echo -e "\n[3/7] ้…็ฝฎ้˜ฒ็ซๅข™..."

if command -v ufw &> /dev/null && ufw status | grep -q "Status: active"; then ufw allow 18789/tcp comment "OpenClaw Gateway" echo " โœ“ UFW: 18789/tcp ๅทฒๆ”พ่กŒ" elif command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld; then firewall-cmd --permanent --add-port=18789/tcp firewall-cmd --reload echo " โœ“ Firewalld: 18789/tcp ๅทฒๆ”พ่กŒ" fi

echo " โš  ไบ‘ๆœๅŠกๅ™จๅฎ‰ๅ…จ็ป„้œ€ๆ‰‹ๅŠจๆ”พ่กŒ 18789 (Tailscale IP: $TAILSCALE_IP)"

============== 4. Node.js ้…็ฝฎ ==============

echo -e "\n[4/7] ้…็ฝฎ Node.js..."

if ! command -v node &> /dev/null; then echo " ๅฎ‰่ฃ… Node.js 22..." if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt-get install -y nodejs else echo " โœ— ไธๆ”ฏๆŒ็š„็ณป็ปŸ" exit 1 fi fi echo " โœ“ Node.js: $(node -v)"

npm config set registry https://registry.npmmirror.com 2>/dev/null || true

============== 5. OpenClaw ๅฎ‰่ฃ… ==============

echo -e "\n[5/7] ๅฎ‰่ฃ… OpenClaw..."

npm install -g openclaw echo " โœ“ OpenClaw: ๅทฒๅฎ‰่ฃ…"

============== 6. ็”Ÿๆˆ Token ==============

echo -e "\n[6/7] ็”Ÿๆˆ่ฎค่ฏ Token..."

TOKEN=$(openssl rand -hex 20) echo " โœ“ Token: $TOKEN" echo " โš  ่ฏทไฟๅญ˜ๆญค Token๏ผŒๆœฌๅœฐ่Š‚็‚น้…็ฝฎ้œ€่ฆ"

============== 7. ้…็ฝฎ็ฝ‘ๅ…ณ + systemd ==============

echo -e "\n[7/7] ้…็ฝฎ็ฝ‘ๅ…ณ (Remote ๆจกๅผ)..."

mkdir -p ~/.openclaw

cat > ~/.openclaw/openclaw.json << EOF { "gateway": { "port": 18789, "mode": "remote", "bind": "lan", "auth": { "mode": "token", "token": "$TOKEN" } }, "security": { "dangerouslyAllowInsecurePrivateWs": true } } EOF

echo " โœ“ ้…็ฝฎๆ–‡ไปถ๏ผš~/.openclaw/openclaw.json"

echo -e "\n ๅˆ›ๅปบ systemd ๆœๅŠก..." cat > /etc/systemd/system/openclaw-gateway.service << 'EOF' [Unit] Description=OpenClaw Gateway (Remote Mode) After=network.target tailscaled.service Wants=tailscaled.service

[Service] Type=simple User=root WorkingDirectory=/root/.openclaw ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789 --bind lan --allow-unconfigured Restart=on-failure RestartSec=10 StartLimitBurst=3 StartLimitIntervalSec=300

Environment=NODE_ENV=production Environment=OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1

LimitNOFILE=65535 Nice=-5

[Install] WantedBy=multi-user.target EOF

systemctl daemon-reload systemctl enable openclaw-gateway systemctl start openclaw-gateway

sleep 5

============== ้ชŒ่ฏ ==============

echo -e "\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" if systemctl is-active --quiet openclaw-gateway; then echo "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

echo -e "\nใ€ๆœๅŠกไฟกๆฏใ€‘" echo " ๆœๅŠก็Šถๆ€๏ผš$(systemctl is-active openclaw-gateway)" echo " ่ฟ่กŒๆจกๅผ๏ผšremote" echo " ่ฎค่ฏๆ–นๅผ๏ผštoken"

echo -e "\nใ€็ฝ‘็ปœไฟกๆฏใ€‘" echo " Tailscale IP: $TAILSCALE_IP" echo " ็ฝ‘ๅ…ณๅœฐๅ€๏ผšws://${TAILSCALE_IP}:18789" echo " Token: $TOKEN"

echo -e "\nใ€็ซฏๅฃ็›‘ๅฌใ€‘" ss -tlnp | grep 18789 || true

echo -e "\nใ€ๆœฌๅœฐ่Š‚็‚น้…็ฝฎ็คบไพ‹ (PowerShell)ใ€‘" cat << POWERSHELL $config = @{ gateway = @{ mode = "remote" auth = @{ token = "$TOKEN" } remote = @{ url = "ws://${TAILSCALE_IP}:18789" } } } | ConvertTo-Json | Out-File ~/.openclaw/openclaw.json -Encoding utf8 POWERSHELL

echo -e "\nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" echo " 1. ๅœจๆœฌๅœฐ่ฟ่กŒ plan2-local-node.ps1" echo " 2. ๆฃ€ๆŸฅ่ฟžๆŽฅ๏ผšopenclaw status" echo " 3. ๆŸฅ็œ‹ๆ—ฅๅฟ—๏ผšjournalctl -u openclaw-gateway -f" else echo "โ•‘ โœ— ้ƒจ็ฝฒๅคฑ่ดฅ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" journalctl -u openclaw-gateway --no-pager -n 20 exit 1 fi

ๆœฌๅœฐ่Š‚็‚นๅฎŒๆ•ด้ƒจ็ฝฒ่„šๆœฌ

# plan2-local-node.ps1 - ๆ–นๆกˆไบŒ๏ผšๆœฌๅœฐ่Š‚็‚นๅฎŒๆ•ด้ƒจ็ฝฒ
param(
    [string]$CloudIP = "",
    [string]$Token = ""
)

$ErrorActionPreference = "Stop" $OpenClawDir = "$env:USERPROFILE\.openclaw" $NodeExe = "C:\Program Files\nodejs\node.exe" $OpenClawMjs = "$env:APPDATA\npm\node_modules\openclaw\openclaw.mjs" $TaskName = "OpenClaw-Node"

Write-Host "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ ๆ–นๆกˆไบŒ๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + Tailscale + ๆœฌๅœฐ่Š‚็‚น โ•‘" -ForegroundColor Cyan Write-Host "โ•‘ ๆœฌๅœฐ่Š‚็‚นๅฎŒๆ•ด้ƒจ็ฝฒ โ•‘" Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

1. ๆฃ€ๆŸฅ Tailscale

Write-Host "
n[1/6] ๆฃ€ๆŸฅ Tailscale..." -ForegroundColor Yellow $tsStatus = tailscale status 2>&1 if ($LASTEXITCODE -ne 0) { Write-Host " Tailscale ๆœช่ฟ่กŒ๏ผŒๆญฃๅœจๅฏๅŠจ..." -ForegroundColor Yellow tailscale up Start-Sleep -Seconds 5 } $tsIP = (tailscale ip | Select-Object -First 1).Trim() Write-Host " โœ“ Tailscale IP: $tsIP" -ForegroundColor Green

2. ๆฃ€ๆŸฅ Node.js

Write-Host "n[2/6] ๆฃ€ๆŸฅ Node.js..." -ForegroundColor Yellow if (!(Test-Path $NodeExe)) { Write-Host " โœ— Node.js ๆœชๅฎ‰่ฃ…" -ForegroundColor Red Write-Host " ไธ‹่ฝฝ๏ผšhttps://nodejs.org/" -ForegroundColor Yellow exit 1 } $nodeVer = & $NodeExe -v Write-Host " โœ“ Node.js: $nodeVer" -ForegroundColor Green

3. ๆฃ€ๆŸฅ/ๅฎ‰่ฃ… OpenClaw

Write-Host "
n[3/6] ๆฃ€ๆŸฅ OpenClaw..." -ForegroundColor Yellow if (!(Test-Path $OpenClawMjs)) { Write-Host " ๅฎ‰่ฃ… OpenClaw..." -ForegroundColor Yellow npm install -g openclaw --registry=https://registry.npmmirror.com if ($LASTEXITCODE -ne 0) { Write-Host " โœ— ๅฎ‰่ฃ…ๅคฑ่ดฅ" -ForegroundColor Red exit 1 } } Write-Host " โœ“ OpenClaw: ๅทฒๅฎ‰่ฃ…" -ForegroundColor Green

4. ่Žทๅ–ไบ‘็ซฏไฟกๆฏ

Write-Host "n[4/6] ้…็ฝฎ่ฟžๆŽฅไฟกๆฏ..." -ForegroundColor Yellow

if ($CloudIP -eq "") { Write-Host " ่ฏท่พ“ๅ…ฅไบ‘็ซฏ็ฝ‘ๅ…ณ Tailscale IP:" -ForegroundColor Yellow $CloudIP = Read-Host " Cloud IP" }

if ($Token -eq "") { Write-Host " ่ฏท่พ“ๅ…ฅไบ‘็ซฏ็ฝ‘ๅ…ณ Token:" -ForegroundColor Yellow $Token = Read-Host " Token" }

Write-Host " ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผš$CloudIP:18789" -ForegroundColor Green

5. ๆต‹่ฏ•่ฟžๆŽฅ

Write-Host "
n[5/6] ๆต‹่ฏ•ไบ‘็ซฏ่ฟžๆŽฅ..." -ForegroundColor Yellow $testResult = Test-NetConnection -ComputerName $CloudIP -Port 18789 -WarningAction SilentlyContinue -InformationLevel Quiet if (!$testResult) { Write-Host " โœ— ๆ— ๆณ•่ฟžๆŽฅไบ‘็ซฏ็ฝ‘ๅ…ณ" -ForegroundColor Red Write-Host " ่ฏทๆฃ€ๆŸฅ๏ผš" -ForegroundColor Yellow Write-Host " 1. ไบ‘็ซฏ Tailscale ๆ˜ฏๅฆ่ฟ่กŒ" -ForegroundColor Yellow Write-Host " 2. ไบ‘็ซฏ็ฝ‘ๅ…ณๆ˜ฏๅฆๅฏๅŠจ" -ForegroundColor Yellow Write-Host " 3. ไบ‘ๅฎ‰ๅ…จ็ป„ๆ˜ฏๅฆๆ”พ่กŒ 18789" -ForegroundColor Yellow exit 1 } Write-Host " โœ“ ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผšๅฏ่พพ" -ForegroundColor Green

6. ้…็ฝฎๅนถๅฏๅŠจ

Write-Host "n[6/6] ้…็ฝฎๅนถๅฏๅŠจ่Š‚็‚น..." -ForegroundColor Yellow

New-Item -ItemType Directory -Force -Path $OpenClawDir | Out-Null

$config = @{ gateway = @{ mode = "remote" auth = @{ token = $Token } remote = @{ url = "ws://$($CloudIP):18789" } } } | ConvertTo-Json -Depth 10

$config | Out-File -FilePath "$OpenClawDir\openclaw.json" -Encoding utf8 -Force Write-Host " โœ“ ้…็ฝฎ๏ผš$OpenClawDir\openclaw.json" -ForegroundColor Green

ๅˆ›ๅปบๅฏๅŠจ่„šๆœฌ

$startScript = "$OpenClawDir\start-node.ps1" @"
$env:OPENCLAW_ALLOW_INSECURE_PRIVATE_WS = "1" & "$NodeExe" "$OpenClawMjs" node run --host "$CloudIP" --port 18789 "@ | Out-File -FilePath $startScript -Encoding utf8 -Force

ๅฏๅŠจ่Š‚็‚น

Write-Host " ๅฏๅŠจ่Š‚็‚น..." -ForegroundColor Yellow $env:OPENCLAW_ALLOW_INSECURE_PRIVATE_WS = "1" Start-Process $NodeExe -ArgumentList "$OpenClawMjs", "node", "run", "--host", $CloudIP, "--port", "18789" -WindowStyle Normal

Start-Sleep -Seconds 5

Write-Host "nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" -ForegroundColor Green Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

Write-Host "nใ€่ฟžๆŽฅไฟกๆฏใ€‘" Write-Host " ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผšws://$($CloudIP):18789" Write-Host " ่Š‚็‚น็Šถๆ€๏ผšๅฏๅŠจไธญ..."

Write-Host "nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" Write-Host " 1. ๆฃ€ๆŸฅ็Šถๆ€๏ผšopenclaw status" Write-Host " 2. ๆŸฅ็œ‹ๆ—ฅๅฟ—๏ผšopenclaw logs --follow" Write-Host " 3. ้…็ฝฎๅผ€ๆœบ่‡ชๅฏ๏ผˆๅฏ้€‰๏ผ‰๏ผš" Write-Host " schtasks /Create /TN "$TaskName" /TR "powershell -File '$startScript'" /SC ONLOGON /F"


ๆ–นๆกˆไธ‰๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + ๆœฌๅœฐ็ฝ‘ๅ…ณๅŒ้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰

ๅฎŒๆ•ดๆžถๆž„ๆต็จ‹ๅ›พ

                              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                              โ”‚  ้€š่ฎฏ่ฝฏไปถ     โ”‚
                              โ”‚ (้’‰้’‰/้ฃžไนฆ)   โ”‚
                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                     โ”‚
                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                โ”‚                                         โ”‚
                โ–ผ                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    ไบ‘็ซฏ็ฝ‘ๅ…ณ (Primary)     โ”‚               โ”‚   ๆœฌๅœฐ็ฝ‘ๅ…ณ (Secondary)     โ”‚
โ”‚  :18789    โ”‚               โ”‚   127.0.0.1:18789         โ”‚
โ”‚                           โ”‚               โ”‚                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚               โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ ้€š้“ๆ’ไปถ (้’‰้’‰/้ฃžไนฆ) โ”‚  โ”‚               โ”‚  โ”‚ ๆœฌๅœฐ้€š้“ (ๆต‹่ฏ•/ๅค‡็”จ) โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚               โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚             โ”‚             โ”‚               โ”‚             โ”‚             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚               โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ AI ๆจกๅž‹ (ไบ‘็ซฏ API)    โ”‚  โ”‚               โ”‚  โ”‚ AI ๆจกๅž‹ (ๆœฌๅœฐ API)    โ”‚  โ”‚
โ”‚  โ”‚ Claude / Qwen       โ”‚  โ”‚               โ”‚  โ”‚ Ollama / LM Studio  โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚               โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚             โ”‚             โ”‚               โ”‚             โ”‚             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚   ๅŒๆญฅ้€š้“    โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ ๆ•ฐๆฎๅŒๆญฅๆจกๅ—        โ”‚โ—„โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ–บโ”‚ ๆ•ฐๆฎๅŒๆญฅๆจกๅ—        โ”‚  โ”‚
โ”‚  โ”‚ - ไผš่ฏ็Šถๆ€ (ๅฎžๆ—ถ)   โ”‚  โ”‚   Tailscale   โ”‚  โ”‚ - ไผš่ฏ็Šถๆ€ (ๅฎžๆ—ถ)   โ”‚  โ”‚
โ”‚  โ”‚ - ๆถˆๆฏๅކๅฒ (ๅขž้‡)   โ”‚  โ”‚   (ๅŠ ๅฏ†)      โ”‚  โ”‚ - ๆถˆๆฏๅކๅฒ (ๅขž้‡)   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚               โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚             โ”‚             โ”‚               โ”‚             โ”‚             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚               โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ SQLite (ไบ‘็ซฏๅญ˜ๅ‚จ)   โ”‚  โ”‚               โ”‚  โ”‚ SQLite (ๆœฌๅœฐๅญ˜ๅ‚จ)   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚               โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๆ•…้šœ่ฝฌ็งป: โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๆญฃๅธธ๏ผš้€š่ฎฏ่ฝฏไปถ โ†’ ไบ‘็ซฏ็ฝ‘ๅ…ณ โ†’ ๅค„็†ๅนถๅ›žๅค โ”‚ โ”‚ ไบ‘็ซฏๆ•…้šœ๏ผšๆœฌๅœฐ็ฝ‘ๅ…ณๆŽฅ็ฎก โ†’ ็ฆป็บฟ้˜Ÿๅˆ— โ†’ ไบ‘็ซฏๆขๅคๅŽๅŒๆญฅ โ”‚ โ”‚ ๆœฌๅœฐๆ•…้šœ๏ผšไบ‘็ซฏ็ปง็ปญ่ฟ่กŒ โ†’ ๆ•ฐๆฎไปŽไบ‘็ซฏๆขๅค โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜


้ƒจ็ฝฒๅ‰ๆฃ€ๆŸฅๆธ…ๅ•

| ๆฃ€ๆŸฅ้กน | ๆœฌๅœฐ | ไบ‘็ซฏ | ้ชŒ่ฏๅ‘ฝไปค | |--------|------|------|----------| | Tailscale ่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | โœ… ๅŒไธ€่ดฆๅท | tailscale status | | Tailscale ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | โœ… ๅทฒ่ฟžๆŽฅ | tailscale ip | | Node.js (v18+) | โœ… ๅทฒๅฎ‰่ฃ… | โœ… ๅทฒๅฎ‰่ฃ… | node -v | | ้˜ฒ็ซๅข™ 18789 | โš ๏ธ ไป…ๆœฌๅœฐ | โš ๏ธ ้œ€ๆ”พ่กŒ | ufw status | | ไบ‘ๅฎ‰ๅ…จ็ป„ 18789 | โŒ | โš ๏ธ ้œ€ๆ”พ่กŒ | ไบ‘ๆŽงๅˆถๅฐๆฃ€ๆŸฅ | | ๅŒๆญฅ Token | โœ… ไธ€่‡ด | โœ… ไธ€่‡ด | ๆฃ€ๆŸฅ้…็ฝฎๆ–‡ไปถ |

ๆœฌๅœฐ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅผ€ๆœบ่‡ชๅฏ + ๅŒๆญฅ้…็ฝฎ๏ผ‰

powershell

plan3-local-gateway.ps1 - ๆ–นๆกˆไธ‰๏ผšๆœฌๅœฐ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰

param( [string]$CloudIP = "" )

$ErrorActionPreference = "Stop" $OpenClawDir = "$env:USERPROFILE\.openclaw" $NodeExe = "C:\Program Files\nodejs\node.exe" $TaskName = "OpenClaw-Gateway" $SyncPort = 18790

Write-Host "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ ๆ–นๆกˆไธ‰๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + ๆœฌๅœฐ็ฝ‘ๅ…ณๅŒ้ƒจ็ฝฒ โ•‘" -ForegroundColor Cyan Write-Host "โ•‘ ๆœฌๅœฐ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰ โ•‘" Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

1. ๆฃ€ๆŸฅ Tailscale

Write-Host "
n[1/7] ๆฃ€ๆŸฅ Tailscale..." -ForegroundColor Yellow $tsStatus = tailscale status 2>&1 if ($LASTEXITCODE -ne 0) { Write-Host " Tailscale ๆœช่ฟ่กŒ๏ผŒๆญฃๅœจๅฏๅŠจ..." -ForegroundColor Yellow tailscale up Start-Sleep -Seconds 5 } $tsIP = (tailscale ip | Select-Object -First 1).Trim() Write-Host " โœ“ Tailscale IP: $tsIP" -ForegroundColor Green

2. ๆฃ€ๆŸฅ Node.js

Write-Host "n[2/7] ๆฃ€ๆŸฅ Node.js..." -ForegroundColor Yellow if (!(Test-Path $NodeExe)) { Write-Host " โœ— Node.js ๆœชๅฎ‰่ฃ…" -ForegroundColor Red exit 1 } Write-Host " โœ“ Node.js: $(& $NodeExe -v)" -ForegroundColor Green

3. ๅฎ‰่ฃ… OpenClaw

Write-Host "
n[3/7] ๅฎ‰่ฃ… OpenClaw..." -ForegroundColor Yellow npm install -g openclaw --registry=https://registry.npmmirror.com if ($LASTEXITCODE -ne 0) { Write-Host " โœ— ๅฎ‰่ฃ…ๅคฑ่ดฅ" -ForegroundColor Red exit 1 } Write-Host " โœ“ OpenClaw: ๅทฒๅฎ‰่ฃ…" -ForegroundColor Green

4. ้…็ฝฎ็ฝ‘ๅ…ณ

Write-Host "n[4/7] ้…็ฝฎ็ฝ‘ๅ…ณ..." -ForegroundColor Yellow

if ($CloudIP -eq "") { Write-Host " ่ฏท่พ“ๅ…ฅไบ‘็ซฏ็ฝ‘ๅ…ณ Tailscale IP:" -ForegroundColor Yellow $CloudIP = Read-Host " Cloud IP" }

New-Item -ItemType Directory -Force -Path $OpenClawDir | Out-Null

$config = @{ gateway = @{ port = 18789 mode = "local" bind = "localhost" } sync = @{ enabled = $true remoteUrl = "https://$($CloudIP):${SyncPort}" token = $(openssl rand -hex 20) direction = "bidirectional" interval = 300 } } | ConvertTo-Json -Depth 10

$config | Out-File -FilePath "$OpenClawDir\openclaw.json" -Encoding utf8 -Force Write-Host " โœ“ ้…็ฝฎ๏ผš$OpenClawDir\openclaw.json" -ForegroundColor Green Write-Host " ๅŒๆญฅ้…็ฝฎ๏ผšๅŒๅ‘ๅŒๆญฅ (5 ๅˆ†้’Ÿ้—ด้š”)" -ForegroundColor Green

5. ๅˆ›ๅปบๅผ€ๆœบ่‡ชๅฏ่„šๆœฌ

Write-Host "
n[5/7] ๅˆ›ๅปบๅผ€ๆœบ่‡ชๅฏ้…็ฝฎ..." -ForegroundColor Yellow

$startScript = "$OpenClawDir\start-gateway.ps1" @" $env:OPENCLAW_ALLOW_INSECURE_PRIVATE_WS = "1" & "$NodeExe" "$OpenClawMjs" gateway run "@ | Out-File -FilePath $startScript -Encoding utf8 -Force

ๅˆ›ๅปบ่ฎกๅˆ’ไปปๅŠก

$argument = "-ExecutionPolicy Bypass -WindowStyle Hidden -File "$startScript"" schtasks /Delete /TN $TaskName /F 2>$null | Out-Null schtasks /Create /TN $TaskName /TR "powershell.exe $argument" /SC ONLOGON /F 2>$null

if ($LASTEXITCODE -eq 0) { Write-Host " โœ“ ่ฎกๅˆ’ไปปๅŠก๏ผš$TaskName (ๅผ€ๆœบ่‡ชๅฏ)" -ForegroundColor Green } else { Write-Host " โš  ่ฎกๅˆ’ไปปๅŠกๅˆ›ๅปบๅคฑ่ดฅ" -ForegroundColor Yellow }

6. ๅฏๅŠจ็ฝ‘ๅ…ณ

Write-Host "
n[6/7] ๅฏๅŠจ็ฝ‘ๅ…ณ..." -ForegroundColor Yellow

$env:OPENCLAW_ALLOW_INSECURE_PRIVATE_WS = "1" Start-Process $NodeExe -ArgumentList "$OpenClawMjs", "gateway", "run" -WindowStyle Normal

Start-Sleep -Seconds 5

7. ้ชŒ่ฏ

Write-Host "n[7/7] ้ชŒ่ฏ็ฝ‘ๅ…ณ..." -ForegroundColor Yellow $portTest = Test-NetConnection -ComputerName localhost -Port 18789 -WarningAction SilentlyContinue -InformationLevel Quiet if ($portTest) { Write-Host " โœ“ ็ฝ‘ๅ…ณ๏ผš่ฟ่กŒไธญ (localhost:18789)" -ForegroundColor Green

Write-Host "nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan Write-Host "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" -ForegroundColor Green Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan

Write-Host "nใ€่ฎฟ้—ฎไฟกๆฏใ€‘" Write-Host " ็ฝ‘ๅ…ณๅœฐๅ€๏ผšws://localhost:18789" Write-Host " ๆŽงๅˆถ้ขๆฟ๏ผšhttp://localhost:18789/" Write-Host " ๅผ€ๆœบ่‡ชๅฏ๏ผš$TaskName"

Write-Host "nใ€ๅŒๆญฅ้…็ฝฎใ€‘" Write-Host " ไบ‘็ซฏ็ฝ‘ๅ…ณ๏ผš$CloudIP" Write-Host " ๅŒๆญฅ็ซฏๅฃ๏ผš${SyncPort}" Write-Host " ๅŒๆญฅๆ–นๅ‘๏ผšๅŒๅ‘" Write-Host " ๅŒๆญฅ้—ด้š”๏ผš300 ็ง’"

Write-Host "nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" Write-Host " 1. ๅœจไบ‘็ซฏ่ฟ่กŒ plan3-cloud-gateway.sh" Write-Host " 2. ๆฃ€ๆŸฅ็Šถๆ€๏ผšopenclaw status" Write-Host " 3. ้…็ฝฎๅŒๆญฅ๏ผšopenclaw sync config" } else { Write-Host " โœ— ็ฝ‘ๅ…ณๅฏๅŠจๅคฑ่ดฅ" -ForegroundColor Red exit 1 }


ไบ‘็ซฏ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰

bash #!/bin/bash

plan3-cloud-gateway.sh - ๆ–นๆกˆไธ‰๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰

set -e

echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" echo "โ•‘ ๆ–นๆกˆไธ‰๏ผšไบ‘็ซฏ็ฝ‘ๅ…ณ + ๆœฌๅœฐ็ฝ‘ๅ…ณๅŒ้ƒจ็ฝฒ โ•‘" echo "โ•‘ ไบ‘็ซฏ็ฝ‘ๅ…ณๅฎŒๆ•ด้ƒจ็ฝฒ๏ผˆๅซๅŒๆญฅๅค‡ไปฝ๏ผ‰ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

็ณป็ปŸๆฃ€ๆต‹

if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID else echo "โœ— ๆ— ๆณ•่ฏ†ๅˆซ็ณป็ปŸ" exit 1 fi

if [ "$EUID" -ne 0 ]; then echo "โœ— ่ฏทไฝฟ็”จ root ๆƒ้™่ฟ่กŒ" exit 1 fi

1. Tailscale

echo -e "\n[1/7] ้…็ฝฎ Tailscale..." if ! command -v tailscale &> /dev/null; then curl -fsSL https://tailscale.com/install.sh | sh fi systemctl enable --now tailscaled 2>/dev/null || tailscaled & sleep 3 TAILSCALE_IP=$(tailscale ip | head -1) echo " โœ“ Tailscale: $TAILSCALE_IP"

2. ้˜ฒ็ซๅข™

echo -e "\n[2/7] ้…็ฝฎ้˜ฒ็ซๅข™..." if command -v ufw &> /dev/null && ufw status | grep -q "active"; then ufw allow 18789/tcp comment "OpenClaw Gateway" ufw allow 18790/tcp comment "OpenClaw Sync" echo " โœ“ UFW: 18789, 18790 ๅทฒๆ”พ่กŒ" elif command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld; then firewall-cmd --permanent --add-port=18789/tcp firewall-cmd --permanent --add-port=18790/tcp firewall-cmd --reload echo " โœ“ Firewalld: 18789, 18790 ๅทฒๆ”พ่กŒ" fi echo " โš  ไบ‘ๆœๅŠกๅ™จๅฎ‰ๅ…จ็ป„้œ€ๆ‰‹ๅŠจๆ”พ่กŒ 18789, 18790"

3. Node.js

echo -e "\n[3/7] ้…็ฝฎ Node.js..." if ! command -v node &> /dev/null; then if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt-get install -y nodejs fi fi echo " โœ“ Node.js: $(node -v)"

4. OpenClaw

echo -e "\n[4/7] ๅฎ‰่ฃ… OpenClaw..." npm install -g openclaw --registry=https://registry.npmmirror.com echo " โœ“ OpenClaw: ๅทฒๅฎ‰่ฃ…"

5. ้…็ฝฎ

echo -e "\n[5/7] ้…็ฝฎ็ฝ‘ๅ…ณ๏ผˆๅซๅŒๆญฅ๏ผ‰..." mkdir -p ~/.openclaw

cat > ~/.openclaw/openclaw.json << 'EOF' { "gateway": { "port": 18789, "mode": "local", "bind": "lan" }, "sync": { "enabled": true, "port": 18790, "token": "auto-generated", "direction": "bidirectional", "interval": 300 } } EOF

echo " โœ“ ้…็ฝฎๆ–‡ไปถ๏ผš~/.openclaw/openclaw.json"

6. systemd ๆœๅŠก

echo -e "\n[6/7] ๅˆ›ๅปบ systemd ๆœๅŠก..."

cat > /etc/systemd/system/openclaw-gateway.service << 'EOF' [Unit] Description=OpenClaw Gateway (with Sync) After=network.target tailscaled.service Wants=tailscaled.service

[Service] Type=simple User=root WorkingDirectory=/root/.openclaw ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789 --bind lan Restart=always Environment=NODE_ENV=production

LimitNOFILE=65535 Nice=-5

[Install] WantedBy=multi-user.target EOF

systemctl daemon-reload systemctl enable openclaw-gateway systemctl start openclaw-gateway

sleep 5

7. ้ชŒ่ฏ

echo -e "\n[7/7] ้ชŒ่ฏๆœๅŠก..."

echo -e "\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" if systemctl is-active --quiet openclaw-gateway; then echo "โ•‘ โœ“ ้ƒจ็ฝฒๆˆๅŠŸ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

echo -e "\nใ€ๆœๅŠกไฟกๆฏใ€‘" echo " ๆœๅŠก็Šถๆ€๏ผš$(systemctl is-active openclaw-gateway)" echo " ๅผ€ๆœบ่‡ชๅฏ๏ผš$(systemctl is-enabled openclaw-gateway)"

echo -e "\nใ€็ฝ‘็ปœไฟกๆฏใ€‘" echo " Tailscale IP: $TAILSCALE_IP" echo " ็ฝ‘ๅ…ณๅœฐๅ€๏ผšws://${TAILSCALE_IP}:18789" echo " ๅŒๆญฅ็ซฏๅฃ๏ผš${TAILSCALE_IP}:18790"

echo -e "\nใ€็ซฏๅฃ็›‘ๅฌใ€‘" ss -tlnp | grep -E "18789|18790" || true

echo -e "\nใ€ไธ‹ไธ€ๆญฅๆ“ไฝœใ€‘" echo " 1. ๅœจๆœฌๅœฐ่ฟ่กŒ plan3-local-gateway.ps1" echo " 2. ้…็ฝฎๅŒๅ‘ๅŒๆญฅ๏ผšopenclaw sync config" echo " 3. ๆŸฅ็œ‹ๅŒๆญฅ็Šถๆ€๏ผšopenclaw sync status" else echo "โ•‘ โœ— ้ƒจ็ฝฒๅคฑ่ดฅ โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" journalctl -u openclaw-gateway --no-pager -n 20 exit 1 fi



ๆ•…้šœๆŽ’ๆŸฅ

้€š็”จ่ฏŠๆ–ญ่„šๆœฌ

bash #!/bin/bash

diagnostic.sh - OpenClaw ๅฟซ้€Ÿ่ฏŠๆ–ญ

echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" echo "โ•‘ OpenClaw ่ฏŠๆ–ญๆŠฅๅ‘Š โ•‘" echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"

echo -e "\nใ€1. ็ณป็ปŸไฟกๆฏใ€‘" uname -a grep PRETTY_NAME /etc/os-release 2>/dev/null || true

echo -e "\nใ€2. Tailscale ็Šถๆ€ใ€‘" tailscale status 2>&1 | head -10 || echo "Tailscale ๆœชๅฎ‰่ฃ…/ๆœช่ฟ่กŒ"

echo -e "\nใ€3. Node.js ็‰ˆๆœฌใ€‘" node -v 2>/dev/null || echo "Node.js ๆœชๅฎ‰่ฃ…" npm -v 2>/dev/null || true

echo -e "\nใ€4. OpenClaw ็Šถๆ€ใ€‘" openclaw status 2>&1 | head -20 || echo "OpenClaw ๆœชๅฎ‰่ฃ…/ๆ— ๆณ•่ฟ่กŒ"

echo -e "\nใ€5. ็ซฏๅฃ็›‘ๅฌใ€‘" ss -tlnp 2>/dev/null | grep -E "18789|18790" || netstat -tlnp 2>/dev/null | grep -E "18789|18790" || echo "ๆ—  OpenClaw ็ซฏๅฃ"

echo -e "\nใ€6. ้˜ฒ็ซๅข™็Šถๆ€ใ€‘" if command -v ufw &> /dev/null; then ufw status 2>&1 | head -10 fi if command -v firewall-cmd &> /dev/null; then firewall-cmd --list-all 2>&1 | head -10 fi

echo -e "\nใ€7. ็ฝ‘ๅ…ณๆœๅŠกใ€‘" systemctl status openclaw-gateway --no-pager -l 2>&1 | head -15 || echo "ๆœๅŠกๆœชๅฎ‰่ฃ…"

echo -e "\nใ€8. ๆœ€่ฟ‘ๆ—ฅๅฟ—ใ€‘" journalctl -u openclaw-gateway --no-pager -n 10 2>&1 || echo "ๆ— ๆ—ฅๅฟ—" `

ๅธธ่ง้—ฎ้ข˜้€ŸๆŸฅ

| ้—ฎ้ข˜ | ๅฏ่ƒฝๅŽŸๅ›  | ่งฃๅ†ณๆ–นๆกˆ | |------|----------|----------| | ็ซฏๅฃไธ้€š | ้˜ฒ็ซๅข™้˜ปๆŒก | ufw allow 18789/tcp | | Tailscale ๆ–ญๅผ€ | ่ฎค่ฏ่ฟ‡ๆœŸ | tailscale up --force | | ๅŒๆญฅๅคฑ่ดฅ | Token ไธไธ€่‡ด | ๆฃ€ๆŸฅไธค่พน้…็ฝฎๆ–‡ไปถ | | ๆœๅŠกๆ— ๆณ•ๅฏๅŠจ | ็ซฏๅฃๅ ็”จ | ss -tlnp \| grep 18789` | | Webhook ไธๅ“ๅบ” | ๅฎ‰ๅ…จ็ป„ๆœชๆ”พ่กŒ | ไบ‘ๆŽงๅˆถๅฐๆทปๅŠ ๅ…ฅ็ซ™่ง„ๅˆ™ |