在电脑上运行编码代理,再用手机查看进度、继续会话,是 Paseo 很实用的一种使用方式。电脑和手机不在同一网络时,可以让两端主动连接一台中继服务器,由它转发通信。

如果希望自行选择服务器位置、管理连接入口,或者减少对公共中继的依赖,就可以部署自己的 Paseo Relay。本文从单机 Docker 部署开始,逐步加入 HTTPS、客户端配置、会话白名单和运维检查。

本文采用官方 ghcr.io/getpaseo/paseo-relay 镜像,以及“宿主机 Nginx + Docker 中继”的结构。所有域名、会话 ID 和证书路径均为示例,不包含真实部署信息。上游仍在持续更新,部署时应记录实际镜像摘要与 Paseo 版本;本文配置未在读者的服务器上执行验证。

一、先弄清楚:中继器负责什么

可以把连接关系理解为:

手机 Paseo App ── WSS ──┐
                        ├─ Nginx :443 ─ HTTP/WS ─ Relay 127.0.0.1:4000
电脑 Paseo daemon ─ WSS ─┘

中继服务器负责连接和转发,编码代理仍运行在安装 daemon 的电脑上。电脑主动向中继建立连接,因此通常不需要为电脑配置公网端口映射。

Paseo 的中继通信采用端到端加密。中继可以看到 IP、连接时序、数据大小及会话标识等元数据,但不能解密受保护的业务消息。TLS 则保护设备到入口服务器这一段传输;两者作用不同,公网部署仍应使用 WSS。这里的加密边界也不代表编码代理不会按自身配置向模型服务发送请求。Paseo 安全说明

二、准备服务器、域名和证书

开始前准备好:

  • 一台电脑和手机都能访问的 Linux 服务器,安装 Docker、Docker Compose 与 Nginx。
  • 一个专用域名,例如 relay.example.com,DNS 指向服务器;如果设置了 AAAA 记录,也要保证 IPv6 链路可用。
  • 覆盖该域名且受设备信任的 TLS 证书、完整证书链及私钥。
  • 运行 Paseo daemon 的电脑,以及手机上的 Paseo App。

公网业务入口只需要 TCP 443。本文也使用 80 做 HTTP 跳转;若证书续期依赖 HTTP-01,还需要按证书工具要求保留验证路径。SSH 管理入口另行限制来源,中继端口 4000 不对公网开放。

注意部署位置:以下 Nginx 运行在宿主机上。如果 Nginx 也在容器里,127.0.0.1 指向的是它自己的容器,需改用容器网络和服务名。

三、先启动一个只允许本机访问的 Relay

在服务器上创建部署目录:

mkdir -p ~/paseo-relay
cd ~/paseo-relay

新建 compose.yaml:

services:
  relay:
    image: ghcr.io/getpaseo/paseo-relay:latest
    container_name: paseo-relay
    restart: unless-stopped
    ports:
      - "127.0.0.1:4000:4000"
    environment:
      PASEO_RELAY_HOST: "0.0.0.0"
      PASEO_RELAY_PORT: "4000"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

这里有两个不同的监听范围:容器里的服务监听 0.0.0.0:4000,Docker 在宿主机只发布 127.0.0.1:4000。前者保证端口转发能到达服务,后者避免公网绕过 Nginx。官方镜像定义

启动并检查:

docker compose up -d
docker compose ps
docker compose logs --tail=100 relay
curl -i http://127.0.0.1:4000/health
curl -i http://127.0.0.1:4000/ready

/health 用来检查进程存活,/ready 用来判断当前是否接受新连接。存活检查成功,并不能证明手机和 daemon 已经成功通信。

示例用 latest 便于首次拉取。正式使用前,执行 docker image inspect ghcr.io/getpaseo/paseo-relay:latest --format '{{json .RepoDigests}}',记录实际摘要,再把 image 改成 ghcr.io/getpaseo/paseo-relay@sha256:实际摘要。这样以后重建容器时,版本仍然可确定。官方运行与镜像说明

四、用 Nginx 提供 HTTPS 和 WebSocket 入口

下面是一份专用站点配置,可以保存为 /etc/nginx/conf.d/paseo-relay.conf。前提是主配置在 http {} 内包含该目录;如果已经定义过 $connection_upgrade,复用现有定义即可。

先准备好证书,再替换域名和证书路径:

# 以下内容位于 http 上下文,不要再包一层 http {}。
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

# 不记录查询参数,减少会话标识进入访问日志的机会。
log_format relay_min '$remote_addr [$time_local] $request_method $uri '
                     '$status $body_bytes_sent $request_time';

