OTS 1.23.1 配置参数详解
OTS v1.23.1 全配置面详解:10 个启动参数、Redis 存储环境变量、customize.yaml 17 个前端定制字段,含 expire 封顶回退、metrics 网段 ACL 实测与生产配置模板。
OTS 1.23.1 配置参数详解
目标:系统讲清一次性秘密分享平台 OTS v1.23.1 的全部可配置项——服务进程启动参数、存储后端环境变量、Web 前端定制文件(customize.yaml)三大配置面,含每个参数的真实默认值、取值范围、生效验证方法与生产配置模板。全部行为均在 Ubuntu 22.04 + OTS v1.23.1(监听 8146)实测验证,回显为真实输出。
一、环境信息
- 操作系统:Ubuntu 22.04(systemd 托管)
- OTS 版本:v1.23.1(官方二进制,
/usr/local/bin/ots) - 监听端口:
0.0.0.0:8146(本文实验端口) - 定制文件:
/etc/ots/customize.yaml - 参数来源取证:
ots --help实测回显、官方 Wiki Customization 页(查询日期 2026-10-30)、仓库源码(main.go / api.go / pkg/customization/customize.go / pkg/storage) - 安装过程见 《Ubuntu 22.04 安装 OTS 指南》,本文默认服务已可运行
二、前置条件
- OTS v1.23.1 已安装并可访问(
curl http://127.0.0.1:8146/api/healthz返回 200); - 能编辑 systemd 单元与定制文件(root 或 sudo 权限);
- 修改任意配置后的生效公式固定为:
systemctl daemon-reload && systemctl restart ots && systemctl is-active ots
实测回显:
active
- 若使用 Redis 后端,需备一个可达的 Redis 实例(连接串见 5.2 节)。
三、参数查看与修改方式
OTS 没有统一的 config.yaml——配置分三个入口,按作用对象区分:
| 入口 | 作用对象 | 修改后生效方式 |
|---|---|---|
进程启动参数(--flag) | 服务进程自身:监听、存储、过期上限、TLS、日志 | systemctl daemon-reload && systemctl restart ots |
环境变量(大写同名 / REDIS_URL 等) | 与启动参数等价 + Redis 连接配置 | 同上(systemd Environment= 注入) |
定制文件(--customize 指向的 YAML) | Web 前端与接口行为:标题、图标、有效期选项、附件、指标 ACL | 同上(随进程重启重读) |
查看当前全部启动参数与真实默认值:
ots --help
实测回显(全文照抄):
Usage of /usr/local/bin/ots:
--cert-file string Path to the TLS certificate file
--customize string Customize-File to load
--enable-tls Enable HTTPS/TLS
--key-file string Path to the TLS private key file
--listen string IP/Port to listen on (default ":3000")
--log-level string Set log level (debug, info, warning, error) (default "info")
--log-requests Enable request logging (default true)
--secret-expiry int Maximum expiry of the stored secrets in seconds
--storage-type string Storage to use for putting secrets to (default "mem")
--version Print version information and exit
⚠️ 注意:
--secret-expiry的 help 未显示默认值,源码默认为0(永不过期);--storage-type默认mem。此外每个启动参数都有同名大写环境变量形态(源码启用rconfig.AutoEnv(true)):--listen↔LISTEN、--storage-type↔STORAGE_TYPE、--secret-expiry↔SECRET_EXPIRY,两者同时存在时启动参数优先。
运行中查看前端实际生效的定制(定制文件的 JSON 投影,排障利器):
curl -s http://127.0.0.1:8146/api/settings
实测回显(本文实验配置):
{"appTitle":"Corp Secrets - One Time Secrets","expiryChoices":[300,3600,86400,604800],"acceptedFileTypes":"","disableFileAttachment":false,"maxAttachmentSizeTotal":10485760,"footerLinks":[{"name":"Internal Security Policy","url":"https://intranet.example.com/security"}]}
💡 说明:
/api/settings只返回非零值字段(JSON 序列化带 omitempty),因此「关闭类」开关未开启时不出现——上例中disableQRSupport等缺失即代表默认(不关闭),这不是配置丢失。
四、参数总览
4.1 服务进程启动参数(10 个)
| 参数 | 默认值 | 等价环境变量 | 一句话作用 |
|---|---|---|---|
--listen | :3000 | LISTEN | HTTP(S) 监听地址与端口 |
--storage-type | mem | STORAGE_TYPE | 存储后端:mem / redis |
--secret-expiry | 0 | SECRET_EXPIRY | 秘密最长存活秒数(0=永不过期) |
--customize | 空 | CUSTOMIZE | 前端定制文件路径 |
--log-level | info | LOG_LEVEL | 日志级别:debug/info/warning/error |
--log-requests | true | LOG_REQUESTS | 记录每条 HTTP 请求访问日志 |
--enable-tls | false | ENABLE_TLS | 直接以 HTTPS 对外服务 |
--cert-file | 空 | CERT_FILE | TLS 证书文件路径 |
--key-file | 空 | KEY_FILE | TLS 私钥文件路径 |
--version | — | VERSION | 打印版本并退出 |
4.2 存储后端环境变量(仅 Redis 后端)
| 变量 | 默认值 | 作用 |
|---|---|---|
REDIS_URL | 无(必填) | Redis 连接串 redis://USR:PWD@HOST:PORT/DB |
REDIS_KEY | io.luzifer.ots | 键前缀(源码 pkg/storage/redis/redis.go:os.Getenv("REDIS_KEY") 非空时覆盖) |
SECRET_EXPIRY | 0 | mem/redis 共用的过期上限(Redis 以 TTL 实现到期自动删除) |
4.3 定制文件字段(customize.yaml,17 个)
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
appIcon | 字符串 | 空 | 前端主图标(建议高 30px) |
appIconDark | 字符串 | 空 | 暗色主题图标(缺省回落 appIcon) |
appTitle | 字符串 | OTS - One Time Secrets | 应用标题 |
disableAppTitle | 布尔 | false | 隐藏标题文字(图标已含品牌时用) |
disableExpiryOverride | 布尔 | false | 关闭前端与 API 的有效期覆盖能力 |
disablePoweredBy | 布尔 | false | 隐藏页脚项目回链 |
disableQRSupport | 布尔 | false | 关闭分享链接二维码按钮 |
disableThemeSwitcher | 布尔 | false | 关闭亮/暗主题切换 |
expiryChoices | 整数数组 | 内置默认集 | 前端有效期下拉选项(秒,顺序即展示顺序) |
overlayFSPath | 字符串 | 空 | 前端静态资源覆盖目录 |
useFormalLanguage | 布尔 | false | 有正式称谓译本的语言用正式版文案 |
acceptedFileTypes | 字符串 | 空 | 附件选择框的 accept 类型过滤(纯前端约束) |
disableFileAttachment | 布尔 | false | 整体关闭附件功能(纯前端约束) |
maxAttachmentSizeTotal | 整数 | 0(内部 64 MiB) | 附件总大小上限(字节,前端实施) |
maxSecretSize | 整数 | 121168782 | 服务端秘密总大小上限(字节) |
metricsAllowedSubnets | 字符串数组 | [](全拒绝) | 允许抓取 /metrics 的来源网段 |
footerLinks | 数组 | 空 | 页脚自定义链接(名称+URL) |
五、核心参数分类详解
5.1 监听与 TLS:--listen / --enable-tls / --cert-file / --key-file
--listen 接受 Go 标准地址形态::8146(全接口)、0.0.0.0:8146(显式全接口,本文实测采用)、127.0.0.1:8146(仅本机,配合反代时最安全)。默认 :3000。
直连 HTTPS 形态(不依赖 nginx 等反代):
# /etc/systemd/system/ots.service 的 ExecStart 片段
ExecStart=/usr/local/bin/ots --listen=0.0.0.0:8146 --enable-tls --cert-file=/etc/ots/tls.crt --key-file=/etc/ots/tls.key --storage-type=mem --secret-expiry=604800 --customize=/etc/ots/customize.yaml
💡 技术拓展:把 TLS 做在应用层(
--enable-tls)还是反代层(nginx/Caddy 终结 TLS)是两条常见路线——
方案 优点 取舍 应用层 TLS(OTS 自带) 拓扑简单,一个进程闭环 证书续期要自己挂钩;无访问日志聚合、限速能力 反代层 TLS(本文推荐) 统一证书管理、可叠加访问控制/限流 多一个组件,需配 X-Forwarded-Proto等头本文实测采用反代层方案(nginx 配置与实测回显见 《Ubuntu 22.04 安装 OTS 指南》第八章);单机内网小场景用
--enable-tls更省事。
5.2 存储后端:--storage-type / REDIS_URL / REDIS_KEY / SECRET_EXPIRY
💡 技术拓展:OTS 支持 mem / redis 两种存储,本质是「进程内存 vs 外置存储」的取舍——
后端 原理 重启后未读秘密 多实例 适用 mem带周期清理的进程内 map(源码 pkg/storage/memory) 全部丢失(官方明言 wiped on restart,实测复现) 不支持 个人/单机/演示 redisSET <prefix>:<id> <cipher> EX <expiry>原子写入(源码 pkg/storage/redis)保留,到期 TTL 自动删除 支持(共享 Redis) 生产/负载均衡部署 本文实验用
mem验证功能;生产建议redis,理由是重启不丢与可水平扩展。
Redis 后端的 systemd 配置形态:
# /etc/systemd/system/ots.service 关键行(仅示例骨架,完整单元见安装指南)
[Service]
Environment=REDIS_URL=redis://:q1w2e3r4@127.0.0.1:6379/0
Environment=REDIS_KEY=io.luzifer.ots
Environment=SECRET_EXPIRY=604800
ExecStart=/usr/local/bin/ots --listen=0.0.0.0:8146 --storage-type=redis --customize=/etc/ots/customize.yaml
要点(依据官方 README 与源码,均在 2026-10-30 核对):
REDIS_URL缺失时服务启动直接失败,报REDIS_URL environment variable not set(源码 redis.go 显式检查);- 连接串支持
tcp://与redis://两种 scheme(源码内做替换兼容);认证用户名的写法:Redis 6 之前用auth作用户名,Redis 6+ 用 ACL 用户; REDIS_KEY是键前缀而非单个键,默认io.luzifer.ots,多套 OTS 共用一个 Redis 时可各配前缀隔离;- Redis 后端下
SECRET_EXPIRY/--secret-expiry换算成SET ... EX <秒>的 TTL,到期由 Redis 自动删除——这是 mem 后端「周期清理」之外的被动兜底。
实测:mem 后端重启即焚(详见安装指南 FAQ Q2):创建秘密 → systemctl restart ots → 再读返回 404。切换存储后端属于一次性动作,切前无需迁移(mem 里本就无可迁数据;反之从 Redis 切回 mem 也会「看起来全丢」)。
5.3 有效期体系:--secret-expiry / expiryChoices / disableExpiryOverride
三件套构成 OTS 的过期控制面:
- 服务端硬上限
--secret-expiry(默认 0=永不过期):任何秘密存活时间不得超过它,本文设 604800(7 天),启动日志可见secret_expiry=168h0m0s(实测); - 前端选项
expiryChoices:创建页下拉框的可选秒值列表,本文配[300, 3600, 86400, 604800](5 分钟/1 小时/1 天/7 天),/api/settings实测回显同值; - 总开关
disableExpiryOverride: true:关闭后前端下拉与 API 的expire参数一起失效,所有秘密一律用服务端上限(合规场景「必须到期即焚」时开启)。
API 侧 expire 参数的封顶与回退规则(源码 api.go parseExpiryOverride + 实测复现,?expire=<秒> 追加在 /api/create):
| 请求 | 实测结果 | 规则 |
|---|---|---|
?expire=3600 | expires_at = 现在+1 小时 | 未超上限,按请求值 |
?expire=999999999 | expires_at = 现在+604800 秒(7 天) | 超过服务端上限被静默封顶为 604800 |
?expire=0 | expires_at = 现在+604800 秒 | 0 值回退服务端默认上限 |
?expire=abc | HTTP 400,{"success":false,"error":"<uuid>"} | 非数字 → invalid_expiry |
?expire=-5 | HTTP 400 | 负数 → invalid_expiry |
disableExpiryOverride: true 时带 ?expire=60 | HTTP 400 | 覆盖能力已关闭 |
⚠️ 注意:封顶是静默的——HTTP 仍返回 201,只是
expires_at被缩短到服务端上限。依赖「精确 30 天过期」的调用方必须确保--secret-expiry大于等于业务期望值。
5.4 前端定制组:appTitle / appIcon* / disable* / footerLinks
品牌与界面开关,全部随 --customize 文件下发到前端(模板渲染进 index.html + /api/settings 双通道)。实测验证 appTitle 生效:
curl -s http://127.0.0.1:8146/ | grep -oE '<title>[^<]*</title>'
实测回显:
<title>Corp Secrets - One Time Secrets</title>
appIcon/appIconDark:填图片文件名(相对根路径,如app.png),图片本身通过overlayFSPath目录下发——覆盖目录里的文件会替代内嵌同名资源,并出现在站点根路径(官方 Wiki:app.png将在https://ots.example.com/app.png提供);disablePoweredBy:隐藏页脚「Powered by」回链(官方建议保留以支持项目,商业使用可考虑捐赠);footerLinks:合规页脚(隐私政策/使用条款),数组元素为{name, url},/api/settings回显已含本文实验配置的示例条目;disableThemeSwitcher:自定义单套主题(只覆盖了亮或暗一种资源)时关掉切换按钮;useFormalLanguage:德语等提供正式称谓译本的语言改用正式文案,中文无差异。
5.5 大小限制组:maxSecretSize / maxAttachmentSizeTotal / acceptedFileTypes / disableFileAttachment
四项共同决定「能分享多大、什么类型的东西」:
maxSecretSize(服务端实施):秘密总大小上限,超出返回 HTTP 400(源码 api.go:secret size exceeds maximum计入secret_size错误计数)。未配置时的内部默认值 121168782 字节 ≈ 115.6 MiB,官方 Wiki 给出推导:前端附件上限 64 MiB,经两轮 base64 膨胀(×4/3 ×4/3 = ×16/9)再加 1 MiB 余量;maxAttachmentSizeTotal(前端实施):附件总大小,默认 0=内部 64 MiB;本文配 10485760(10 MiB),/api/settings回显确认;acceptedFileTypes(纯前端):文件选择框的 accept 过滤(如.pem,.key,.txt);disableFileAttachment(纯前端):整体关闭附件上传。
⚠️ 注意:官方 Wiki 用加粗强调后三项只是前端约束,不是安全边界——服务端无法感知密文内部「11 KB 秘密 + 10 KB 附件」的构成,也挡不住直接调 API 的客户端(如 ots-cli 不检查文件类型)。真正的入口限流要在反代上做(nginx
client_max_body_size,见安装指南 8.2 节)。
5.6 指标与可观测:metricsAllowedSubnets / --log-level / --log-requests
/metrics 网段 ACL:默认空列表=拒绝一切来源(请求直接 404)。配置必须是带掩码的子网形态,单个 IP 也要写 127.0.0.1/32。本文实验配置放行 127.0.0.1/32 与实验网段 10.89.71.0/24,实测双向验证:
# 放行网段内的来源
curl -s -o /dev/null -w 'metrics_allow_code=%{http_code}\n' http://127.0.0.1:8146/metrics
实测回显:
metrics_allow_code=200
把放行列表清空重启后重测,返回 metrics_deny_code=404(实测);恢复配置后回到 200。指标样例(实测节选):
ots_secrets_create_errors{reason="invalid_expiry"} 1
ots_secrets_create_errors{reason="invalid_json"} 1
ots_secrets_create_errors{reason="secret_missing"} 1
ots_secrets_created 3
ots_secrets_read 1
ots_secrets_read_errors{reason="secret_not_found"} 3
ots_secrets_stored 2
⚠️ 注意:OTS 跑在反代后面时,
/metrics的网段校验看到的是代理的地址(官方 Wiki 原文提示),不要把反代网段无脑放行,除非该端点已在代理层另行鉴权。
日志两参数:--log-level 四档(debug/info/warning/error),排障期间可临时调 debug;--log-requests 默认开启,访问日志行格式实测:
time="2026-10-29T17:41:00Z" level=info msg="10.89.71.1 - \"GET /api/get/8866920b-d07b-4f42-9b2d-6acb8394feea\" 200 93 \"\" \"curl/8.18.0\" 32.426µs"
字段依次为:时间、来源 IP、方法与路径、状态码、响应字节数、referer、UA、耗时。错误类请求部分会落一行带 err_id 的结构化错误(与 API 响应里的 error UUID 对应,用于排查「接口只回 UUID 的问题」;实测 404 与非法 JSON 有日志、空秘密与非法 expire 刻意静默,完整对照见 《OTS 1.23.1 常用 CLI 命令与 API 详解》4.6 节):
time="2026-10-29T17:41:00Z" level=error msg="reading & destroying secret" err_id=ddf5013f-5b41-46c0-b218-67fc2e25223e error="secret not found"
六、生产配置模板
6.1 模板 A:内网单机(1C/1GB 内存/普通磁盘,团队内部口令交接)
# /etc/systemd/system/ots.service
[Unit]
Description=OTS - One-Time-Secret sharing platform
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ots
Group=ots
ExecStart=/usr/local/bin/ots --listen=0.0.0.0:8146 --storage-type=mem --secret-expiry=86400 --log-level=info --customize=/etc/ots/customize.yaml
Environment=SECRET_EXPIRY=86400
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
# /etc/ots/customize.yaml
appTitle: "Internal Secrets"
disableExpiryOverride: false
expiryChoices: [300, 1800, 3600, 86400]
maxAttachmentSizeTotal: 10485760
metricsAllowedSubnets:
- 127.0.0.1/32
footerLinks:
- name: "Security Policy"
url: "https://intranet.example.com/security"
场景说明:秘密最长活 1 天(--secret-expiry=86400),前端只能选 5 分钟~1 天;mem 后端零依赖(重启丢失未读秘密在内网交接场景可接受);内存占用实测 2–4 MB,磁盘无持久化需求。防火墙/反代限制来源网段(OTS 无账号体系)。
6.2 模板 B:多实例 + Redis(2C/4GB,高可用要求)
[Service]
Environment=REDIS_URL=redis://:q1w2e3r4@redis.internal:6379/0
Environment=REDIS_KEY=io.luzifer.ots
Environment=SECRET_EXPIRY=604800
ExecStart=/usr/local/bin/ots --listen=0.0.0.0:8146 --storage-type=redis --log-level=info --customize=/etc/ots/customize.yaml
# /etc/ots/customize.yaml
appTitle: "Secrets Relay"
expiryChoices: [300, 3600, 86400, 604800]
maxAttachmentSizeTotal: 33554432
metricsAllowedSubnets:
- 127.0.0.1/32
- 10.0.0.0/8
场景说明:两个以上 OTS 实例共享 Redis(Redis 侧持久化 AOF/RDB 按机房策略定),秘密最长 7 天、TTL 到期自动清;REDIS_KEY 保持默认前缀,多套环境用不同 Redis DB 或前缀隔离;指标放行监控网段 10.0.0.0/8。演示密码 q1w2e3r4 应替换为 Redis ACL 专用账号口令。
七、常见问题(FAQ)
Q1:改了 customize.yaml 没生效?
定制文件随进程启动读取(源码 customization.Load 在 init 阶段执行),必须 systemctl restart ots。验证通道:curl -s http://127.0.0.1:8146/api/settings 比对字段值;页面级字段(标题/图标)同时受前端缓存影响,强刷(Ctrl+Shift+R)再验证。
Q2:--secret-expiry=0 和 expiryChoices 能共存吗?
能,但语义组合要想清楚:服务端 0 = 不设硬上限、秘密按用户所选 expiryChoices 过期;若同时想让「不选就走默认」成立,应把服务端上限设为非 0 值(API ?expire=0 会回退该值,实测见 5.3 节)。
Q3:/api/settings 里没有我配的 disableQRSupport 等字段?
/api/settings 的 JSON 带 omitempty,零值字段(false/0/空串)不出现——缺失即默认值。确认定制加载是否成功看启动日志(customize 文件路径错误时日志出现 customize file given but not found 警告,且按无定制继续运行,源码 customization.Load 行为)。
Q4:maxSecretSize 我配小了,前端还显示能传大文件?
正常。大小与类型四参数里只有 maxSecretSize 是服务端实施的,其余是前端约束;服务端拒绝发生在提交时(HTTP 400 + ots_secrets_create_errors{reason="secret_size"} 计数上涨)。想同时约束前端体验就成对配置。
Q5:日志里全是访问行太吵,能关吗?
--log-requests=false(或 LOG_REQUESTS=false)关闭访问日志,仅保留错误/警告与启动行。访问日志不含秘密内容与解密密码(零知识架构决定服务端无从记录),只有密文操作元数据,按需保留即可。
Q6:想给不同部门不同有效期选项?
部署多个实例(同一二进制),各配独立 customize.yaml(不同 expiryChoices/标题),mem 后端各自独立,Redis 后端用不同 REDIS_KEY 前缀隔离,反代按路径/域名分流。
八、参考链接
- 官方 Wiki 定制文档(customize.yaml 权威出处):https://github.com/Luzifer/ots/wiki/Customization
- 官方仓库 README(存储后端与 SECRET_EXPIRY):https://github.com/Luzifer/ots
- 源码参数定义:main.go(启动参数)、api.go(expire 覆盖逻辑)、pkg/customization/customize.go(定制结构体):https://github.com/Luzifer/ots/tree/master
- 本系列文章:《OTS 介绍与选型指南》、《Ubuntu 22.04 安装 OTS 指南》、《OTS 1.23.1 常用 CLI 命令与 API 详解》
- 同类配置参考:《OneTimeSecret v0.26.19 配置参数详解》(Ruby 系同类平台的配置面,可对照)