> 内容来源：Onevium 官方文档
> 文章: 远端网关：Docker、HTTPS 与私有管理
> 原文: https://onevium.com/zh/docs/developers/remote-gateway
> 语言：简体中文
> 更新于: 2026-09-09
> 适用版本: 1.1.23+

---

# 远端网关：Docker、HTTPS 与私有管理

从匹配部署包构建网关，配置持久目录、HTTPS、SSH 配对及重启与回滚检查。

## 什么情况下需要远端网关

需要电脑离线时仍接收业务事件、需要固定 HTTPS 地址时，可以将网关部署到自己的服务器。助手仍在指定 Onevium 设备执行；网关不会把离线电脑变成在线执行器。离线任务只在允许期限内排队。

界面截图使用隔离演示数据，令牌为空、草稿未保存等状态均按图注说明。部署后请完成下方连接检查。

## 前提：先取得匹配部署包

继续前应具备：

- 与桌面版本匹配的**完整部署源码包**，包含 `server/gateway/Dockerfile`、`compose.example.yml` 及 Dockerfile 引用的协议和 workers 文件。
- 可用的 Docker Engine 与 Compose v2、服务器 SSH 权限、域名和有效 TLS 证书。
- 专用持久目录，以及有该目录权限的服务器账号。
- 可用的 Onevium 安装和模型连接。

没有部署包时先向维护者获取。本文不提供未经确认的公共镜像，也不要求普通用户 clone 私有仓库。下文镜像名只是**在你服务器上构建的本地标签**。

所有 Docker 命令在服务器的**部署包根目录**运行；SSH 转发命令则在运行 Onevium 的电脑执行。

**地址只填 origin：** 网关设置、`ONEVIUM_GATEWAY_PUBLIC_URL`，以及 API 示例的 `GATEWAY_URL` 都只含协议、主机和可选端口。若界面“API 地址”为 `https://gateway.example.com/api/v1`，这些值应填 `https://gateway.example.com`，去掉末尾 `/api/v1`。私有管理地址也只填 `http://127.0.0.1:8430`，不追加管理路径。

## 第一步：保存远端模式并导出设备公钥

在 Onevium 打开「渠道 → 外部接入 → 外部接入设置 → 连接」：

1. 「网关位置」选「远端网关」。
2. 「网关地址」填计划使用的 `https://gateway.example.com`，不追加 `/api/v1`。
3. 展开「远端高级设置」，「管理连接」选「通过 SSH 私有连接」；私有管理地址可先填 `http://127.0.0.1:8430`，令牌暂不填。
4. 先保存。切换连接方式会暂停外部接入；保存后才可点击「导出设备公钥」。
5. 导出 `onevium-device-public.json`，通过已核验的 SSH 连接上传到服务器。

