OpenClaw 节点配置完整教程:Mac mini 连接 Gateway 踩坑记录

背景

将 Mac mini 配置为 OpenClaw 节点,通过 Tailscale 连接到远程 Gateway,实现:

  • 开机自动连接 Gateway
  • Gateway 直接控制节点执行命令
  • Codex CLI 远程使用

最终架构:

1
2
3
4
5
6
7
8
9
┌─────────────────┐                    ┌─────────────────┐
│ Mac mini │ │ Gateway 服务器 │
│ (节点) │ │ (云端网关) │
├─────────────────┤ ├─────────────────┤
│ Tailscale │◄──── Tailscale ───►│ Tailscale │
│ Trojan 客户端 │ │ Trojan 服务端 │
│ OpenClaw Node │◄──── WebSocket ───►│ socat 转发 │
│ Codex CLI │ │ OpenClaw Gateway│
└─────────────────┘ └─────────────────┘

踩坑清单

# 坑点 问题 解决方案
1 Tailscale 未安装 GUI tailscale up 报错 brew services start tailscale
2 OpenClaw Node 路径错误 找不到模块 openclaw node run 而非直接调用
3 WebSocket 协议不匹配 需要审批 添加 OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1
4 Gateway 绑定 loopback 外部无法连接 socat 转发端口
5 节点首次连接需审批 连接失败 openclaw devices approve
6 Codex OAuth 地区限制 403 Forbidden 本地浏览器完成授权,绕过代理
7 OpenAI 封锁代理 IP SOCKS5 也被拒 本地网络直接授权
8 nodes run –raw 需审批 shell 包装器限制 不用 --raw,直接传命令
9 –cwd 路径格式 审批失败 使用完整绝对路径
10 LaunchAgent 权限 Node.js 找不到 设置 EnvironmentVariables PATH

完整配置步骤

第一阶段:服务器端配置

1. Gateway 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Gateway 默认绑定 127.0.0.1:18789
# 外部无法直接连接,需要 socat 转发

# 安装 socat
apt install socat

# 转发 Tailscale IP:18790 → loopback:18789
socat TCP-LISTEN:18790,reuseaddr,fork TCP:127.0.0.1:18789 &

# 设置开机自启(systemd)
cat > /etc/systemd/system/openclaw-socat.service << 'EOF'
[Unit]
Description=OpenClaw Gateway socat forwarder
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/socat TCP-LISTEN:18790,reuseaddr,fork TCP:127.0.0.1:18789
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl enable openclaw-socat
systemctl start openclaw-socat

2. Trojan 服务端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 安装 Trojan
apt install trojan

# 配置
cat > /usr/src/trojan/server.conf << 'EOF'
{
"run_type": "server",
"local_addr": "0.0.0.0",
"local_port": 443,
"remote_addr": "127.0.0.1",
"remote_port": 80,
"password": ["YOUR_PASSWORD"],
"ssl": {
"cert": "/path/to/fullchain.cer",
"key": "/path/to/private.key"
}
}
EOF

第二阶段:Mac mini 节点配置

1. Tailscale 安装与配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装 Tailscale(CLI 版本)
brew install tailscale

# 启动服务
sudo brew services start tailscale

# 连接
tailscale up

# 验证
tailscale status
# 100.64.13.100 marsdemac-mini ← Mac mini
# 100.115.57.114 meta-bliss-2 ← Gateway

⚠️ 坑点 1: 如果没有安装 Tailscale GUI 应用,tailscale up 会报错 “failed to connect to local Tailscale service”。解决方法是用 brew services start tailscale 启动守护进程。

2. Trojan 客户端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 下载 Trojan 客户端
mkdir -p ~/trojan
cd ~/trojan
wget https://github.com/trojan-gfw/trojan/releases/download/v1.16.0/trojan-1.16.0-macos-x64.tar.xz
tar xf trojan-1.16.0-macos-x64.tar.xz

# 配置客户端
cat > ~/trojan/trojan/client.json << 'EOF'
{
"run_type": "client",
"local_addr": "127.0.0.1",
"local_port": 1080,
"remote_addr": "YOUR_SERVER_IP",
"remote_port": 443,
"password": ["YOUR_PASSWORD"]
}
EOF

