mirror

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

  •  
  •   mirror · 1 day ago · 703 views

    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 也采用这个排查顺序。

    No Comments Yet
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3209 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 97ms · UTC 13:52 · PVG 21:52 · LAX 06:52 · JFK 09:52
    ♥ Do have faith in what you're doing.