server {
    listen 80;
    server_name relay.example.com;
    return 301 https://relay.example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name relay.example.com;
    server_tokens off;

    ssl_certificate /etc/nginx/ssl/relay.example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/relay.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    access_log /var/log/nginx/paseo-relay.access.log relay_min;
    error_log /var/log/nginx/paseo-relay.error.log warn;

    # 运维探针和指标仅通过服务器本机入口访问。
    location = /health { return 404; }
    location = /ready { return 404; }
    location = /metrics { return 404; }

    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;

        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
        proxy_pass http://127.0.0.1:4000;
    }
}

这里显式转发 WebSocket 升级头,并使用 HTTP/1.1 连接后端。proxy_pass 没有追加路径,保留请求原有路径和查询参数,避免破坏 Relay 路由。长超时用于容纳空闲连接,但不能保证连接永不断开,客户端仍需要正常重连。Nginx WebSocket 代理说明

此配置假定 Nginx 是直接面向公网的第一层代理,因此重设了转发来源。如果前面还有负载均衡,应只信任明确配置的代理来源,再调整真实 IP 处理。

检查语法并重载:

sudo nginx -t
sudo systemctl reload nginx

只有语法检查通过后才执行重载。不要直接覆盖整份 nginx.conf,以免影响同一台服务器上的其他站点。

到这里,443 已经提供 TLS 入口。暂时还没有接入白名单,应接着完成后续限制,避免长期作为开放中继运行。

五、配置电脑上的 Paseo daemon

这一步在运行 daemon 的电脑上操作,使用平时运行 Paseo 的同一系统账号。默认配置文件为 ~/.paseo/config.json;自定义过 PASEO_HOME 或 --home 时,要使用对应目录。Windows 若实际运行在 WSL 中,也应在对应 WSL 环境内操作。

1. 备份后合并配置

macOS 终端:

cp ~/.paseo/config.json ~/.paseo/config.json.before-private-relay.bak
open -e ~/.paseo/config.json

Windows PowerShell:

Copy-Item "$env:USERPROFILE\.paseo\config.json" "$env:USERPROFILE\.paseo\config.json.before-private-relay.bak"
notepad "$env:USERPROFILE\.paseo\config.json"

如果已有同名备份,请更换文件名。首次使用且配置文件不存在时,先正常启动一次 Paseo。

将以下字段合并进现有配置,保留其他设置:

{
  "version": 1,
  "daemon": {
    "relay": {
      "enabled": true,
      "endpoint": "relay.example.com:443",
      "publicEndpoint": "relay.example.com:443",
      "useTls": true,
      "publicUseTls": true
    }
  }
}

endpoint 是 daemon 连接的地址,publicEndpoint 是向客户端提供的地址。本例两端都使用同一个公网域名,TLS 也都启用。地址使用 主机名:端口,不要附加 https:// 或 /ws。已有 daemon、relay 对象时修改原字段,避免重复键;JSON 不支持注释和尾部逗号。

2. 按需要设置配对链接的基础地址

原接入方案还配置了:

{
  "app": {
    "baseUrl": "https://relay.example.com"
  }
}

该字段决定生成的配对链接使用哪个基础地址,和实际中继地址是两回事。若沿用原方案,让手机 Paseo App 扫码或粘贴完整配对链接,可以合并这段配置,并验证当前 App 能识别。

但 Relay 镜像不提供浏览器配对页面,设置 baseUrl 不会自动部署网页。若需要点击链接直接打开网页,应将它设为实际部署了兼容配对前端的 HTTPS 地址;没有自建前端时,可以保留现有可用值。是否修改 baseUrl,并不改变 daemon.relay 指定的中继目的地。

3. 重启 daemon

paseo daemon restart
paseo daemon status

若实例尚未运行,执行 paseo daemon start。由 Paseo Desktop 管理的实例,也可通过桌面设置中的对应主机重启入口操作,避免误操作另一套实例。

中继地址和 TLS 设置需要重启才能生效。前台运行、Docker 或直接由进程管理器启动的部署,还应检查启动环境变量和遗留参数是否覆盖了文件配置。Paseo 配置说明

六、加入 serverId 白名单,限制中继使用范围

对个人或小团队,可以在 Nginx 层仅放行登记过的 serverId。先从每台运行 daemon 的电脑读取实际 ID。

macOS / Linux:

cat ~/.paseo/server-id

Windows PowerShell:

Get-Content "$env:USERPROFILE\.paseo\server-id"

不要删除或随意修改这个文件,也不要为了登记设备而发送整个配置目录、密钥文件或二维码。目录不存在时,先确认使用的系统账号和 PASEO_HOME 是否正确。

在前面 Nginx 配置的 http 上下文新增:

map $arg_serverId $paseo_server_allowed {
    default 0;
    ~^srv_REPLACE_WITH_YOUR_ID$ 1;
    # 更多设备各写一行,使用各自完整 ID。
}

将示例 ID 替换为实际值;使用 ~^...$ 做区分大小写的完整匹配。若 ID 含正则特殊字符,需要转义。

