GoForum🌐 V2EX

使用 Neko 搭建 ChatGPT 拼车共享浏览器

mirror · 2026-07-20 17:18 · 0 次点赞 · 0 条回复

image.png

  • 之前开了 GPT Pro 共享车,需要把已经登录的 Web 端共享给车友。直接提供账密码或者分发浏览器资料(比如指纹浏览器),账号凭证和登录状态都不容易控制。

  • 后来我改成用 Neko 共享一台已经登录 ChatGPT 的 Chromium 。车友只进入 Neko 房间,不直接接触账号密码;房间口令、控制权和浏览器可访问的网站可以分别限制。下面记录完整的手动部署过程。

网络结构

先总览一下网络拓扑,帮助大家理解 Neko + 共享浏览器的网络链路:

image.png

  • Neko 站点的 HTTPS 、登录接口和 WebSocket 经过 443 ,再由 Nginx 转发到 Neko 的 8080 。

  • Neko 页面中浏览器画面和音频通过 WebRTC 传输,本文开放 UDP 52000–52100 ,并保留 TCP 52101 作为回退。

  • ChatGPT 账号网络:Chromium 访问网站时使用容器自己的出站网络。给浏览器增加代理,不会替代 WebRTC 的入站端口。

域名页面能打开,只能证明 443 和 8080 正常,不能证明 WebRTC 已经连通。Neko WebRTC 文档 也明确要求媒体端口直接可达,或者通过 TURN 中继。(部署时就踩了这个坑)

Docker Compose 部署

准备一台带公网 IP 的 VPS 、一个已解析到该 IP 的域名,以及 Docker Engine 和 Compose 插件。新建目录后写入 compose.yaml

services:
  neko:
    image: ghcr.io/m1k1o/neko/chromium:latest
    container_name: neko
    restart: unless-stopped
    shm_size: "2gb"
    ports:
      - "127.0.0.1:8080:8080"
      - "52000-52100:52000-52100/udp"
      - "52101:52101/tcp"
    environment:
      NEKO_MEMBER_PROVIDER: "multiuser"
      NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "${NEKO_USER_PASSWORD:?required}"
      NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "${NEKO_ADMIN_PASSWORD:?required}"

      NEKO_SERVER_BIND: "0.0.0.0:8080"
      NEKO_SERVER_PROXY: "true"
      NEKO_DESKTOP_SCREEN: "1920x1080@30"

      NEKO_SESSION_IMPLICIT_HOSTING: "false"
      NEKO_SESSION_CONTROL_PROTECTION: "true"
      NEKO_FILETRANSFER_ENABLED: "false"
      NEKO_DESKTOP_UPLOAD_DROP: "false"

      NEKO_WEBRTC_EPR: "52000-52100"
      NEKO_WEBRTC_NAT1TO1: "${NEKO_PUBLIC_IP:?required}"
      NEKO_WEBRTC_ICELITE: "true"
      NEKO_WEBRTC_TCPMUX: "52101"

同目录创建 .env

NEKO_PUBLIC_IP=203.0.113.10
NEKO_USER_PASSWORD=replace-with-a-long-random-value
NEKO_ADMIN_PASSWORD=replace-with-another-long-random-value

普通用户和管理员使用不同口令。当前配置关闭了点击画面自动取得控制权,并要求管理员在房间内时普通用户才能取得控制权;如果需要无人值守的远程控制,应按使用场景调整这两个选项。

.env 权限收紧,并在启动前检查 Compose 展开结果:

chmod 600 .env
docker compose config --quiet
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8080/health

NEKO_SERVER_BIND=0.0.0.0:8080 让 Docker 能访问容器内服务;宿主机的端口映射仍限定在 127.0.0.1,外部访问只能经过反向代理。NEKO_SERVER_PROXY=true 用于信任反向代理传入的客户端地址头,不能在 Neko 直接暴露公网时开启。完整变量说明可在官方配置页核对。

官方示例使用 latest。完成测试后可以固定到验证过的镜像版本或摘要,避免重新拉取镜像时引入未验证变更。

反向代理和防火墙

Nginx 配置需要保留 WebSocket Upgrade 头:

