Outline Server 管理 API 使用详解
Outline Server v1.12.3 管理 API 详解:认证模型(秘密前缀+证书固定)、四大 API 域全端点实测(服务器/访问密钥/配置/指标)、错误码与安全行为、分页过滤约定(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"}` |
| 请求体非法 JSON | 400 | {"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 节)。
八、参考链接
- 上游仓库:https://github.com/OutlineFoundation/outline-server
- 管理服务源码(接口面取证依据):https://github.com/OutlineFoundation/outline-server/blob/server-v1.12.3/src/shadowbox/server/manager_service.ts
- 安装实测(本仓姊妹篇):《Ubuntu 22.04 安装 Outline Server 指南》
- 配置参数详解(本仓姊妹篇):《Outline Server 配置参数详解》
- 介绍与选型(本仓姊妹篇):《Outline Server 介绍与选型指南》