# 测试连接
cd ~/trojan/trojan
./trojan -c client.json &
curl -x socks5://127.0.0.1:1080 https://ifconfig.me

3. HTTP 代理脚本

Codex OAuth 需要 HTTP 代理,但 Trojan 只提供 SOCKS5。创建转换脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
cat > /tmp/http_proxy.py << 'EOF'
#!/usr/bin/env python3
"""Simple HTTP proxy that forwards to SOCKS5"""
import socket
import struct
import threading
import sys

SOCKS5_HOST = "127.0.0.1"
SOCKS5_PORT = 1080
HTTP_PORT = 8118

def socks5_connect(target_host, target_port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(30)
sock.connect((SOCKS5_HOST, SOCKS5_PORT))
sock.send(b"\x05\x01\x00")
response = sock.recv(2)
if response != b"\x05\x00":
raise Exception("SOCKS5 auth failed")

request = b"\x05\x01\x00\x01"
request += socket.inet_aton(socket.gethostbyname(target_host))
request += struct.pack(">H", target_port)
sock.send(request)
response = sock.recv(10)
if response[1] != 0:
raise Exception(f"SOCKS5 connect failed: {response[1]}")
return sock

def handle_client(client_sock):
try:
request = client_sock.recv(8192)
if not request:
return

lines = request.decode("utf-8", errors="ignore").split("\r\n")
if not lines:
return

first_line = lines[0].split()
if len(first_line) < 3:
return

method = first_line[0]

if method == "CONNECT":
host_port = first_line[1].split(":")
host = host_port[0]
port = int(host_port[1]) if len(host_port) > 1 else 443
remote_sock = socks5_connect(host, port)
client_sock.send(b"HTTP/1.1 200 Connection Established\r\n\r\n")

while True:
data = client_sock.recv(8192)
if not data:
break
remote_sock.send(data)
response = remote_sock.recv(8192)
if response:
client_sock.send(response)
remote_sock.close()
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
finally:
client_sock.close()

def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("0.0.0.0", HTTP_PORT))
server.listen(100)
print(f"HTTP proxy running on port {HTTP_PORT}")
sys.stdout.flush()

while True:
client_sock, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(client_sock,))
thread.daemon = True
thread.start()

if __name__ == "__main__":
main()
EOF

chmod +x /tmp/http_proxy.py
python3 /tmp/http_proxy.py &

4. OpenClaw Node 安装

1
2
3
4
5
6
# 安装 OpenClaw CLI
npm install -g openclaw

# 验证
openclaw --version
# OpenClaw 2026.3.7

5. LaunchAgent 配置(开机自启)

Trojan LaunchAgent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.trojan.client</string>
<key>ProgramArguments</key>
<array>
<string>/Users/mars/trojan/trojan/trojan</string>
<string>-c</string>
<string>/Users/mars/trojan/trojan/client.json</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/trojan.log</string>
<key>StandardErrorPath</key>
<string>/tmp/trojan.log</string>
</dict>
</plist>

OpenClaw Node LaunchAgent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.openclaw.node</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/usr/local/lib/node_modules/openclaw/dist/index.js</string>
<string>node</string>
<string>run</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin</string>
<key>OPENCLAW_GATEWAY_URL</key>
<string>ws://GATEWAY_TAILSCALE_IP:18790</string>
<key>OPENCLAW_GATEWAY_TOKEN</key>
<string>YOUR_GATEWAY_TOKEN</string>
<key>OPENCLAW_ALLOW_INSECURE_PRIVATE_WS</key>
<string>1</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/openclaw-node.log</string>
<key>StandardErrorPath</key>
<string>/tmp/openclaw-node.log</string>
</dict>
</plist>

⚠️ 坑点 3: OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 必须设置,否则 WebSocket 连接需要审批。

⚠️ 坑点 10: 必须设置 PATH 环境变量,否则 Node.js 找不到系统命令。

1
2
3
4
5
6
7
# 放置 LaunchAgent
mv com.trojan.client.plist ~/Library/LaunchAgents/
mv com.openclaw.node.plist ~/Library/LaunchAgents/