server {
    listen 443 ssl http2;
    server_name neko.example.com;

    ssl_certificate     /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

修改后执行 nginx -t,确认无误再 reload 。Neko 会定期发送 WebSocket 心跳,代理超时时间不能短于会话心跳周期。官方反向代理示例给出了相同的 Upgrade 配置。

需要开放的端口如下:

端口 协议 用途
443 TCP HTTPS 、登录接口和 WebSocket
80 TCP 可选;用于 ACME HTTP-01 签发或跳转 HTTPS
52000–52100 UDP WebRTC 媒体端口,必须与 NEKO_WEBRTC_EPR 完全一致
52101 TCP 可选的 WebRTC TCP mux 回退

不要把 8080 开放到公网。云防火墙和系统防火墙都要检查;只配置其中一层仍可能导致媒体连接超时。

关键配置

1.持久化 Chromium 资料

默认情况下,重建容器会丢失 Chromium 的 Cookie 、扩展和设置,为了避免每次重启容器需要重新登录 chatgpt 账号。需要保留资料时增加卷挂载:

    volumes:
      - ./chromium-data:/home/neko/.config/chromium

挂载后先检查目录属主。浏览器无法启动、只有黑屏时,可以在容器内确认目录是否属于 neko 用户:

docker exec -it neko ls -la /home/neko/.config/chromium
docker exec -it neko chown -R neko:neko /home/neko/.config/chromium

持久化目录会同时保存网站登录态。允许多人进入同一个房间时,应把整个 profile 视为共享数据,并单独决定备份和销毁方式。

把 WebRTC 收敛到单端口

如果不想开放一段 UDP 端口,可以改用 UDP/TCP mux 。删除 NEKO_WEBRTC_EPR 及其端口映射,改成:

    ports:
      - "127.0.0.1:8080:8080"
      - "52000:52000/udp"
      - "52000:52000/tcp"
    environment:
      NEKO_WEBRTC_UDPMUX: "52000"
      NEKO_WEBRTC_TCPMUX: "52000"

UDP 延迟通常更低,TCP 适合作为受限网络中的回退。端口不能在 Docker 层改映射,例如不能把宿主机 52000 转到容器 59000 。

2.单独设计浏览器出站

  • 为了降低 WebRTC 延迟,可以把 Neko 部署在离用户较近的服务器;如果服务器无法直接访问 ChatGPT ,再单独为 Chromium 配置出站代理。

  • Neko v3 没有用于设置 Chromium 代理的环境变量。当前 Chromium 镜像会读取 /etc/chromium/policies/managed/ 下的浏览器策略,因此可以新建 chromium-proxy.json

{
  "ProxySettings": {
    "ProxyMode": "fixed_servers",
    "ProxyServer": "socks5://proxy.example.com:1080",
    "ProxyBypassList": "localhost,127.0.0.1"
  }
}

HTTP 代理可以把 ProxyServer 改成 http://proxy.example.com:3128。先检查 JSON ,再把文件挂载到 Chromium 的 managed policy 目录:

jq empty chromium-proxy.json
    volumes:
      - ./chromium-proxy.json:/etc/chromium/policies/managed/20-proxy.json:ro

如果前面已经配置了 Chromium 资料持久化,把两个挂载项放在同一个 volumes 列表中。重新创建容器使策略生效:

docker compose up -d --force-recreate

先从容器测试代理是否可达。下面以 SOCKS5 为例,HTTP 代理将参数改为 --proxy http://proxy.example.com:3128

docker exec neko curl -fsS --proxy socks5h://proxy.example.com:1080 https://api.ipify.org
  • 最后在 Neko 的 Chromium 中打开 https://api.ipify.org。浏览器显示代理出口 IP ,说明 ProxySettings 已经生效;

  • docker exec neko curl -fsS https://api.ipify.org 仍会显示服务器自己的出口 IP ,因为这份策略只作用于 Chromium ,不会改变 Neko 容器的出口 IP 。

  • 示例没有加入 direct:// 回退:代理断开时 Chromium 会直接报错,不会改用服务器出口。Chromium 也不会读取写在代理 URL 中的用户名和密码;需要认证时,优先让上游代理按服务器 IP 放行,或者增加一个只在 Docker 网络内监听的本地转发代理。

  • HTTP/SOCKS5 只能代理 Chromium 的 HTTP 、HTTPS 和 WebSocket 请求,但不能转发 UDP 。如果需要让语音等 UDP 流量走代理,应改用 VPN 或网关容器;使用 network_mode: service:<gateway> 后,Neko 的 8080 和 WebRTC 端口也要改由网关容器发布。Chromium 代理文档列出了代理协议、WebSocket 选择顺序和认证限制。

3.限制用户使用共享浏览器的访问地址

Neko 的 Chromium 镜像已经内置了一份浏览器策略,其中包括禁用开发者工具、下载和访客模式等限制。为了保留这些默认项,先从正在运行的容器复制策略文件,只修改其中的 URLBlocklistURLAllowlist

docker cp neko:/etc/chromium/policies/managed/policies.json ./chromium-policies.json

jq 只替换这两个字段,输出一份新的策略文件:

jq '
  .URLBlocklist = ["*", "file://*"] |
  .URLAllowlist = [
    "chatgpt.com",
    "chat.openai.com",
    ".auth.openai.com",
    ".auth0.openai.com",
    ".setup.auth.openai.com",
    "oaistatic.com",
    "oaiusercontent.com",
    "oaistatsig.com",
    ".cdn.openaimerge.com",
    ".challenges.cloudflare.com",
    ".cdn.workos.com",
    ".forwarder.workos.com",
    ".setup.workos.com",
    ".images.workoscdn.com",
    ".workos.imgix.net",
    "chrome://policy"
  ]
' chromium-policies.json > chromium-policies-restricted.json

Chromium 的策略语法中,chatgpt.com 会同时匹配它的子域名;以点开头的 .auth.openai.com 只匹配这个主机名。上面的列表用于 ChatGPT Web 、登录、静态资源和文件访问,域名取自 OpenAI 当前的网络配置建议。语音、付款或第三方登录需要使用时,再从官方列表加入对应域名。

先检查 JSON 格式,然后把文件挂载回原路径:

jq empty chromium-policies-restricted.json
    volumes:
      - ./chromium-data:/home/neko/.config/chromium
      - ./chromium-policies-restricted.json:/etc/chromium/policies/managed/policies.json:ro

如果不需要持久化 Chromium 资料,删除第一行卷挂载即可。重新创建容器后,在 Chromium 中打开 chrome://policy,点击 Reload policies (重新加载策略),确认 URLBlocklistURLAllowlist 的状态为 OK

docker compose up -d --force-recreate

最后分别打开 https://chatgpt.com 和一个未放行的网站,确认前者可用、后者显示被管理员阻止。验证完成后可以从白名单中删除 chrome://policy,再重新创建容器。

URLBlocklist 限制的是 Chromium 中的地址访问,不是容器级防火墙;chatgpt.com 内部的会话、设置等功能也仍在放行范围内。需要限制容器内其他进程的出站连接时,还要在出口代理或防火墙上单独配置白名单。

排障

现象 检查 处理
域名无法打开 curl http://127.0.0.1:8080/health 、Nginx 错误日志 先确认容器健康,再检查反代目标、证书和 443
登录页正常,画面超时 EPR 、Docker UDP 映射、两层防火墙、nat_ips 日志 让端口范围和协议完全一致;修正 NEKO_WEBRTC_NAT1TO1
有光标但 Chromium 黑屏 shm_size 、profile 路径和属主 保持至少 2 GB /dev/shm ;修复或暂时移除持久化目录
外网正常,内网无法连接 路由器是否支持 NAT loopback 使用公网地址回环、VPN 或 TURN
Chromium 没有网络 先访问 https://1.1.1.1 ,再检查 DNS 和 Docker 网段 能访问 IP 但不能访问域名时修 DNS ;同时排除 Docker 子网冲突

服务端可以先看 Neko 识别到的公网地址:

docker compose logs neko | grep nat_ips

客户端使用 Chromium 时打开 chrome://webrtc-internals。如果 candidate 中只有不可达的内网地址,继续检查 NAT1TO1 、端口映射或 TURN ,不必反复修改 Nginx 。Neko Troubleshooting 也采用这个排查顺序。

0 条回复
添加回复
你还需要 登录 后发表回复

登录后可发帖和回复

登录 注册
主题信息
作者: mirror
发布: 2026-07-20
点赞: 0
回复: 0