Sourcehut 配置参数详解
Sourcehut /etc/sr.ht 配置体系详解:global.ini 公共节、meta/git 服务节逐参数说明,密钥体系(service/network/webhook)与联动关系,附 9 条配置类故障症状-根因-修法速查表与生效路径。
Sourcehut 配置参数详解
本篇是 Sourcehut 系列的配置篇:以单机最小可用集(meta.sr.ht 0.88.9 + git.sr.ht 0.102.8,Ubuntu 22.04.5)的
/etc/sr.ht目录为主线,逐节讲清每个 ini 参数的含义、取值与联动关系,并给出配置类故障的症状→根因→修法速查表(全部来自真实排障)。安装过程见《Sourcehut 0.88.9 + git.sr.ht 0.102.8 Ubuntu 22.04 安装指南》。
一、配置体系总览
1.1 文件布局与加载顺序
Sourcehut 没有单一配置文件,而是 /etc/sr.ht/ 下的一组 ini:
/etc/sr.ht/
├── global.ini # [sr.ht] 公共节 + 跨服务引用
├── meta.sr.ht.ini # [meta.sr.ht] 及其子节
└── git.sr.ht.ini # [git.sr.ht] 及其子节
加载规则(core.sr.ht 的 srht/config.py 实测确认):
- 优先读工作目录下的
config.ini;存在即停。 - 否则读
/etc/sr.ht/config.ini;存在即停。 - 否则按 glob 读
/etc/sr.ht/*.ini全部文件并逐个合并——同节同键后者覆盖前者(glob 按文件名字母序展开)。
Go 层(各 *-api 二进制,core-go 的 config.LoadFiles)同样合并 /etc/sr.ht/*.ini。因此"公共放 global.ini、差异放各自文件"是官方样例约定的组织方式,两侧一致。
1.2 ini 语法与节命名约定
- 标准 configparser 语法:
[节]+key=value,#开头为注释。 - 节名即服务名:
[meta.sr.ht]、[git.sr.ht];子节用::分隔:[meta.sr.ht::settings]、[git.sr.ht::api]。 - 每服务源码里的
config.example.ini是该版本参数的权威清单(升级后对照一遍,新参数以它为准)。
二、[sr.ht] 公共节:全网络共享的身份与基础设施
[sr.ht]
site-name=My Sourcehut
site-info=http://meta.srht.local
site-blurb=the hacker's forge
environment=development
owner-name=admin
owner-email=admin@srht.local
source-url=http://meta.srht.local
service-key=<64 位十六进制,sr.ht-keygen service>
network-key=<base64,sr.ht-keygen network>
redis-host=redis://127.0.0.1:6379/0
global-domain=srht.local
逐项说明:
| 参数 | 作用 | 取值要点 |
|---|---|---|
| site-name / site-blurb | 站点名称与一句话简介,页面标题栏取 site-name | 自由文本 |
| site-info | "关于"页地址 | 一般指向 meta 站 |
| environment | development 时页脚显示非生产横幅,且静态资源走未压缩路径;生产必须设 production | 二选一 |
| owner-name / owner-email | 页脚展示的运营者信息 | 自由 |
| source-url | 页脚"源码"链接 | 自由 |
| service-key | 会话 cookie 与内部会话签名的对称密钥 | 同一服务的多节点必须一致;全站一致也可(简化部署) |
| network-key | 服务间内部调用报文的加密密钥 | 全部服务必须一致,不一致则跨服务 GraphQL 调用解密失败 |
| redis-host | 缓存/webhook 队列的 Redis 地址 | 必须是完整 URL(见六.1 排障表) |
| global-domain | 全站域名,决定 cookie 域与"每服务一个子域"的推导 | 设了它,meta.<域>、git.<域> 的 origin 才能联动 |
| security-address | 安全问题报告邮箱 | 可选 |
| assets | 静态资源根目录,默认 /usr/share/sourcehut | 一般不动 |
service-key / network-key 生成命令(实测输出格式):
$ sr.ht-keygen service
Secret key: 63382df4607b494e6aeadbecd31e891e8542c670da47fd9bb26c501f296673c3
$ sr.ht-keygen network
Secret key: Nv_VAcXJfwgKST_StkD1SLSDMp7wWH0B2u-s8g1vjwQ=
cookie 域与 global-domain 的联动是配置篇最重要的一个联动:会话 cookie 以
.srht.local为域下发(实测 Set-Cookie 可见),所以任何绕过域名直接用 IP 的访问都拿不到登录态。改域名要同时改 global-domain 与各服务的 origin。
三、[meta.sr.ht]:认证中心的参数
3.1 基础节
[meta.sr.ht]
origin=http://meta.srht.local # 对外访问 URL(协议://域名)
debug-host=0.0.0.0 # debug 服务器监听地址(flask run 用)
debug-port=5000 # debug 端口;gunicorn 场景下无作用
connection-string=postgresql://srht:q1w2e3r4@127.0.0.1/meta
migrate-on-upgrade=no # yes 时包升级触发自动迁移
webhooks=redis://127.0.0.1:6379/1 # webhook worker 的队列(注意 DB 序号)
api-origin=http://127.0.0.1:5100 # 本服务 Go API 的地址
要点:
connection-string建议显式走127.0.0.1(TCP)。PostgreSQL 默认 local 认证是 peer 模式,应用进程用户(root/www-data)与库属主 srht 不同名,走 socket 会直接Peer authentication failed。migrate-on-upgrade=yes只在用官方包管理器/迁移工具管升级时开启;源码手工部署建议 no,升级走手工迁移,避免启动期意外改库。api-origin不配时按"web 端口 + 100"推导,但显式写出来能避免歧义(尤其反代/多网卡场景)。
3.2 [meta.sr.ht::api]:GraphQL 服务端预算
[meta.sr.ht::api]
max-complexity=200 # 单次查询复杂度上限(约等于返回字段数)
max-duration=3s # 单次查询处理时限
internal-ipnet=127.0.0.0/8,::1/128,10.0.0.0/8 # 允许内部认证(service-key 签名)的网段
internal-ipnet 是安全关键项:列出哪些来源网段可以用内部签名直接调 API。必须只含你的服务间网络,绝不能放公网网段。多机部署时写各服务所在内网 CIDR 的并集。
3.3 [meta.sr.ht::settings]:注册行为
[meta.sr.ht::settings]
registration=yes # no 则关闭公开注册(仅管理员可建号)
onboarding-redirect=http://git.srht.local # 注册完成后的跳转
welcome-emails=no # 欢迎邮件(需 SMTP 与 cron 配套)
key-expiration-emails=no # PGP/SSH key 到期提醒
3.4 [meta.sr.ht::billing]:计费开关
[meta.sr.ht::billing]
enabled=no # yes 时启用 Stripe 计费流(需 stripe-* 三项 + 注册页首步)
联动行为实测:enabled=no 时访问 /register 会 302 直接跳 /register/step2(两步注册的第一步只在计费开启时出现);enabled=yes 则需要完整 Stripe 配置,否则注册流不可用。自托管建议保持 no。
四、[git.sr.ht]:代码托管的参数
[git.sr.ht]
origin=http://git.srht.local
api-origin=http://127.0.0.1:5101
debug-host=0.0.0.0
debug-port=5001
connection-string=postgresql://srht:q1w2e3r4@127.0.0.1/git
migrate-on-upgrade=no
webhooks=redis://127.0.0.1:6379/1
post-update-script=/usr/local/bin/git.sr.ht-update-hook
repos=/var/lib/git/
repos-index= # 代码搜索索引目录,留空禁用
s3-bucket= # 大文件对象存储(可选)
s3-prefix=
enable-dispatch=no # SSH 统一分发(需 sourcehut-ssh)
outgoing-domain= # 补件邮件出站域
[git.sr.ht::api]
max-complexity=200
max-duration=3s
internal-ipnet=127.0.0.0/8,::1/128,10.0.0.0/8
四个最容易踩的参数:
- repos:裸仓库根目录,实际仓库落在
repos/~<用户>/<仓库>。目录必须存在且对运行进程可写(实测建仓成功后生成/var/lib/git/~srhtadmin/demo-repo)。 - post-update-script:仓库 hooks 符号链接的源(pre-receive/update/post-update/post-receive 四个链接都指向它)。留空 = 建仓必败,实测症状是页面报
symlink /var/lib/git/~user/repo/hooks/pre-receive: no such file or directory。它必须指向编译产物git.sr.ht-update-hook。 - api-origin:git Web 层创建仓库等写操作全部转给本服务的 Go API 执行。不配时回退到 origin(Web 端口),而 Web 端口上并没有
/query路由,表现为 ConnectError/500。 - enable-dispatch:SSH 推送链路的开关。最小集关掉(HTTP clone 照常可用);要开 push 需部署 sourcehut-ssh 分发器与授权链。
五、[mail]、[webhooks]、[objects]:辅助节
5.1 [mail](每服务都要有一份)
[mail]
smtp-host= # 空 = 不发信(注册欢迎邮件、通知邮件静默失败但不阻塞注册)
smtp-port=587
smtp-from=no-reply@srht.local
smtp-encryption=starttls # starttls | tls | insecure
smtp-auth=none # plain | none
smtp-user=
smtp-password=
error-to= # 应用异常告警邮箱
error-from=
pgp-privkey= # 出站邮件签名(可选)
pgp-pubkey=
pgp-key-id=
最小集用 smtp-host= 空值即可让站点工作;一旦要发信,smtp-auth=plain 时 user/password 必填。
5.2 [webhooks]
[webhooks]
private-key=<base64,sr.ht-keygen webhook>
Ed25519 签名密钥:服务端持私钥,所有 webhook 载荷用它签名;消费方拿对应的 Public key 验签。全站一致可简化下游验签。
5.3 [objects](可选,S3 兼容存储)
[objects]
s3-upstream=
s3-access-key=
s3-secret-key=
用于头像、构建工件等对象存储;全部留空时相关功能退化(头像不可上传等),最小集可忽略。
六、配置类故障速查表(实测沉淀)
| # | 症状(原文回显) | 根因 | 修法 |
|---|---|---|---|
| 1 | Exception: Unknown redis connection URL scheme | redis-host 写成裸 127.0.0.1:6379 | 改 redis://127.0.0.1:6379/0 |
| 2 | FATAL: Peer authentication failed for user "srht" | connection-string 走 socket + peer 认证 | 改走 TCP:@127.0.0.1 |
| 3 | symlink .../hooks/pre-receive: no such file or directory | post-update-script 留空 | 指向 /usr/local/bin/git.sr.ht-update-hook |
| 4 | httpx.ConnectError: [Errno 111] Connection refused(建仓 500) | git.sr.ht 未配 api-origin,回退到 web 端口 | 补 api-origin=http://127.0.0.1:5101 |
| 5 | 在 meta 已登录,git 站仍是未登录 | 用 IP 访问,cookie 域(global-domain)对不上 | 用域名访问;核对 global-domain 与 origin 同域 |
| 6 | TypeWarning/TypeError: unsupported operand type(s) for 'in': 'str' and 'EnumMeta'(建仓 500,validation.py) | Python 3.10 的枚举 in 语义限制(上游按 3.12 开发) | 按 3.12+ 部署,或给 srht/validation.py 打兼容补丁 |
| 7 | This username is not available(注册 admin) | admin 在上游 username_blacklist 硬编码保留名 | 换非保留用户名(如 srhtadmin) |
| 8 | fatal: detected dubious ownership in repository(HTTP clone 500) | 仓库属主与 fcgiwrap 运行身份不一致 | git config --system --add safe.directory "*" |
| 9 | ModuleNotFoundError: No module named 'metasrht.graphql' | sdist 未带 codegen 产物 | ariadne-codegen 生成后重装(见安装篇 3.3) |
七、改配置之后:生效路径
| 改了什么 | 谁在读 | 生效动作 |
|---|---|---|
| [sr.ht] 公共节、connection-string、origin | Python web | 重启对应 *.service(web) |
| [xx::api]、internal-ipnet、api-origin | Go api | 重启对应 *-api.service |
| post-update-script、repos | Go api(建仓时) | 重启 git.sr.ht-api |
| [mail] | Python web + worker | 重启 web 与 webhook worker |
| redis-host | 两层都读 | web 与 api 都要重启 |
| nginx 配置 | nginx | nginx -t && systemctl reload nginx |
原则:web 与 api 是两个进程、两个密钥消费者,别只重启一半。配置错误一般不会让进程退出(懒加载),首次触发对应功能才炸,所以改完配置建议把关键路径(注册、建仓、clone)各点一遍。
八、生产加固清单
environment=production(关闭 debug 静态路径与非生产横幅)。registration按需收紧;开启[meta.sr.ht::api]复杂度/时限预算的监控。internal-ipnet精确到服务网段;service-key/network-key/webhook key 三把密钥轮换流程先演练。- PostgreSQL 连接串强制 TLS(
sslmode=require起步),应用账号最小授权(只授业务库)。 - HTTPS 全站(origin 写 https,反代终结 TLS),cookie 才能加 Secure 语义。
系列其余篇目:《Sourcehut 介绍与选型指南》《Sourcehut 0.88.9 + git.sr.ht 0.102.8 Ubuntu 22.04 安装指南》《Sourcehut 常用命令与运维详解》。
参考资料
- 各服务 config.example.ini(随版本自带,权威参数清单):meta.sr.ht-0.88.9 / git.sr.ht-0.102.8 源码包
- 官方自托管文档:https://man.sr.ht/pages/install.md
- core.sr.ht 配置加载实现:srht/config.py(git.sr.ht/~sircmpwn/core.sr.ht,tag 0.84.10)