Outline Server 管理 API 使用详解

Outline Server v1.12.3 管理 API 详解:认证模型(秘密前缀+证书固定)、四大 API 域全端点实测(服务器/访问密钥/配置/指标)、错误码与安全行为、分页过滤约定(2026-10-20 全量实测)。

Outline ServerVPN安全OutlineSS代理2026/10/20

Outline Server 管理 API 使用详解

定位:Outline Server 官方未提供服务器端命令行工具(上游仓库与文档溯源,2026-10-20),其管理面由两部分构成:桌面图形端 Outline Manager 与服务端 REST 管理 API。本文按 API 篇组织,逐端点给出实测请求/响应,覆盖服务器信息、访问密钥、服务器级配置与指标四个域。所有回显均在 Outline Server v1.12.3 + Ubuntu 22.04.5 实测环境逐字采集(2026-10-20)。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(Jammy),x86_64
  • 软件版本:Outline Server v1.12.3(GET /server 返回体自报,实测)
  • 管理端口:15490(TCP,HTTPS);访问密钥端口:15491(TCP+UDP,数据面,不在本文范围)
  • 服务器对外地址:10.0.0.2(实测环境 IP,生产为服务器公网 IP)
  • 证书与凭据:/opt/outline/persisted-state/shadowbox-selfsigned.crt(自签证书)+ /opt/outline/access.txt(apiUrl/certSha256)
  • 实测密钥规模:3 个访问密钥(id 0/1/3)
  • 接口面取证:对 v1.12.3 源码 src/shadowbox/server/manager_service.ts 的路由注册逐条核对(2026-10-20),与实测行为一致
  • 安装过程见《Ubuntu 22.04 安装 Outline Server 指南》,配置文件含义见《Outline Server 配置参数详解》

二、前置条件

2.1 端点构成

https://<服务器地址>:<管理端口>/<秘密前缀>/<资源路径>
  • <秘密前缀>:安装时生成的 16 字节随机 URL 安全串(如实测环境的 81XKB8WldZi-_V92KSKvsQ),是管理 API 的唯一"口令"——完整 apiUrl 在 /opt/outline/access.txt,形如 https://10.0.0.2:15490/81XKB8WldZi-_V92KSKvsQ;
  • 前缀错误的请求一律 404 ResourceNotFound(服务不暴露任何前缀探测信息,实测见 5.5 节)。

2.2 认证模型(证书固定 + 秘密前缀)

要素说明实测行为
TLS自签证书(CN=对外地址,RSA-4096,100 年)客户端必须指定证书校验或显式跳过(不推荐)
证书固定Manager 用 certSha256 比对证书指纹指纹即 access.txt 中 certSha256
秘密前缀URL 路径段,承担鉴权无请求头 Token/Cookie 机制;前缀错 → 404
传输安全仅 HTTPS明文 HTTP 访问直接断开:curl: (52) Empty reply from server(实测)

⚠️ 注意:由于"口令"在 URL 路径中,请在使用时避免把完整 apiUrl 写进日志、截图或分享链接;凭据轮换方式为重跑安装脚本(实测见安装指南 10.2 节)。

2.3 客户端工具

任意 HTTP 客户端均可。本文统一用 curl,并始终附带服务器自签证书做服务端校验:

# 变量准备(生产环境以 access.txt 实际值为准)
API=https://10.0.0.2:15490/81XKB8WldZi-_V92KSKvsQ
CERT=/opt/outline/persisted-state/shadowbox-selfsigned.crt

三、API 总览

  • 协议/格式:HTTPS + JSON;写操作成功返回 204(空响应体),创建返回 201(密钥对象),查询返回 200(JSON);
  • 认证方式:秘密前缀(URL)+ 证书固定(客户端侧校验),无 Header Token;
  • 限流约定:实测高频连续调用未触发任何 429/限流(v1.12.3 源码亦无限流逻辑,2026-10-20 取证);管理端口仍建议做来源限制(安全组);
  • 版本:随服务端版本演进,GET /server 的 version 字段即实装版本。

全端点表(v1.12.3,源码取证 + 全量实测):