然后在中继站点的 location / 内、代理指令之前加入:

if ($paseo_server_allowed = 0) {
    return 403;
}

再次执行 sudo nginx -t,通过后重载。没有 serverId 或 ID 不在名单里的业务请求会被拒绝;运维检查继续访问服务器本机 127.0.0.1:4000。

白名单可以减少陌生会话使用这台中继,但 serverId 是客户端可提供的路由标识,知道它的人仍可尝试连接对应路由。它不是密码,也不是完整的身份认证机制,更不能替代端到端加密与 daemon 自身的访问控制。更新白名单主要影响后续握手,已经建立的 WebSocket 不会因为配置重载而立即断开。

七、重新配对,并确认真正走了新中继

配置生效且 ID 已放行后,在 daemon 所在电脑执行:

paseo daemon pair --relay

用手机 Paseo App 扫描新二维码,或粘贴本次生成的完整配对链接。旧二维码可能仍携带原来的连接信息,修改配置后应重新生成。

建议按这个顺序验收:

  1. 手机切换到蜂窝网络,确认可以访问中继入口。
  2. 在 App 中选择刚配对的 Relay 连接,检查其中的中继地址。
  3. 打开主机会话,发送一条无敏感内容的测试消息,并确认响应。
  4. 查看中继运行状态及连接记录,确认测试时存在对应连接,避免实际走的是已保存的直连或 VPN。
  5. 将手机放到后台再返回,观察能否恢复连接。

二维码和完整链接应视为敏感连接资料,不要放进公开文章、群聊截图或问题反馈中。手机端成功完成一次真实会话,比“容器在运行”更能说明部署可用。

八、进一步加固:保护入口,也保护 daemon

缩小网络暴露范围

保持 Docker 的回环地址映射,不额外发布 4000,也不要把电脑的 daemon 管理端口映射到公网。安全组和主机防火墙应覆盖 IPv4、IPv6,最终从外部网络检查实际可达端口。

如果需要更严格的中继访问限制,可将入口放进 VPN,或使用设备实际支持的身份验证方案。不要直接在 Relay 前增加网页登录、验证码或 Basic Auth 后就假定客户端兼容;原生 App 和 daemon 必须能够完成相应认证流程。

给 daemon 增加访问密码

端到端加密保护传输内容,daemon 的访问密码则提供额外的接入控制。可在 daemon 所在电脑使用交互式命令设置,随后重启:

paseo daemon set-password
paseo daemon restart

配对后按客户端提示认证,并用当前客户端版本验证完整连接。密码不要写进教程、终端演示命令或公开配置示例。

控制日志和配置的可见范围

示例访问日志使用 $uri,避开包含查询参数的 $request_uri 和完整 $request,减少 serverId、connectionId 被长期保存的机会。但这并不意味着所有日志都完成脱敏:Nginx 错误日志、上游代理日志和 Relay 日志也应检查,并限制权限与保留时间。

证书私钥、daemon 密钥和完整配对链接不要进入公开代码仓库。公开排障时只保留必要状态码、时间范围和脱敏配置。

九、日常运维与常见问题

运维时至少观察容器是否反复重启、证书有效期、磁盘日志占用,以及 /health 和 /ready。需要指标时,从本机或受保护的监控网络采集 /metrics,不要为了方便直接公开。

现象 优先检查
Nginx 返回 502 容器是否启动、本机 4000 是否可访问、Nginx 是否也在容器中
握手返回 403 实际 serverId 是否完整匹配、配置是否已重载、是否操作了另一套 Paseo 目录
HTTPS 证书错误 域名、完整证书链、有效期、设备时间;保留证书校验
连接空闲后断开 Nginx、CDN、负载均衡各层的空闲超时,以及客户端重连行为
仍然连接旧中继 daemon 是否重启、配对信息是否重新生成、是否存在启动覆盖参数
浏览器打开链接 404 该地址是否只有 Relay、是否实际部署了兼容的网页配对前端
Windows 找不到文件 daemon 在 Windows 还是 WSL、运行账号及 PASEO_HOME 是否一致

升级前保留当前 Compose 文件和镜像摘要;备份 Nginx 站点配置时,不要将私钥混入公开备份。更新镜像后,重新检查本机探针、TLS、白名单和手机会话。重建中继容器会中断现有连接,应安排可接受的维护时间。

单机方案适合先把连接和安全边界做好。后续需要多实例高可用时,还要处理官方 Relay 的会话归属和升级路由,不能仅把多个容器放到普通轮询负载均衡后就认为完成扩容。

完成部署后,检查以下结果:4000 仅本机可访问,公网入口使用可信 TLS,未登记 ID 无法建立中继连接,手机可以通过新 Relay 完成会话,日志与发布材料不含真实连接凭据。这样,这台中继才具备继续维护和使用的基础。