Svix 1.102.1 配置参数详解
svix-server 1.102.1 全量配置逐节详解:三源加载优先级、认证加密、数据库/队列/缓存、投递重试与安全边界,含生产配置模板与实测验证方法。
Svix 1.102.1 配置参数详解
目标:逐节讲清 svix-server 1.102.1 的全部配置参数——监听与认证、数据库与连接池、队列与缓存、日志与可观测、投递行为与安全边界,以及三种配置来源的加载优先级;关键参数均配有实测验证方法与回显。命令与回显实测于 Ubuntu 22.04 + svix-server 1.102.1。
一、环境信息
- 软件版本:svix-server 1.102.1(自托管开源版)
- 配置基线来源:仓库文件
server/svix-server/config.default.toml(153 行,逐节核对) - 配置加载机制来源:源码
server/svix-server/src/cfg.rs(figment 框架三源合并) - 实测环境:Ubuntu 22.04,官方镜像部署,
SVIX_JWT_SECRET=q1w2e3r4 - 前置:已有一套可运行的 svix-server(部署见 《Svix Docker Compose 部署指南》)
💡 说明:svix-server 没有「配置样例生成」命令,
config.default.toml就是官方全部参数的唯一权威清单(内置进二进制),本文按该文件逐节展开。
二、前置条件
- svix-server 已按部署指南跑通,健康检查正常:
curl -s http://127.0.0.1:8071/api/v1/health/
实测回示:
{"database":{"status":"ok"},"queue":{"status":"ok"},"cache":{"status":"ok"}}
- 查看当前生效配置的版本基线(确认你研究的参数与运行版本一致):
svix-server --version
实测回示:
svix-server 1.102.1
三、参数查看与修改方式
3.1 三种配置来源与优先级
svix-server 用 Rust 的 figment 框架做配置合并,加载顺序(后者覆盖前者同名项):
① 内置默认值:config.default.toml(编译进二进制,兜底)
② 文件配置:工作目录下的 config.toml(可选)
③ 环境变量:SVIX_ 前缀 + 参数名大写(如 db_dsn → SVIX_DB_DSN)
源码实证(cfg.rs):
let merged = Figment::new()
.merge(Toml::string(DEFAULTS))
.merge(Toml::file("config.toml"))
.merge(Env::prefixed("SVIX_"));
两条实用推论:
- 环境变量优先级最高,排查「改了配置不生效」时先查同名
SVIX_*环境变量; DATABASE_URL环境变量在SVIX_DB_DSN未设置时会被自动采用(兼容 12-factor 应用)。
3.2 修改配置的两种姿势
环境变量方式(容器部署最常用,改 docker-compose.yml 的 environment: 段后 docker compose up -d 重建生效);文件方式:挂载 config.toml 到工作目录 /app/config.toml(必须叫这个名字,实测踩坑:挂成 svix-server.toml 静默不加载)。文件加载的实测验证方法:设置 whitelabel_headers = true 后重建服务,接收端签名头从 svix-* 变为 webhook-* 即证明文件生效:
加载前:H svix-id: msg_... H svix-signature: v1,...
加载后:H webhook-id: msg_... H webhook-signature: v1,...
3.3 参数类型速记
- 布尔型:
true/false;可选型:注释掉的参数多为「不设置即关闭」(如main_secret、sentry_dsn); - 列表型:TOML 数组(文件)或 JSON 数组字符串(环境变量,如
SVIX_WHITELIST_SUBNETS="[10.89.56.0/24, 192.168.0.0/16]"); - 数值型:注意单位,重试计划是秒、端点禁用阈值是小时、Worker 超时是秒。
四、参数总览
按主题分组的全部参数速查(默认值取自 config.default.toml):
| 分组 | 参数 | 默认值 |
|---|---|---|
| 监听与角色 | listen_address / api_enabled / worker_enabled | 0.0.0.0:8071 / true / true |
| 认证与加密 | jwt_secret / jwt_algorithm / main_secret / default_signature_type | 必填 / HS256 / 未设 / hmac256 |
| 数据库 | db_dsn / db_pool_max_size / db_tracing | 无(必填)/ 100 / false |
| 队列 | queue_type / queue_dsn / queue_max_poll_secs | redis / 未设 / 20 |
| 缓存 | cache_type / cache_dsn / redis_dsn / redis_pool_max_size | memory / 未设 / 未设 / 100 |
| 投递行为 | retry_schedule / worker_request_timeout / worker_max_tasks / endpoint_failure_disable_after | 7 级秒数组 / 30 / 500 / 120 |
| 安全边界 | whitelist_subnets / whitelist_names / endpoint_https_only / dangerous_disable_tls_verification | 空 / 空 / false / false |
| 日志观测 | log_level / log_format / opentelemetry_address / sentry_dsn | info / default / 未设 / 未设 |
| 生命周期 | expired_message_cleaner_enabled / background_migrations_enabled | true / true |
| 品牌 | whitelabel_headers / operational_webhook_address | false / 未设 |
五、核心参数分类详解
5.1 监听与角色:listen_address / api_enabled / worker_enabled
listen_address = "0.0.0.0:8071"
api_enabled = true
worker_enabled = true
listen_address:HTTP 监听地址,改端口就改这里(如"0.0.0.0:9080");api_enabled/worker_enabled:角色开关。生产扩容的标配拆法:API 实例设worker_enabled = false,Worker 实例设api_enabled = false,各自水平扩展、互不影响。
角色拆分的验证方法:Worker 实例上访问 API 应无路由响应。实测单实例全开时:
curl -s http://127.0.0.1:8071/api/v1/health/
{"database":{"status":"ok"},"queue":{"status":"ok"},"cache":{"status":"ok"}}
5.2 认证与加密:jwt_secret / jwt_algorithm / main_secret / default_signature_type
# jwt_secret = "8KjzRXrKkd9YFcNyqLSIY8JwiaCeRc6WK4UkMnSW" # 必填
# jwt_algorithm = "HS256"
# main_secret = "kPafCtH7KC351nWXQb2pEGa6IRW3OsYpzQJldB8X"
default_signature_type = "hmac256"
jwt_secret:唯一必填参数,缺失启动即退出(实测报错missing field jwt_secret)。API 的 Bearer JWT 由此密钥派生,用svix-server jwt generate生成;jwt_algorithm:令牌签名算法,支持 HS256/HS384/HS512/RS256/RS384/RS512/EdDSA。用 RS 系或 EdDSA 时密钥配置方式不同(非对称密钥对),小团队维持 HS256 即可;main_secret:客户端加密主密钥,用于端点敏感数据(如 mTLS 私钥)的应用层加密。一经设定不可更改,丢失后已加密数据不可解密——首次部署时就要定好并妥善保管;default_signature_type:新建端点密钥的默认类型,hmac256(对称)或ed25519(非对称)。只影响新端点,存量端点按创建时类型不变。
💡 技术拓展:Webhook 签名密钥的两类方案——
类型 原理 取舍 hmac256(对称) 收发双方共享同一 whsec_密钥,HMAC-SHA256 签名简单通用,密钥泄露即双向失守;Svix 默认 ed25519(非对称) 服务端持私钥签名,接收方只存公钥验签 公钥可公开分发、接收方无法伪造消息;适合开放生态 本文采用默认 hmac256:Svix 官方 SDK 全部内置该方案验签,通用性最好。
5.3 数据库:db_dsn / db_pool_max_size / db_tracing
db_dsn = "postgresql://postgres:postgres@pgbouncer/postgres"
db_pool_max_size = 100
db_tracing = false
db_dsn:PostgreSQL 连接串,唯一支持的持久库。官方 compose 走 PgBouncer(@pgbouncer/postgres);单机直连写@postgres/postgres;db_pool_max_size:连接池上限,最小 10。多 API/Worker 实例时注意总连接数 = 实例数 × 池上限,超出 PostgreSQLmax_connections会报连接拒绝——这正是官方引入 PgBouncer 的原因;db_tracing:打开后把 SQL 调用日志并入日志流(分析慢查询用,常开有噪音)。
5.4 队列:queue_type / queue_dsn / queue_max_poll_secs
queue_type = "redis"
# queue_dsn = "redis://redis:6379"
queue_max_poll_secs = 20
queue_type:memory / redis / rediscluster。多实例部署必须 redis(memory 队列随进程消亡,实测确认SVIX_QUEUE_TYPE=memory的单容器形态健康检查 queue 状态正常,但不具备可靠性);queue_dsn:队列专用 Redis DSN,覆盖redis_dsn;把队列和缓存拆到不同 Redis 实例时用;queue_max_poll_secs:Worker 长轮询上限秒数,默认 20。调大可减少空轮询的 Redis 压力,代价是任务延迟上限。
5.5 缓存:cache_type / cache_dsn / redis_dsn / redis_pool_max_size
# redis_dsn = "redis://redis:6379"
cache_type = "memory"
# cache_dsn = "redis://redis:6379"
redis_pool_max_size = 100
cache_type:memory / redis / rediscluster / none。官方注释明确:只有单 API 实例时才能用 memory;多 API 实例必须 redis,否则幂等(idempotency-key)等功能跨实例失效;redis_dsn:queue_dsn/cache_dsn 未设时的 Redis 兜底 DSN;- 实测佐证:官方 compose 单实例跑
cache_type=memory+queue_type=redis(只显式给了SVIX_REDIS_DSN),健康检查三项全 ok——队列与缓存可以只用一个 Redis 实例的不同用途。
5.6 投递行为:retry_schedule / worker_request_timeout / worker_max_tasks / endpoint_failure_disable_after
retry_schedule = [5,300,1800,7200,18000,36000,36000]
worker_request_timeout = 30
worker_max_tasks = 500
endpoint_failure_disable_after = 120
retry_schedule:重试间隔秒数数组,默认 7 次:5s → 5min → 30min → 2h → 5h → 10h → 10h(总跨度约 32 小时)。改短提高实时性、改长提高最终成功率;worker_request_timeout:对端点的单次 HTTP 超时(秒)。下游普遍慢时可调大,注意与重试节奏联动;worker_max_tasks:单实例并发投递任务上限,0 不限。压测或受端点侧限流约束时调整;endpoint_failure_disable_after:连续失败多少小时后自动禁用端点(120 = 5 天)。期间任意一次成功即重置计时。设 0 关闭自动禁用。
重试行为的实测证据(一次内网白名单未放行导致的失败投递):
svix message-attempt list-by-msg app_3L7Zxp4qhRw1RxdY6I7X25jzIRo msg_3L7aJ3wNLbjVAzaZZtr44SfgCVe
实测回示(节选,前两次 fail 第三次 success):
{"responseStatusCode": 0, "status": 2, "statusText": "fail", "timestamp": "2026-10-24T02:04:44.511103Z"},
{"responseStatusCode": 0, "status": 2, "statusText": "fail", "timestamp": "2026-10-24T02:04:51.332157Z"},
{"responseStatusCode": 200, "status": 0, "statusText": "success", "responseDurationMs": 6, "timestamp": "2026-10-24T02:10:30.125120Z"}
首次失败 02:04:44 → 第二次 02:04:51(间隔 5s,与 retry_schedule[0]=5 一致)→ 白名单修复后第三次重试在 02:10:30 自动恢复成功(约 5min 间隔档位)。
5.7 安全边界:whitelist_subnets / whitelist_names / endpoint_https_only / dangerous_disable_tls_verification
# whitelist_subnets = []
# whitelist_names = []
endpoint_https_only = false
# dangerous_disable_tls_verification = false
whitelist_subnets:允许投递的内网 CIDR 列表。默认空 = 全部私网地址被拒(SSRF 防护),这是自托管最常见的「投递失败 response_code=0」原因。实测:放行10.89.56.0/24前内网端点投递失败,放行后成功;whitelist_names:按主机名放行,绕过 IP 过滤。仅用于你完全掌控 DNS 的域名;endpoint_https_only:true 时拒绝 http:// 端点,面向外部客户的正式环境建议开启;dangerous_disable_tls_verification:跳过下游 TLS 证书校验,仅限自签证书联调,生产禁用。
5.8 日志与可观测:log_level / log_format / opentelemetry_* / sentry_dsn
log_level = "info"
log_format = "default"
# opentelemetry_address = "http://localhost:4317"
# opentelemetry_sample_ratio = 1.0
opentelemetry_service_name = "svix_server"
opentelemetry_logs_enabled = false
# sentry_dsn = "https://somedsn.ingest.sentry.io/12345"
log_level:info(默认)/ debug / trace。排障投递问题时开 debug,能看到每次 HTTP 尝试细节;log_format:default(人读)/ json(采集器友好,接 ELK/Loki 用 json);opentelemetry_address:OTLP gRPC 地址,设了即上报 traces+metrics,opentelemetry_logs_enabled = true再加日志;opentelemetry_sample_ratio:采样率,1.0 全量;高流量生产建议 0.1–0.5;sentry_dsn:Sentry 错误上报,设了即启用。
实测日志样例(info 级别,一次成功投递后服务器输出,已脱去颜色码):
INFO svix_server::worker: Worker concurrent task limit: 500
5.9 生命周期:expired_message_cleaner_enabled / background_migrations_enabled
expired_message_cleaner_enabled = true
background_migrations_enabled = true
expired_message_cleaner_enabled:过期消息清理器,定时把过期消息的 payload 置空(行保留以维持分页稳定)。彻底删数据用 CLI 的svix-server prune;background_migrations_enabled:后台迁移开关。多实例滚动升级时保持开启即可;由单独迁移任务执行时其余实例可关。
实测启动日志(两个生命周期组件的工作痕迹):
INFO svix_server::expired_message_cleaner: No payloads pending expiry found in `message` table. Skipping the cleaner for this table.
INFO svix_server::db::background_migrations: Background migration completed id="2026_04_1777303796_messageattempt_per_endp_no_status" elapsed_secs=0.002453141
5.10 品牌与运营:whitelabel_headers / operational_webhook_address
whitelabel_headers = false
# operational_webhook_address = "http://127.0.0.1:8071"
whitelabel_headers:true 时投递头前缀svix-→webhook-(实测已验证),把 Svix 包装成自有品牌时用;operational_webhook_address:运营事件回调地址——Svix 自身的端点创建/失败等事件会推到这里,仍走标准 Svix 签名。
5.11 代理:proxy_addr / noproxy
# proxy_addr = socks5://localhost:1080
# noproxy = "10.0.0.0/8, .example.com"
svix-server 向端点投递时走的出站代理(socks5 或 http),noproxy 指定绕过列表。端点在公网而服务器出网必须经代理的企业环境使用。
六、生产配置模板
适用场景:4 核 8GB 内存的 Ubuntu 22.04 单机(或同等 K8s 资源),SSD 盘,日投递 10 万级消息,2 API 实例 + 2 Worker 实例(可同一台机多实例或分开部署)。
listen_address = "0.0.0.0:8071"
# 认证:务必换成 32 字节以上随机值;首次部署时定好 main_secret 且永不更改
jwt_secret = "请用 openssl rand -base64 32 生成"
jwt_algorithm = "HS256"
# main_secret = "首次部署时设定"
# 数据库:经 PgBouncer 接 PostgreSQL,池上限按 (实例数×100) < pgbouncer MAX_CLIENT_CONN 控制
db_dsn = "postgresql://svix:强密码@pgbouncer/svix"
db_pool_max_size = 50
# 队列与缓存:生产全走 Redis 并开启持久化
queue_type = "redis"
queue_dsn = "redis://:强密码@redis:6379/0"
cache_type = "redis"
cache_dsn = "redis://:强密码@redis:6379/1"
# 投递:保持官方默认重试;对外 SaaS 场景收紧安全边界
retry_schedule = [5,300,1800,7200,18000,36000,36000]
worker_request_timeout = 30
worker_max_tasks = 500
endpoint_failure_disable_after = 120
endpoint_https_only = true
# 安全:只放行真正需要的内网网段
whitelist_subnets = ["10.0.0.0/8"]
# 可观测
log_level = "info"
log_format = "json"
opentelemetry_service_name = "svix_server"
# 生命周期
expired_message_cleaner_enabled = true
background_migrations_enabled = true
模板要点解读:队列与缓存分库(0/1 号 DB)便于独立清理与监控;endpoint_https_only 防止业务方误配明文端点;日志 json 化直接对接采集器;其余保持官方默认值,它们已在 Svix 大规模 SaaS 上验证过。
七、常见问题
Q1:改了 config.toml 完全不生效?
按顺序排查:文件名必须是 config.toml(源码固定读取,实测挂成其他名字静默忽略);文件必须在 svix-server 进程的工作目录(官方镜像为 /app,compose 挂载示例 ./config.toml:/app/config.toml:ro + working_dir: /app);是否存在同名 SVIX_* 环境变量覆盖(环境变量优先)。验证手段见 3.2(whitelabel_headers 前后签名头变化)。
Q2:SVIX_WHITELIST_SUBNETS 环境变量怎么写多个网段?
写成 TOML 数组的字符串形态:SVIX_WHITELIST_SUBNETS="[10.89.56.0/24, 192.168.0.0/16]"。实测单网段写法 "[10.89.56.0/24]" 生效(内网端点投递成功)。
Q3:启动报 missing field jwt_secret?
SVIX_JWT_SECRET 未设置。jwt_secret 无默认值,是唯一强制参数。实测报错:
Error: failed to extract configuration
Caused by:
missing field `jwt_secret`
Q4:多实例部署后 idempotency-key 幂等失效?
cache_type 还是 memory。幂等键存缓存,多 API 实例必须共享 Redis 缓存(cache_type = "redis" + 对应 DSN),官方 config.default.toml 注释原文即如此警告。
Q5:如何确认某个环境变量实际生效?
svix-server 没有 dump-config 命令,用行为验证:改 listen_address 端口后看监听(ss -ltn);改 log_level = debug 后看日志量明显增多;改 whitelabel_headers 后看投递头前缀。任何「以为改了」的参数,都应找到它对应的行为证据。