方法路径用途成功码
GET/server服务器信息(名称/版本/对外地址/新密钥默认端口/指标开关等)200
PUT/name服务器改名204
GET/access-keys列出全部访问密钥200
POST/access-keys创建访问密钥201
GET/access-keys/{id}读取单个访问密钥200
PUT/access-keys/{id}指定 ID 导入(迁移)密钥201
DELETE/access-keys/{id}删除访问密钥204
PUT/access-keys/{id}/name密钥改名204
PUT/access-keys/{id}/data-limit设置单密钥流量上限204
DELETE/access-keys/{id}/data-limit解除单密钥流量上限204
PUT/server/hostname-for-access-keys修改对外地址(仅作用于新密钥)204
PUT/server/port-for-new-access-keys修改新密钥默认端口(仅作用于新密钥)204
PUT/server/access-key-data-limit设置全体密钥默认流量上限204
DELETE/server/access-key-data-limit解除全体默认流量上限204
GET/metrics/transfer按密钥的累计流量统计200
GET/metrics/enabled读取匿名指标上报开关200
PUT/metrics/enabled设置匿名指标上报开关204
GET/experimental/server/metrics?since=实验性服务器指标(隧道时长/带宽/地区分布)200

💡 说明:/experimental/access-key-data-limit 在 v1.12.3 中以 308 重定向到 /server/access-key-data-limit(源码取证),属兼容别名;新集成请直接使用新路径。

四、认证与首次调用

首次调用读服务器信息,验证凭据与证书链路:

curl --cacert /opt/outline/persisted-state/shadowbox-selfsigned.crt \
  https://10.0.0.2:15490/81XKB8WldZi-_V92KSKvsQ/server

实测回显:

{"name":"Outline Server","serverId":"db7d0e08-70c8-47ec-a256-5be6c01e4219","metricsEnabled":false,"createdTimestampMs":1792508135464,"version":"1.12.3","portForNewAccessKeys":15491,"hostnameForAccessKeys":"10.0.0.2"}

三种典型失败形态(实测回显):

# 秘密前缀错误
curl --cacert $CERT https://10.0.0.2:15490/WRONGPREFIX/access-keys
{"code":"ResourceNotFound","message":"/WRONGPREFIX/access-keys does not exist"}
[http 404]
# 明文 HTTP 访问 HTTPS 端口
curl http://10.0.0.2:15490/81XKB8WldZi-_V92KSKvsQ/access-keys
curl: (52) Empty reply from server
# 未附带自签证书(用系统 CA 校验自签证书)
curl --cacert /etc/ssl/certs/ca-certificates.crt $API/server
curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

💡 说明:宿主侧经发布端口远程访问同一 API 的连通性亦实测通过(带 --resolve 指向服务器地址 + --cacert 校验,返回 200),即 Manager 在桌面端远程接入的行为等价可复现。

五、各 API 域详解

5.1 服务器信息与命名域

GET /server —— 读取服务器信息(字段含义逐项见配置详解篇 5.2 节),回显见第四章。

PUT /name —— 服务器改名:

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"name":"outline-demo-server"}' $API/name -w "\n[%{http_code}]\n"

实测回显:

[204]

改名后 GET /server 的 name 字段即变为新值(实测);重跑安装脚本会重置该名称(实测)。

5.2 访问密钥域

GET /access-keys —— 列出全部密钥:

curl -sS --cacert $CERT $API/access-keys -w "\n[%{http_code}]\n"

实测回显(节选首密钥对象,3 个密钥结构一致):

{"accessKeys":[{"id":"0","name":"","password":"TjDlqvxukYzNcvTPW4qtsV","port":15491,"encryptionMethod":"chacha20-ietf-poly1305","accessUrl":"ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpUakRscXZ4dWtZek5jdlRQVzRxdHNW@10.0.0.2:15491/?outline=1"},...]}
[200]

💡 说明:accessUrl 即可直接分发的 ss:// 链接(base64 段解码后为 chacha20-ietf-poly1305:<password>,实测解码验证一致),客户端粘贴即用。

POST /access-keys —— 创建密钥(无请求体):

curl -sS --cacert $CERT -X POST $API/access-keys -w "\n[%{http_code}]\n"

实测回显:

{"id":"1","name":"","password":"zmhZ2Fwh6qDo4eLXGvDnye","port":15491,"encryptionMethod":"chacha20-ietf-poly1305","accessUrl":"ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTp6bWhaMkZ3aDZxRG80ZUxYR3ZEbnll@10.0.0.2:15491/?outline=1"}
[201]

GET /access-keys/{id} —— 读取单个密钥(GET /access-keys/1,实测 200,结构同上单对象)。