![输入远端网关的 HTTPS 地址；切换连接方式在保存后生效。](https://onevium.com/docs/external-access/3cc390708/zh/16-remote-gateway.png "输入远端网关的 HTTPS 地址；切换连接方式在保存后生效。")

文件包含 `owner_id`、`device_id` 和 `public_key`，不含私钥。不要另外生成私钥来替代桌面的执行身份。导出不表示已经配对、开启监听或发布服务。

## 第二步：构建本地镜像

在匹配部署包根目录运行：

```bash
docker build -f server/gateway/Dockerfile \
  -t onevium-gateway:preview-c2409f75f .
```

该 Dockerfile 使用 Node 24.15.0，镜像内安装并构建所需依赖。无需在日常 Onevium 安装目录执行 native rebuild。构建成功只得到镜像，不代表服务已启动。

准备一个**新的专用数据目录**。使用之后建立 SSH 转发的服务器账号核对 UID/GID：

```bash
id -u
id -g
```

下面示例把数据放在 `/srv/onevium-gateway`；确认它不是别的服务目录，再按本机权限创建：

```bash
sudo install -d -m 700 -o "$(id -u)" -g "$(id -g)" /srv/onevium-gateway
```

已有部署不要重新初始化或更换归属。SQLite 存储应使用支持本机文件锁的磁盘／块存储，不当作多主机共享数据库。

## 第三步：配置 Compose 与环境变量

在部署包根目录创建 `gateway.env`。将 UID/GID 换成上一步输出，将域名和路径换成实际值：

```dotenv
GATEWAY_UID=1000
GATEWAY_GID=1000
ONEVIUM_GATEWAY_IMAGE=onevium-gateway:preview-c2409f75f
ONEVIUM_GATEWAY_DATA_PATH=/srv/onevium-gateway
ONEVIUM_GATEWAY_PUBLIC_URL=https://gateway.example.com
ONEVIUM_GATEWAY_ENABLED=1
ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0
ONEVIUM_GATEWAY_CALLBACK_HOSTS=
```

| 变量                                     | 作用                                |
| -------------------------------------- | --------------------------------- |
| `GATEWAY_UID/GID`                      | 容器进程与 SSH 管理账号使用匹配文件权限            |
| `ONEVIUM_GATEWAY_DATA_PATH`            | 挂到容器 `/data` 的持久目录                |
| `ONEVIUM_GATEWAY_PUBLIC_URL`           | 公网 HTTPS origin；也是公开请求的 Host 校验依据 |
| `ONEVIUM_GATEWAY_ENABLED=1`            | 显式启动服务器监听                         |
| `ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0` | 初次配置期间拒绝新任务，保留管理与已有查询通道           |
| `ONEVIUM_GATEWAY_CALLBACK_HOSTS`       | 逗号分隔的精确回调域名；空值拒绝全部回调              |

部署包的 `compose.example.yml` 将容器 `0.0.0.0:8420` 映射为**宿主 `127.0.0.1:8420`**。不要改成向公网直接开放 8420。

基础 Compose 没有把接纳开关和回调名单传入容器。再创建 `gateway.override.yml`：

```yaml
services:
  gateway:
    image: "${ONEVIUM_GATEWAY_IMAGE:?Set the local image tag}"
    environment:
      ONEVIUM_GATEWAY_ENABLED: "${ONEVIUM_GATEWAY_ENABLED:-1}"
      ONEVIUM_GATEWAY_ACCEPTING_REQUESTS: "${ONEVIUM_GATEWAY_ACCEPTING_REQUESTS:-0}"
      ONEVIUM_GATEWAY_CALLBACK_HOSTS: "${ONEVIUM_GATEWAY_CALLBACK_HOSTS:-}"
```

这一步不可省略；只在 `gateway.env` 中增加变量不会自动让未引用的变量进入容器。先验证合并配置：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml config --quiet
```

## 第四步：初始化身份并启动暂停接纳的网关

把挂载参数中的公钥文件换成服务器上真实绝对路径，再执行：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml run --rm --no-deps --pull never \
  -v /srv/onevium-device-public.json:/device-public.json:ro \
  gateway init --identity-file /device-public.json
```

预期看到 `Gateway identity initialized. No listener started.`。初始化只写一次身份配置；如果提示文件已存在，先确认是否是已有部署，不要删除配置强行重试。[Compose run](https://docs.docker.com/reference/cli/docker/compose/run/)在这里运行一次性初始化命令，不发布服务端口。

然后启动：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml up -d --no-build --pull never gateway
```

检查私有管理与日志：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml exec -T gateway node dist/cli.cjs manage --path state
```

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml logs --tail 50 gateway
```

预期管理命令返回状态 JSON，启动日志包含 `status: listening`、`public_management: false`。这是应检查的结果，不是本文代你完成的实测。

## 第五步：配置公网 HTTPS 反向代理

下面示例假定 Nginx 已安装并运行，代理与网关在同一服务器。将此 server 块加入你的站点配置，并替换域名与有效证书路径：

```nginx
server {
    listen 443 ssl;
    server_name gateway.example.com;
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    client_max_body_size 20m;

    location / {
        proxy_pass http://127.0.0.1:8420;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
}
```

先检查语法，成功后再加载；检查失败时先修复，不执行 reload：

```bash
sudo nginx -t
sudo nginx -s reload
```

必须保留公网 Host、传递 WebSocket 升级头，并关闭代理缓冲以供 SSE 使用。[Nginx 官方 WebSocket 说明](https://nginx.org/en/docs/http/websocket.html)解释了升级头为什么需要显式转发。

这是 **Docker 远端网关**配置；不要套用“内置网关把上游 Host 改为 loopback”的规则。更不能反代 Onevium 的原网页／管理端口。

从有权访问的客户端检查：

```bash
curl -sS -o /dev/null -w '%{http_code}\n' \
  https://gateway.example.com/api/v1/management/state
```

预期为 404。公网不开放管理接口；浏览器脚本带 Origin 的直接业务请求也会被拒绝。业务访问应来自你的后端。

## 第六步：建立 SSH 私有管理并配对

管理 socket 在容器 `/data/control/gateway.sock`，对应宿主 `/srv/onevium-gateway/control/gateway.sock`。目录权限为 700，socket 和控制令牌为 600。

在服务器受信任终端取得控制令牌：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml exec -T gateway node dist/cli.cjs management-token
```

输出是敏感的**私有管理令牌**，只粘贴到 Onevium 对应密码字段，不写入 URL、代码或日志截图。

在 Onevium 所在电脑开启转发，并保持此终端连接：

```bash
ssh -o ExitOnForwardFailure=yes -N \
  -L 127.0.0.1:8430:/srv/onevium-gateway/control/gateway.sock \
  gateway-user@YOUR_SERVER
```

使用已核验的 SSH 主机和密钥，不关闭主机校验。SSH 用户必须有宿主 socket 权限。`-L` 的本地地址明确绑定 loopback；[OpenSSH 手册](https://man.openbsd.org/ssh#L)说明了本地端口到远端 Unix socket 的转发形式。

返回 Onevium 远端高级设置，核对：

| 字段     | 本例值                           |
| ------ | ----------------------------- |
| 网关地址   | `https://gateway.example.com` |
| 管理连接   | 通过 SSH 私有连接                   |
| 私有管理地址 | `http://127.0.0.1:8430`       |
| 私有管理令牌 | 上一步取得的 control-token          |

![私有管理字段近景：填写地址与令牌，保存后再配对。图中令牌为空，草稿尚未保存。](https://onevium.com/docs/external-access/3cc390708/zh/17-private-management.png "私有管理字段近景：填写地址与令牌，保存后再配对。图中令牌为空，草稿尚未保存。")

保存后点击「配对当前设备」。预期提示设备已配对；若失败，先查 SSH 与私有管理，不要把管理地址改成公网 `/management`。仅有公网 URL 不足以管理自托管网关。

## 第七步：发布服务、允许接纳并做一次真实调用

1. 在远端模式下创建或选择应用，配置助手与项目能力。
2. 运行能力检查，通过后点「发布服务」。流程见[外部接入](https://onevium.com/zh/docs/developers/external-access)。
3. 把服务器 `gateway.env` 的 `ONEVIUM_GATEWAY_ACCEPTING_REQUESTS` 改为 `1`，重新执行上面的 `up -d --no-build --pull never gateway` 命令，使环境变更进入容器。
4. 在 Onevium 应用页面点「启用外部接入」，确认连接状态。
5. 用该应用的密钥和已认证主体提交一个只回复测试文字的请求，保存回执，再查询实际 Run 结果。

**看到 202、容器 running、设备 paired 都不能单独证明闭环完成。** 应看到同一 `run_id` 从接纳走到真实终态，并在后端取得正确结果。API 和 SSE 示例见[会话](https://onevium.com/zh/docs/developers/conversations)，凭据范围见[身份认证](https://onevium.com/zh/docs/developers/authentication)。

需要结果回调时，把精确域名加入服务器 `ONEVIUM_GATEWAY_CALLBACK_HOSTS`，重新应用 Compose 配置，再配置回调。它只接受公网 HTTPS/443，空名单、内网或 localhost 不会放行。详见[Webhook 与回调](https://onevium.com/zh/docs/developers/webhooks)。

## 重启后验证什么

先停止测试发送方，并等已有任务到终态或完成必要核对，再重启网关：

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml restart gateway
```

`restart` 用于同一配置的重启；修改 env 或镜像后使用本教程的 `up` 命令重新创建容器。Compose 会保留挂载目录，见[官方 up 说明](https://docs.docker.com/reference/cli/docker/compose/up/)。

检查四件事：

- 私有管理仍可读取，应用和设备身份未变。
- 原应用密钥仍可查询旧 Run 和会话。
- 已完成附件仍能下载，内容校验一致。
- Onevium 恢复连接后，没有把“已开始但结果未知”的工作当新任务重跑。

未知结果可能处于 `reconciling`、`pending_sync` 等状态，需要实际确认。服务器在线只能接纳并限期排队，不能让休眠电脑执行任务。

## 暂停、备份与回滚

1. 暂停业务发送方，检查当前 Run；确认终态或记录待核对项。
2. 将 `ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0` 后重新应用 Compose，验证新任务返回 503、旧结果仍可查询。
3. 在 Onevium 暂停外部接入。需要一致备份时停止网关，再复制**完整持久目录**到一个新的受限备份位置。

```bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml stop gateway
```

备份应包含身份配置、数据库及相关文件、私有控制凭据和附件。不要仅复制运行中的单个 SQLite 文件，不要用 `down -v` 或删除 `/data` 作为回滚步骤。

回退镜像前先确认它与当前数据格式兼容。不能确认时保持暂停，使用维护者提供的兼容版本或匹配快照。恢复旧快照可能遗漏之后已发生的执行与回调，必须核对，不能自动重放业务副作用。恢复后先保持接纳为 0，检查身份、旧数据与连接，再允许新请求。

## 常见失败与定位

| 现象            | 先查哪里                                              |
| ------------- | ------------------------------------------------- |
| 构建缺文件         | 是否拿到完整匹配包，是否在包根目录 build                           |
| init 文件已存在    | 是否已初始化；不要覆盖已有 owner/device 身份                     |
| 容器启动后退出       | enabled、server-config.json、目录权限、日志                |
| 地址正确却 403     | PUBLIC\_URL 与实际 Host、反代是否保留 Host、请求是否带 Origin     |
| 502／WSS 断开    | 宿主 8420 监听、TLS 代理、Upgrade 头与超时                    |
| 私有管理 401／无法连接 | control-token、SSH 转发存活、loopback 地址、socket UID/GID |
| 配对按钮不可用       | 是否先保存、是否仍有草稿、私有地址与令牌是否已配置                         |
| 202 长时间未完成    | Onevium 在线状态、助手发布/能力、审批与 Run 状态                   |
| 改了 env 没生效    | 是否通过 override 传入，并重新执行 up 而非只 restart             |
| 重启后数据消失       | DATA\_PATH 是否变化、是否误用了新 volume；不要重新初始化掩盖问题         |

## 下一步与验收边界

保留本次镜像标签、部署配置和数据备份位置。记录真实 API、模型执行、SSH、TLS、SSE、回调以及重启恢复的结果。完成这些检查前，状态应写“部署待验收”，不能写“生产已上线”。

继续阅读[身份认证](https://onevium.com/zh/docs/developers/authentication)、[业务会话](https://onevium.com/zh/docs/developers/conversations)和[Webhook 与结果回调](https://onevium.com/zh/docs/developers/webhooks)。