# 加载
launchctl load ~/Library/LaunchAgents/com.trojan.client.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.node.plist

6. 节点配对

1
2
3
4
5
# 服务器端检查待配对节点
openclaw devices pending

# 批准配对
openclaw devices approve <node-id>

第三阶段:Codex CLI 配置

1. 安装 Codex

1
2
3
4
5
npm install -g @openai/codex

# 验证
codex --version
# codex-cli 0.114.0

2. OAuth 认证

⚠️ 坑点 6 & 7: 如果代理 IP 被 OpenAI 封锁,OAuth 会失败。

解决方案:在本地网络完成授权(不需要代理)

1
2
# Mac mini 上运行
codex auth login

会输出类似:

1
2
3
Starting local login server on http://localhost:1455.
Open this URL to authenticate:
https://auth.openai.com/oauth/authorize?...

在 Mac mini 的浏览器中打开这个 URL(不需要代理),完成授权后会自动重定向到 localhost:1455,Codex 会自动完成认证。


第四阶段:Gateway 控制节点

1. 验证节点连接

1
2
3
4
5
# 服务器端检查
openclaw nodes status

# 输出
# Mac-mini │ paired · connected

2. 执行命令

⚠️ 坑点 8 & 9:

1
2
3
4
5
6
7
8
9
10
11
12
13
# ❌ 错误方式:使用 --raw
openclaw nodes run --node Mac-mini --raw "hostname"
# Error: shell wrappers like sh/bash/zsh -c require approval

# ✅ 正确方式:直接传命令
openclaw nodes run --node Mac-mini -- hostname
# MarsdeMac-mini.lan

# ✅ 指定工作目录(完整路径)
openclaw nodes run --node Mac-mini --cwd /Users/mars/hewu/01_code -- ls -la

# ✅ 设置环境变量
openclaw nodes run --node Mac-mini --env PATH=/usr/local/bin:$PATH -- codex --version

完整配置清单

服务器端

组件 状态 说明
Tailscale 连接 Mac mini
socat 转发 18790 → 18789
Trojan 服务端 提供代理
OpenClaw Gateway 核心服务

Mac mini 节点

组件 状态 说明
Tailscale brew services 自启
Trojan 客户端 LaunchAgent 自启
HTTP 代理 Python 脚本
OpenClaw Node LaunchAgent 自启
Codex CLI OAuth 认证完成

常见问题排查

1. 节点无法连接

1
2
3
4
5
6
7
8
# 检查 Tailscale
tailscale status

# 检查 socat
lsof -i :18790

# 检查 OpenClaw Node 日志
tail -50 /tmp/openclaw-node.log

2. Codex 认证失败

1
2
3
4
5
# 检查代理
curl -x socks5://127.0.0.1:1080 https://ifconfig.me

# 如果返回 403,说明代理 IP 被封锁
# 解决方案:本地浏览器完成授权

3. 命令执行失败

1
2
3
# 不要用 --raw
# 使用完整路径
# 检查环境变量

参考资料

  1. OpenClaw 官方文档:https://docs.openclaw.ai
  2. Tailscale 文档:https://tailscale.com/kb
  3. Trojan 文档:https://trojan-gfw.github.io/trojan/

总结

关键配置点:

  1. Gateway 绑定 loopback,需要 socat 转发
  2. OpenClaw Node 需要设置 OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1
  3. LaunchAgent 必须设置 PATH 环境变量
  4. Codex OAuth 最好在本地网络完成
  5. openclaw nodes run 不要用 --raw

Mac mini 重启后会自动:

  1. 连接 Tailscale
  2. 启动 Trojan 代理
  3. 连接 OpenClaw Gateway
  4. 可以直接通过 Gateway 控制节点

配置时间:2026-03-15
OpenClaw 版本:2026.3.7
Node.js 版本:v22.22.1


OpenClaw 节点配置完整教程:Mac mini 连接 Gateway 踩坑记录
https://dapalm.com/2026/03/15/2026-03-15-OpenClaw节点配置完整教程-Mac-mini连接Gateway踩坑记录/
作者
Mars
发布于
2026年3月15日
许可协议