SCM-Manager 3.12.2 配置参数详解
逐层拆解 SCM-Manager 3.12.2 三级配置体系:/etc/default/scm-server 启动层堆参数、/etc/scm/config.yml 与 /opt 路径硬链接同源的服务层全参数、/api/v2/config 应用层默认值,附堆限制、端口、DEBUG 日志三组改参数实测闭环与 forceBaseUrl 307 全站重定向排障实录及生产配置模板。
SCM-Manager 3.12.2 配置参数详解
本文基于 Ubuntu 22.04.5 LTS + SCM-Manager 3.12.2 实测环境,逐层拆解配置体系:启动层 /etc/default/scm-server、服务层 /etc/scm/config.yml(与 /opt/scm-server/conf/config.yml 为同一文件)、应用层 Web/REST 配置,并给出三组"改参数→重启→验证"实测闭环与一个 forceBaseUrl 引发的 307 全站重定向排障实录。安装背景见《SCM-Manager 3.12.2 Ubuntu 22.04 安装指南》,选型背景见《SCM-Manager 介绍与选型指南》。
一、配置体系总览
SCM-Manager 3.12.2 的配置分三层,权属与生效方式实测如下:
| 层级 | 路径 | 载体 | 生效方式 |
|---|---|---|---|
| 启动层(JVM/进程) | /etc/default/scm-server | shell 环境变量 | 重启服务 |
| 服务层(HTTP/日志/工作线程) | /etc/scm/config.yml | YAML | 重启服务 |
| 应用层(业务行为) | Web 管理界面 / REST /api/v2/config 等 | SQLite(/var/lib/scm/scm.db) | 保存即时生效 |
两点实测结论先行:
/etc/scm/config.yml与/opt/scm-server/conf/config.yml是同一个文件:实测两路径stat -c "%i"均为 inode3672632,编辑任意一份内容同步变化(我们 sed 修改/opt路径后,/etc路径 grep 立即看到相同值,重启后监听端口随之改变)。该文件属主root:scm、权限640,非 root 编辑需相应权限;- 服务层文件改错不会导致服务崩溃起不来——YAML 解析失败时启动日志会打印解析异常并退出,
journalctl -u scm-server可定位(实测环境未触发,此为官方文档 Troubleshooting 指引路径)。
二、启动层:/etc/default/scm-server
deb 包安装的默认内容(实测节选,许可头略):
# force jvm path
# JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64"
# increase memory
# EXTRA_JVM_ARGUMENTS="$EXTRA_JVM_ARGUMENTS -Xms1g -Xmx1g"
# pass extra jvm arguments
EXTRA_JVM_ARGUMENTS="$EXTRA_JVM_ARGUMENTS"
参数说明:
JAVA_HOME:默认注释。3.12.2 需要 Java 17,deb 依赖已装 OpenJDK 17(实测java -version为 17.0.20.1);系统存在多版本 JDK 时在此强制指向 17 的安装目录;EXTRA_JVM_ARGUMENTS:追加给 JVM 的参数,默认堆未显式限制(JVM 自行按物理内存 1/4 取默认上限)。
2.1 实测闭环:限制堆为 256MB
生产建议显式控堆(512MB 内可稳定承载中小团队,与选型篇资源口径一致)。实测过程与回显:
# cp /etc/default/scm-server /etc/default/scm-server.orig
# echo "EXTRA_JVM_ARGUMENTS=\"-Xms128m -Xmx256m\"" >> /etc/default/scm-server
# tail -2 /etc/default/scm-server
EXTRA_JVM_ARGUMENTS="$EXTRA_JVM_ARGUMENTS"
EXTRA_JVM_ARGUMENTS="-Xms128m -Xmx256m"
# systemctl restart scm-server && sleep 14
# ps aux | grep -o "\-Xms128m -Xmx256m" | head -1
-Xms128m -Xmx256m
# systemctl status scm-server --no-pager | grep -E "Memory|Active"
Active: active (running) since Wed 2026-10-28 02:04:56 UTC; 14s ago
Memory: 340.2M
结论:-Xms128m -Xmx256m 经 scm-server 启动脚本透传至 Java 进程(ps 实证),进程 RSS 340.2M(堆 256M + 元空间与堆外)。未控堆时实测 RSS 为 284M~420M 波动(默认堆上限随宿主内存而定)。改堆必须重启服务,仅重载无效。
三、服务层:/etc/scm/config.yml 逐项
默认文件全文结构(3.12.2 实测,注释保留):
addressBinding: 0.0.0.0
port: 8080
contextPath: /scm
forwardHeadersEnabled: false
httpHeaderSize: 16384
https:
keyStorePath: ""
keyStorePassword: secret
keyStoreType: PKCS12
sslPort: 8443
redirectHttpToHttps: false
tempDir: /var/cache/scm/work
log:
logDir: /var/log/scm
rootLevel: WARN
enableFileAppender: true
enableConsoleAppender: false
logger:
sonia.scm: INFO
com.cloudogu.scm: INFO
webapp:
workDir:
homeDir: /var/lib/scm
cache:
dataFile:
enabled: true
store:
enabled: true
endlessJwt: false
asyncThreads: 4
maxAsyncAbortSeconds: 60
centralWorkQueue:
workers: 4
workingCopyPoolStrategy: sonia.scm.repository.work.SimpleCachingWorkingCopyPool
workingCopyPoolSize: 5
3.1 HTTP 服务段
| 参数 | 默认值 | 说明 |
|---|---|---|
addressBinding | 0.0.0.0 | 监听地址,全部网卡;内网限定场景可绑具体网卡 IP |
port | 8080 | HTTP 端口 |
contextPath | /scm | Web 上下文路径,Web 入口与 API 前缀均受其影响 |
forwardHeadersEnabled | false | 是否信任反向代理的 X-Forwarded-For/Proto/Host 头,置于 Nginx 之后时改为 true |
httpHeaderSize | 16384 | HTTP 头最大字节数,注释说明为 Mercurial 场景调大 |
3.2 实测闭环:修改监听端口
# cp /etc/scm/config.yml /etc/scm/config.yml.orig
# sed -i "s/^port: 8080/port: 8090/" /etc/scm/config.yml && grep -n "^port:" /etc/scm/config.yml
20:port: 8090
# systemctl restart scm-server && sleep 14
# curl -s -o /dev/null -w "port8090:%{http_code}\n" http://localhost:8090/scm/
port8090:200
# curl -s -o /dev/null -w "port8080:%{http_code}\n" --max-time 3 http://localhost:8080/scm/
port8080:000
端口修改重启后生效(8090 返回 200,8080 停止响应)。验证完毕恢复为 8080(实测恢复后 200)。
3.3 HTTPS 段
| 参数 | 默认值 | 说明 |
|---|---|---|
https.keyStorePath | "" | PKCS12 密钥库路径;留空则整段 SSL 配置不生效(注释原文:ssl is only evaluated if key store path is set) |
https.keyStorePassword | secret | 密钥库口令 |
https.keyStoreType | PKCS12 | 密钥库类型 |
https.sslPort | 8443 | HTTPS 端口 |
https.redirectHttpToHttps | false | 是否将 HTTP 请求重定向到 HTTPS |
启用内置 HTTPS 的最小操作:用 keytool -genkeypair 生成 PKCS12 库,填 keyStorePath 与口令后重启。生产更常见做法是保持 HTTP + 前置 Nginx 做 TLS 终结,此时记得把 forwardHeadersEnabled 改为 true。
3.4 日志段
| 参数 | 默认值 | 说明 |
|---|---|---|
log.logDir | /var/log/scm | 日志目录(deb 包默认,主日志文件 scm-manager.log) |
log.rootLevel | WARN | 全局日志级别 |
log.enableFileAppender | true | 写文件 |
log.enableConsoleAppender | false | 写标准输出(journalctl 场景可开) |
log.logger.sonia.scm | INFO | 主程序日志级别 |
log.logger.com.cloudogu.scm | INFO | Cloudogu 插件日志级别 |
3.5 实测闭环:DEBUG 日志
# wc -l < /var/log/scm/scm-manager.log
373
# sed -i "s/^ rootLevel: WARN/ rootLevel: DEBUG/" /etc/scm/config.yml
# sed -i "s/^ sonia.scm: INFO/ sonia.scm: DEBUG/" /etc/scm/config.yml
# systemctl restart scm-server && sleep 14
# tail -3 /var/log/scm/scm-manager.log | cut -c1-90
2026-10-28 02:06:03.621 [qtp935044096-21] [ ] DEBUG org.hibernate.validator.internal.engine.ValidatorFa
2026-10-28 02:06:03.621 [qtp935044096-21] [ ] DEBUG org.jboss.resteasy.plugins.validation.i18n - RESTEASY
2026-10-28 02:06:03.637 [qtp935044096-21] [DWVZJ1vvq1] DEBUG sonia.scm.template.MustacheTemplate - render mustach
rootLevel: DEBUG 生效后,第三方框架(hibernate-validator、RESTEasy)DEBUG 行大量出现,日志体积显著增长,仅建议临时排障使用,排障后恢复 WARN/INFO 并重启。
3.6 webapp 运行段
| 参数 | 默认值 | 说明 |
|---|---|---|
webapp.homeDir | /var/lib/scm | 数据主目录(仓库、元数据、插件) |
webapp.workDir | 空(用 Java 默认临时目录) | 内部进程工作目录 |
webapp.endlessJwt | false | 会话 JWT 永不过期;注释明确警告有安全风险,保持 false |
webapp.asyncThreads | 4 | 异步线程数 |
webapp.maxAsyncAbortSeconds | 60 | 异步任务中止等待上限 |
webapp.centralWorkQueue.workers | 4 | 中央工作队列并发 worker 数 |
webapp.workingCopyPoolStrategy | SimpleCachingWorkingCopyPool | 工作副本池策略,另一可选值 NoneCachingWorkingCopyPool(不缓存) |
webapp.workingCopyPoolSize | 5 | 缓存的工作副本数量 |
tempDir: /var/cache/scm/work 为 Web 应用临时目录(卸载时的 not empty 警告即来自这里)。cache.dataFile/store.enabled 为内置缓存开关,保持默认。
四、应用层:Web 管理与 REST 配置
4.1 全局配置项与实测默认值
应用层配置经 Web 界面(管理 → Settings)或 REST GET/PUT /api/v2/config 管理。3.12.2 全新实例默认值实测(admin 会话):
| 配置项 | 实测默认值 | 说明 |
|---|---|---|
baseUrl | null | 对外访问基准地址,建议部署后必配 |
forceBaseUrl | false | 开启后强制所有请求重定向到 baseUrl |
realmDescription | "SONIA :: SCM Manager" | 登录页描述文案 |
anonymousAccessEnabled | false | 匿名访问总开关 |
anonymousMode | (随开关) | 匿名模式细分 |
loginAttemptLimit | -1 | 登录失败次数上限(-1 不限制),生产建议设 10~30 |
loginAttemptLimitTimeout | 300 | 超限锁定秒数 |
jwtExpirationInH | (数值型) | 会话令牌有效期(小时) |
enabledXsrfProtection | (布尔) | XSRF 防护开关 |
enabledApiKeys | (布尔) | API Key 功能开关 |
mailDomainName | "scm-manager.local" | 默认邮箱域补全 |
proxyServer/proxyPort/proxyUser/proxyPassword/enableProxy/proxyExcludes | 关闭 | 出网代理(插件中心拉取走此配置) |
namespaceStrategy | 空 | 仓库命名空间策略 |
emergencyContacts | 空 | 紧急联系人(告警用) |
4.2 实测闭环:PUT 修改 baseUrl(含 307 排障实录)
# curl -s -b /tmp/cookies.txt -X PUT http://localhost:8080/scm/api/v2/config \
> -H "Content-Type: application/vnd.scmm-config+json;v=2" \
> -d '{"baseUrl":"http://192.168.1.50:8080/scm","forceBaseUrl":true,"realmDescription":"SONIA :: SCM Manager","anonymousAccessEnabled":false,"loginAttemptLimit":-1,"loginAttemptLimitTimeout":300,"mailDomainName":"scm-manager.local", ... }' \
> -o /dev/null -w "PUT:%{http_code}\n"
PUT:204
# curl -s -b /tmp/cookies.txt http://localhost:8080/scm/api/v2/config | python3 -m json.tool | grep -E "baseUrl"
307
排障实录:把 forceBaseUrl 与一个不可达的 baseUrl(192.168.1.50 为示例假地址)同时保存后,本机全部请求立刻开始返回 307 重定向——服务把所有流量强制跳往 baseUrl,包括正在使用的管理会话本身。Web 界面同样会跳向错误地址,且配置存在 SQLite 内、不走 config.yml,改文件无效。实测修复路径(curl --connect-to 将假地址映射回本机后重新登录并 PUT 恢复):
# curl -s -L -c /tmp/ck2 -X POST --connect-to 192.168.1.50:8080:127.0.0.1:8080 \
> http://192.168.1.50:8080/scm/api/v2/auth/access_token -H "Content-Type: application/json" \
> -d '{"cookie":true,"grant_type":"password","username":"scmadmin","password":"q1w2e3r4"}' -o /dev/null -w "login:%{http_code}\n"
login:204
# curl -s -b /tmp/ck2 --connect-to 192.168.1.50:8080:127.0.0.1:8080 -X PUT \
> http://192.168.1.50:8080/scm/api/v2/config -H "Content-Type: application/vnd.scmm-config+json;v=2" \
> -d '{"baseUrl":null,"forceBaseUrl":false, ...}' -o /dev/null -w "PUT_restore:%{http_code}\n"
PUT_restore:204
# curl -s -b /tmp/ck2 --connect-to 192.168.1.50:8080:127.0.0.1:8080 -L http://192.168.1.50:8080/scm/api/v2/config | grep -o '"baseUrl":[^,]*'
"baseUrl":null
经验结论:baseUrl 填真实对外地址再开 forceBaseUrl;两者不同时改;若已中招,--connect-to(或直接给服务器加临时 IP)是唯一无需动数据库的恢复手段。PUT 时服务端接受不带 If-Match 乐观锁头的请求(实测 204),但标准用法建议先 GET /api/v2/config 取 ETag 头一并提交,避免并发覆盖。
4.3 仓库级与其他配置入口
- 仓库创建与配置:
POST/PUT /api/v2/repositories/,类型git/hg/svn; - 用户/组/权限:
/api/v2/users、/api/v2/groups、/api/v2/permissions(命令化操作见运维篇); - 插件:
/api/v2/plugins/available与/installed; - 认证配置(LDAP 等):
/api/v2/config/authentications(装对应插件后出现)。
五、生产配置模板
中小团队(≤50 人)单机推荐基线,全部经本文实测项组合:
# /etc/default/scm-server —— 启动层
JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64"
EXTRA_JVM_ARGUMENTS="-Xms256m -Xmx512m"
# /etc/scm/config.yml —— 服务层(与 /opt/scm-server/conf/config.yml 同一文件)
addressBinding: 0.0.0.0
port: 8080
contextPath: /scm
forwardHeadersEnabled: true # 前置 Nginx 时开启
httpHeaderSize: 16384
https:
keyStorePath: "" # TLS 交给 Nginx,内置 SSL 不启用
keyStorePassword: secret
keyStoreType: PKCS12
sslPort: 8443
redirectHttpToHttps: false
tempDir: /var/cache/scm/work
log:
logDir: /var/log/scm
rootLevel: WARN
enableFileAppender: true
enableConsoleAppender: false
logger:
sonia.scm: INFO
com.cloudogu.scm: INFO
webapp:
homeDir: /var/lib/scm
endlessJwt: false # 安全红线,保持 false
asyncThreads: 4
maxAsyncAbortSeconds: 60
centralWorkQueue:
workers: 4
workingCopyPoolStrategy: sonia.scm.repository.work.SimpleCachingWorkingCopyPool
workingCopyPoolSize: 5
应用层(Web Settings 或 REST):baseUrl 设为对外真实地址(如 https://scm.example.com/scm)并确认可达后再开 forceBaseUrl;loginAttemptLimit 设 10、loginAttemptLimitTimeout 保持 300;anonymousAccessEnabled 保持 false。
六、配置排障清单
- 改了配置不生效:启动层与服务层改动均需
systemctl restart scm-server;确认编辑的是硬链接同一份/etc/scm/config.yml(改/opt/scm-server/conf/下的等效); - 服务起不来:
journalctl -u scm-server --no-pager+/var/log/scm/scm-manager.log双路取证;YAML 缩进错误(config.yml 段下必须两空格层级)与/etc/default/scm-server引号不配对是高频原因; - 全站 307:
forceBaseUrl+ 错误 baseUrl 所致,见 4.2 排障实录; - JWT 频繁过期:按需调
jwtExpirationInH,严禁开endlessJwt; - 端口被占:
port改动后与既有进程冲突时启动失败,ss -tlnp | grep <port>先行确认(命令+预期结果:输出含LISTEN行即为被占)。