PUT /access-keys/{id}/name —— 改名:

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"name":"office-test-key"}' $API/access-keys/1/name -w "\n[%{http_code}]\n"

实测回显:

[204]

PUT /access-keys/{id}/data-limit —— 设置单密钥流量上限(1GB):

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"limit":{"bytes":1073741824}}' $API/access-keys/1/data-limit -w "\n[%{http_code}]\n"

实测回显:

[204]

设置后该密钥对象即携带 "dataLimit":{"bytes":1073741824} 字段(实测 GET /access-keys/1 读回)。

DELETE /access-keys/{id}/data-limit —— 解除上限(实测 [204],读回后 dataLimit 字段消失)。

PUT /access-keys/{id} —— 指定 ID 导入(迁移)密钥。请求体需完整给定 method/name/password/port(可选 limit),适合把旧服务器密钥原样迁到新服务器:

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"method":"chacha20-ietf-poly1305","name":"migrated-key","password":"ImportedDemo9x8y7z","port":15491}' \
  $API/access-keys/9 -w "\n[%{http_code}]\n"

实测回显:

{"id":"9","name":"migrated-key","password":"ImportedDemo9x8y7z","port":15491,"method":"chacha20-ietf-poly1305","accessUrl":"ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpJbXBvcnRlZERlbW85eDh5N3o@10.0.0.2:15491/?outline=1"}
[201]

DELETE /access-keys/{id} —— 删除密钥(实测 DELETE /access-keys/9 → [204],列表中该密钥消失;删除后该凭据立即不可用)。

5.3 服务器级配置域

PUT /server/hostname-for-access-keys —— 修改对外地址:

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"hostname":"outline.demo.example.com"}' $API/server/hostname-for-access-keys -w "\n[%{http_code}]\n"

实测回显:

[204]

实测语义:仅对之后新建的密钥生效(新建密钥的 accessUrl 立即使用新地址),既有密钥链接不变;改回原值实测正常。非法主机名被拒(错误码见 5.5 节)。

PUT /server/port-for-new-access-keys —— 修改新密钥默认端口:

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"port":15492}' $API/server/port-for-new-access-keys -w "\n[%{http_code}]\n"

实测回显:

[204]

实测语义:仅作用于新密钥;新建密钥落在新端口且该端口随即开始监听(实测 ss -ltn 复核出现 15491 与 15492 双监听),既有密钥仍在原端口服务。

PUT /server/access-key-data-limit —— 全体密钥默认流量上限(10GB):

curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"limit":{"bytes":10737418240}}' $API/server/access-key-data-limit -w "\n[%{http_code}]\n"

实测回显:

[204]

设置后 GET /server 出现 "accessKeyDataLimit":{"bytes":10737418240}(实测读回);DELETE /server/access-key-data-limit 解除(实测 [204],字段消失)。

5.4 指标域

GET /metrics/transfer —— 按密钥累计流量(字节):

curl -sS --cacert $CERT $API/metrics/transfer -w "\n[%{http_code}]\n"

实测回显:

{"bytesTransferredByUserId":{}}
[200]

💡 说明:实测时点返回为空对象——该统计来自内部指标聚合链路(服务刚重启/重装后统计从零起算,聚合按周期产生),数值随服务运行逐步累积;结构为 {密钥ID: 字节数}。

GET /metrics/enabled 与 PUT /metrics/enabled —— 匿名指标上报开关:

curl -sS --cacert $CERT $API/metrics/enabled -w "\n[%{http_code}]\n"

实测回显:

{"metricsEnabled":false}
[200]
curl -sS --cacert $CERT -X PUT -H "Content-Type: application/json" \
  -d '{"metricsEnabled":true}' $API/metrics/enabled -w "\n[%{http_code}]\n"

实测回显:

[204]

再次 GET 返回 {"metricsEnabled":true}(实测),改回 false 实测正常。

GET /experimental/server/metrics?since=1h —— 实验性服务器指标:

curl -sS --cacert $CERT "$API/experimental/server/metrics?since=1h" -w "\n[%{http_code}]\n"

实测回显:

