Svix 1.102.1 配置参数详解

svix-server 1.102.1 全量配置逐节详解:三源加载优先级、认证加密、数据库/队列/缓存、投递重试与安全边界,含生产配置模板与实测验证方法。

SvixSvixWebhook中间件2026/10/24

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 就是官方全部参数的唯一权威清单(内置进二进制),本文按该文件逐节展开。

二、前置条件

  1. svix-server 已按部署指南跑通,健康检查正常:
curl -s http://127.0.0.1:8071/api/v1/health/

实测回示:

{"database":{"status":"ok"},"queue":{"status":"ok"},"cache":{"status":"ok"}}
  1. 查看当前生效配置的版本基线(确认你研究的参数与运行版本一致):
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_enabled0.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_secsredis / 未设 / 20
缓存cache_type / cache_dsn / redis_dsn / redis_pool_max_sizememory / 未设 / 未设 / 100
投递行为retry_schedule / worker_request_timeout / worker_max_tasks / endpoint_failure_disable_after7 级秒数组 / 30 / 500 / 120
安全边界whitelist_subnets / whitelist_names / endpoint_https_only / dangerous_disable_tls_verification空 / 空 / false / false
日志观测log_level / log_format / opentelemetry_address / sentry_dsninfo / default / 未设 / 未设
生命周期expired_message_cleaner_enabled / background_migrations_enabledtrue / true
品牌whitelabel_headers / operational_webhook_addressfalse / 未设

五、核心参数分类详解

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 实例时注意总连接数 = 实例数 × 池上限,超出 PostgreSQL max_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 后看投递头前缀。任何「以为改了」的参数,都应找到它对应的行为证据。

八、参考链接