{"server":{"tunnelTime":{"seconds":0},"dataTransferred":{"bytes":0},"bandwidth":{"current":{"data":{"bytes":0},"timestamp":1792508042.406},"peak":{"data":{"bytes":0},"timestamp":null}},"locations":[{"location":"XL","asn":null,"asOrg":null,"dataTransferred":{"bytes":0},"tunnelTime":{"seconds":0}}]},"accessKeys":[{"accessKeyId":0,"dataTransferred":{"bytes":0},"tunnelTime":{"seconds":0},"connection":{"lastTrafficSeen":null,"peakDeviceCount":{"data":0,"timestamp":null}}}]}
[200]

字段解读:server.tunnelTime(隧道总时长)、server.dataTransferred(总流量)、server.bandwidth(当前/峰值带宽)、server.locations[](按接入方地区/ASN 组织分布,asOrg 为组织名)、accessKeys[](按密钥的连接统计:最近流量时间、峰值设备数)。since 参数取值格式为 <数值><单位>,支持单位 s/h/d/w(源码 TIME_RANGE_UNIT_TO_SECONDS_MULTIPLYER,2026-10-20 取证);缺省 since 报 400(实测见 5.5 节)。

5.5 错误码与安全行为

实测错误面汇总(全部为逐字回显):

场景状态码响应体
缺必填参数(如 PUT /name 无 body)400{"code":"MissingParameter","message":"Parameter \name` is missing"}`
请求体非法 JSON400{"code":"InvalidContent","message":"Invalid JSON: Unexpected token b in JSON at position 1"}
参数值非法(如主机名 not valid host!)400{"code":"InvalidArgument","message":"Hostname not valid host! isn't a valid hostname or IP address"}
资源不存在(GET /access-keys/99)404{"code":"NotFound","message":"Access key \"99\" not found"}
秘密前缀错误(/WRONGPREFIX/access-keys)404{"code":"ResourceNotFound","message":"/WRONGPREFIX/access-keys does not exist"}
HTTP 方法不允许(GET /name)405{"code":"MethodNotAllowed","message":"GET is not allowed"}
缺 since 查询参数400{"code":"MissingParameter","message":"Parameter \since` is missing"}`

安全行为实测:前缀错误不暴露任何服务信息(与普通 404 无异);明文 HTTP 直接断开连接;证书不匹配在客户端即被拒绝(curl: (60));响应均不回显服务端内部路径。

六、分页/过滤/排序通用约定

本 API 无分页、排序与字段过滤机制(v1.12.3 源码逐条核对 + 实测,2026-10-20):

  • 列表全量返回:GET /access-keys 一次性返回全部密钥(实测 3 个密钥全量返回,无 page/limit 参数);密钥数量通常在个位到百位级,全量返回不构成性能问题;
  • 唯一的时间过滤:GET /experimental/server/metrics 的 since 查询参数(格式 <数值><单位>,单位 s/h/d/w),是全 API 唯一的"过滤"参数;
  • 排序:列表按密钥 ID 序返回(实测 id 0→1→3 顺序),无排序参数。

七、常见问题(FAQ)

Q1:Outline 有没有官方 CLI? 没有。官方管理面 = Outline Manager(图形端)+ 本 REST 管理 API(上游仓库与文档溯源,2026-10-20)。需要脚本化/自动化时用本 API 封装即可,本文全部端点可直接作为封装依据。

Q2:401/403 在哪?为什么没有 Token? 本 API 的鉴权是"URL 秘密前缀 + 证书固定"模型,不走 HTTP 认证头;前缀错误直接 404(伪装为路由不存在)。因此不要在网关日志中打印完整请求路径。

Q3:改了 hostname/port-for-new-access-keys,为什么老密钥没变? 设计行为:这两个接口只影响新建密钥(实测验证,详见 5.3 节)。存量密钥迁移用"记录旧密码 → 删除 → PUT /access-keys/{id} 导入重建"的路径。

Q4:POST /access-keys 能否指定端口或加密方法? 常规创建不能(端口跟随服务器级默认值、加密方法统一 chacha20-ietf-poly1305,实测);需要指定时用 PUT /access-keys/{id} 导入接口(可指定 method/password/port,实测见 5.2 节)。

Q5:流量上限设错了会影响在途连接吗? 上限以字节数存储于密钥对象(实测读回);执行后由服务端在数据面生效,无需重启服务实例(实测配置即时可读)。

Q6:如何安全轮换管理凭据? 重跑官方安装脚本会轮换秘密前缀与证书(实测 apiUrl/certSha256 全变),已建访问密钥保留;轮换后 Outline Manager 需用新 JSON 串重新接入(实测记录见安装指南 10.2 节)。

八、参考链接