GitBucket 4.48.0 配置参数详解

把 GitBucket 4.48.0 的配置拆成启动参数、JVM 系统属性、环境变量、gitbucket.conf 与 database.conf 五类载体,逐项给出默认值、作用域与实测结论,覆盖 H2→MySQL/PostgreSQL 切换、LDAP/OIDC、SMTP、反向代理与 base URL、JVM 内存与 GC、日志,含端口/数据目录/base_url 优先级与引号陷阱的真实回显。

GitBucketGitBucket配置版本控制2026/10/27

目标:把 GitBucket 4.48.0 的配置拆成启动参数、系统属性、环境变量、gitbucket.conf、database.conf 五类载体,逐项给出默认值、作用域与实测结论,覆盖数据库切换、LDAP/OIDC、SMTP、反向代理与 base URL、JVM 内存与 GC、日志。

GitBucket 4.48.0 配置参数详解

GitBucket 的配置分散在四个地方:JVM 启动参数(--port 这类)、JVM 系统属性(-Dgitbucket.xxx)、环境变量(GITBUCKET_XXX)、以及 $GITBUCKET_HOME 下的 gitbucket.conf 与 database.conf。它们不是一套统一的优先级,而是两条不同的优先级链:启动参数类是「命令行 > 环境变量 > 系统属性」,业务设置类是「系统属性 > 环境变量 > 配置文件」。搞混这两条链,就会出现「明明写了配置却不生效」的排查地狱。

本文所有回显来自 2026-10-27 在 GitBucket 4.48.0 部署实例上的实测,实例为 Ubuntu 22.04 + OpenJDK 17.0.20.1 + systemd 托管,数据目录 /opt/gitbucket/data,监听 8080;对比实验在 8091–8104 端口上以独立数据目录启动,互不干扰。

一、配置载体与优先级

1.1 五类配置载体

载体形式生效范围典型用途
Jetty 启动参数--port=8080、--prefix=/gitbucket进程级,只影响 Web 监听端口、监听地址、HTTPS、URL 前缀
JVM 系统属性-Dgitbucket.port=8080、-Dgitbucket.base_url=...进程级与命令行同名的兜底,或业务设置
环境变量GITBUCKET_PORT=8080、GITBUCKET_BASE_URL=...进程级systemd EnvironmentFile、批量部署
gitbucket.conf$GITBUCKET_HOME/gitbucket.conf(HOCON 文件)实例级,业务设置默认值站点 URL、SMTP、LDAP、OIDC、上传限制
database.conf$GITBUCKET_HOME/database.conf(HOCON 文件)实例级,仅数据库数据库 URL、账号、连接池

1.2 两条优先级链(实测)

启动参数类(端口为例):

# 只给环境变量
GITBUCKET_PORT=8098 java -Dgitbucket.home=/tmp/hG -jar gitbucket.war
# ss -ltn | grep 8098 → LISTEN(环境变量生效)

# 环境变量 + 命令行
GITBUCKET_PORT=8098 java -Dgitbucket.home=/tmp/hG -jar gitbucket.war --port=8099
# ss -ltn → 只有 8099 在听(命令行覆盖环境变量)

# 环境变量 + 系统属性
GITBUCKET_PORT=8098 java -Dgitbucket.home=/tmp/hG -Dgitbucket.port=8100 -jar gitbucket.war
# ss -ltn → 只有 8098 在听(环境变量覆盖系统属性)

实测三次监听的端口分别是 8098 / 8099 / 8098,结论:命令行 > 环境变量 > -Dgitbucket.port。系统属性在这一链里排最后,和很多 Java 程序的直觉相反。

业务设置类(base_url 为例):

# 只在 gitbucket.conf 写 base_url = https://gitbucket.example.com
curl -D- -d "userName=root&password=root&hash=" http://127.0.0.1:8093/signin | grep -i Location
# Location: https://gitbucket.example.com/;jsessionid=node0hmn...

# 再加环境变量 GITBUCKET_BASE_URL=http://env.example.com
# Location: http://env.example.com/;jsessionid=node0q6h...

# 再加系统属性 -Dgitbucket.base_url=http://sys.example.com
# Location: http://sys.example.com/;jsessionid=node011x...

结论:系统属性 > 环境变量 > gitbucket.conf。这一链由 ConfigUtil.getConfigValue(key) 实现:先读系统属性 gitbucket.<key>,再读环境变量 GITBUCKET_<KEY 大写、点号转下划线>,都没有才回落到配置文件。

💡 技术拓展:ConfigUtil 的键转换是机械式大写替换——base_url → GITBUCKET_BASE_URL,useSMTP → GITBUCKET_USESMTP(不是 GITBUCKET_USE_SMTP),smtp.host → GITBUCKET_SMTP_HOST(点号变下划线,但驼峰不拆)。写环境变量前先用 -D 实测一次,比猜命名规则可靠。

1.3 一句话记忆法

  • 想让进程换端口/换前缀:改命令行或环境变量,别指望 -D。
  • 想让站点行为变化(URL、邮件、认证):改 gitbucket.conf,需要临时覆盖就用环境变量或 -D。

二、GITBUCKET_HOME 的解析顺序

所有数据、配置、插件都挂在 GITBUCKET_HOME 下。它的解析顺序实测为:

  1. JVM 系统属性 -Dgitbucket.home;
  2. 环境变量 GITBUCKET_HOME;
  3. 默认 ~/.gitbucket。

三次实测(看 Hikari 建池时的 JDBC URL 即可确认实际目录):

# 同时给系统属性与环境变量
GITBUCKET_HOME=/tmp/hB java -Dgitbucket.home=/tmp/hA -jar gitbucket.war --port=8091
# 13:01:27 [main] INFO HikariPool-1 - Added connection conn0: url=jdbc:h2:/tmp/hA/data user=SA
# → 系统属性优先

# 只给环境变量
GITBUCKET_HOME=/tmp/hB java -jar gitbucket.war --port=8092
# 13:01:38 [main] INFO HikariPool-1 - Added connection conn0: url=jdbc:h2:/tmp/hB/data user=SA
# → 环境变量生效

# 两者都不给
java -jar gitbucket.war --port=8102
# 13:07:40 [main] INFO HikariPool-1 - Added connection conn0: url=jdbc:h2:/root/.gitbucket/data user=SA
# → 默认目录是 ~/.gitbucket,不是 ~/gitbucket

~/.gitbucket 这个默认值容易踩坑:以 systemd 的 User=gitbucket 运行且没有设环境变量时,数据会落到 /opt/gitbucket/.gitbucket(系统用户 home)而不是你以为的 /opt/gitbucket/data。安装时务必显式指定。

目录结构(/opt/gitbucket/data 实测):

/opt/gitbucket/data/
├── activity.log          # 活动流水(JSON Lines)
├── data.mv.db            # H2 数据库文件
├── database.conf         # 数据库连接配置(首次启动自动生成)
├── gist/                 # Gist 数据
├── plugins/              # 插件 jar(首次启动自动解包 4 个内置插件)
├── repositories/         # 裸 git 仓库
├── tmp/                  # Jetty 临时目录
└── gitbucket.conf        # 业务设置默认值(手工创建,默认不存在)

gitbucket.conf 默认不存在,需要自己创建;database.conf 在第一次启动时自动生成。

三、gitbucket.conf 的语法与全量键

3.1 语法:HOCON 外壳,字符串取值不带引号

gitbucket.conf 是 HOCON 文件,但取值不以 Typesafe Config 的方式解析,而是按原始字符串交给业务层。最直接的后果:值加了引号会连引号一起被当成内容。

实测:写 base_url = "https://gitbucket.example.com"(带引号)后,登录直接 500:

13:02:06.937 [qtp20132171-19] ERROR g.c.controller.PreProcessController - Catch unhandled error in request: Request(POST http://127.0.0.1:8093/signin)
java.net.URISyntaxException: Illegal character in scheme name at index 0: "https://gitbucket.example.com"
	at java.base/java.net.URI$Parser.fail(URI.java:2976)
	at gitbucket.core.controller.Context.<init>(ControllerBase.scala:354)
	at gitbucket.core.controller.ControllerBase.context(ControllerBase.scala:100)
	at gitbucket.core.controller.PreProcessControllerBase.$anonfun$$init$$5(PreProcessController.scala:32)

把引号去掉后立刻正常:

base_url = https://gitbucket.example.com
curl -D- -d "userName=root&password=root&hash=" http://127.0.0.1:8093/signin | grep -i Location
# Location: https://gitbucket.example.com/;jsessionid=node0hmnbu0u4sh6v1ly1ww9nx0wsc0.node0

⚠️ 与 database.conf 对比:database.conf 是真正的 Typesafe Config 解析,必须带引号(默认生成的文件就是 url = "jdbc:h2:${DatabaseHome}")。两个文件同目录、同为 HOCON,引号规则却相反,这是 GitBucket 4.48.0 最容易踩的坑之一。

3.2 常用键与默认值

下表的默认值取自一个全新数据目录的实例(首启后打开 Administration → System settings 读取表单值),未改任何配置。

键默认值说明
base_url空站点对外根 URL,反代/HTTPS 场景必须写,影响重定向、webhook、邮件链接
information空登录页公告(支持 Markdown)
allow_account_registrationfalse是否允许自助注册
allow_reset_passwordfalse是否允许「忘记密码」重置
reset_password_token_expiration10重置令牌有效期(分钟)
allow_anonymous_accesstrue匿名可读公开仓库
is_create_repository_option_publictrue新建仓库时「公开」选项默认勾选
allow_create_repository_by_clonefalse允许从远程克隆创建仓库
repository_operation_create/delete/rename/transfer/fork均 true允许普通用户执行的仓库操作
limitVisible_repositories(表单名 basicBehavior.limitVisibleRepositories)false仅展示有权限的仓库
compare_no_check_by_defaultfalse比较页默认不跑 CI 检查
gravatarfalse使用 Gravatar 头像
notificationfalse开启站内通知(需同时配 SMTP)
showMailAddressfalse公开显示邮箱
default_branchmain新建仓库默认分支名
show_full_namefalse页面展示用户全名
upload.maxFileSize3145728普通上传上限(字节,3 MB)
upload.timeout30000普通上传超时(ms)
upload.largeMaxFileSize3145728大文件上传上限(字节)
upload.largeTimeout30000大文件上传超时(ms)
repository_viewer_max_files0单次展示的变更文件数上限,0 = 不限
repository_viewer_max_diff_files100差异页最多渲染的文件数
repository_viewer_max_diff_lines1000差异页最多渲染的行数
webhook.block_private_addressfalse禁止 webhook 指向内网地址(SSRF 防护,生产建议开)
webhook.whitelist空webhook 地址白名单(逗号分隔)
skinName空皮肤名,空为默认
userDefinedCss空自定义 CSS

upload.maxFileSize 的 3145728 字节(3 MB)在 4.48.0 默认值下偏小,上传 release 附件或大 patch 时很容易触发 413,生产建议按 104857600(100 MB)调大。

3.3 键名与后台表单的对应关系

后台表单的字段名是嵌套结构(smtp.host、ldap.baseDN、webhook.blockPrivateAddress),而配置文件里既有平铺键也有嵌套键。实测确认的对应关系:

后台表单字段配置文件键
baseUrlbase_url
basicBehavior.allowAnonymousAccessallow_anonymous_access
basicBehavior.repositoryOperation.createrepository_operation_create
smtp.hostsmtp.host
ldap.bindPasswordldap.bind_password
oidc.clientIDoidc.client_id
webhook.blockPrivateAddresswebhook.block_private_address
ssh.enabledssh

规律:配置文件里用蛇形命名,后台表单用驼峰,两者不是逐字对应。写配置文件时以本文表格的键名为准。

3.4 配置文件值的可见性验证

在全新实例的 gitbucket.conf 写入一组值后,打开后台能直接看到回填结果(说明配置文件确实作为默认值被读取):

useSMTP = true
smtp.host = 127.0.0.1
smtp.port = 2525
smtp.user = noreply@example.com
smtp.from_address = noreply@example.com
smtp.from_name = GitBucket Notify
curl -s -b e.txt http://127.0.0.1:8096/admin/system | grep -E 'id="(smtpHost|smtpPort|fromAddress|fromName)"'

表单回显(节选):

smtpHost = 127.0.0.1
smtpPort = 2525
fromAddress = noreply@example.com
fromName = GitBucket Notify
useSMTP checked: True

⚠️ 实测真问题:后台「System settings」页面的保存接口 POST /admin/system,用脚本按表单字段原样提交时返回 400(无响应体、无异常日志),只有浏览器端 JS 组装完整字段才能保存成功。自动化部署不要试图用 curl 改后台设置,直接写 gitbucket.conf + 环境变量。

四、数据库配置(database.conf)

4.1 文件与键

database.conf 首次启动自动生成,内容逐字如下:

db {
  url = "jdbc:h2:${DatabaseHome}"
  user = "sa"
  password = "sa"
#  connectionTimeout = 30000
#  idleTimeout = 600000
#  maxLifetime = 1800000
#  minimumIdle = 10
#  maximumPoolSize = 10
}

${DatabaseHome} 是 GitBucket 内置变量,解析为 $GITBUCKET_HOME/data。可用键:

键默认值说明
db.urljdbc:h2:${DatabaseHome}JDBC URL
db.user / db.passwordsa / sa数据库账号
db.jdbcDriver按 URL 推断驱动类名,一般不用写
db.slickDriver按 URL 推断Slick profile
db.liquiDriver按 URL 推断Liquibase 方言
db.connectionTimeout30000取连接超时(ms)
db.idleTimeout600000空闲连接回收(ms)
db.maxLifetime1800000连接最大存活(ms)
db.minimumIdle10最小空闲连接数
db.maximumPoolSize10最大连接数

内置驱动(war 内 WEB-INF/lib):h2-2.5.250.jar、postgresql-42.7.13.jar、mariadb-java-client-2.7.15.jar。没有 mysql-connector-j,MySQL 连接靠 MariaDB 驱动兼 容 jdbc:mysql:// 前缀(Connector/J 2.x 支持该前缀,3.x 需要 permitMysqlScheme)。

4.2 切 PostgreSQL(实测)

sudo apt install -y postgresql-15
sudo -u postgres psql -c "CREATE USER gitbucket WITH PASSWORD 'gb_pg_2026';"
sudo -u postgres psql -c "CREATE DATABASE gitbucket OWNER gitbucket;"
db {
  url = "jdbc:postgresql://127.0.0.1:5432/gitbucket"
  user = "gitbucket"
  password = "gb_pg_2026"
  maximumPoolSize = 10
}

重启后日志:

12:25:54.796 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
12:25:54.803 [main] WARN  c.z.hikari.util.DriverDataSource - Registered driver with driverClassName=org.postgresql.Driver2 was not found, trying direct instantiation.
12:25:55.103 [main] INFO  com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@2b4786dd

建表结果:

sudo -u postgres psql -d gitbucket -tAc "select count(*) from information_schema.tables where table_schema='public'"
# 43

43 张表(42 张业务表 + versions 之外的 Liquibase 辅助表随版本略有差异),说明 schema 迁移完成。

⚠️ 实测真问题:driverClassName=org.postgresql.Driver2 was not found 是 GitBucket 4.48.0 自己把驱动类名写成了 org.postgresql.Driver2(多了一个 2)。HikariCP 捕获异常后回落为直接实例化,连接仍能建立,但每次启动都会打一条 WARN。监控若把 WARN 计为故障,需要单独放行。

4.3 切 MySQL(配置说明,本环境无实例未实测)

db {
  url = "jdbc:mysql://127.0.0.1:3306/gitbucket?characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true"
  user = "gitbucket"
  password = "q1w2e3r4"
  maximumPoolSize = 10
}

注意点:

  • characterEncoding=UTF-8 必带,否则中文仓库名、issue 会乱码;
  • MySQL 端要 CREATE DATABASE gitbucket CHARACTER SET utf8mb4;
  • 驱动是 MariaDB 2.x,若遇到 Unknown database 之外的表征错误,先在 db.jdbcDriver 显式写 org.mariadb.jdbc.Driver 试。

4.4 H2 版本与迁移

war 内置 H2 2.5.250。从 4.42 及更早升级且继续用 H2 的实例,必须手工迁移 1.x → 2.x(导出 SQL → 改方言 → 导入),否则新版本启动即报 H2 语法/文件格式错误。切了 PostgreSQL/MySQL 的实例不受影响。

五、LDAP 认证

5.1 键与默认值

键默认值说明
ldap_authenticationfalse总开关
ldap.host空LDAP 服务地址
ldap.port空(389)端口
ldap.bindDN空绑定账号 DN
ldap.bind_password空绑定密码
ldap.baseDN空用户搜索基准 DN
ldap.username_attribute空(uid)登录名属性
ldap.fullname_attribute空(cn)全名属性
ldap.mail_attribute空(mail)邮箱属性
ldap.additional_filter_condition空附加过滤条件
ldap.tls / ldap.sslfalseStartTLS / LDAPS
ldap.keystore空LDAPS 信任库路径

5.2 实测

配置(base_url 与 LDAP 同文件):

ldap_authentication = true
ldap.host = 127.0.0.1
ldap.port = 389
ldap.bindDN = cn=admin,dc=example,dc=com
ldap.bind_password = ldappass
ldap.baseDN = ou=people,dc=example,dc=com
ldap.username_attribute = uid

后台表单回填确认配置已读取:

ldapHost = 127.0.0.1
ldapPort = 389
ldapBaseDN = ou=people,dc=example,dc=com
ldapAuthentication checked: True

本机 389 端口没有 LDAP 服务,用任意账号登录:

curl -s -o /dev/null -w "login=%{http_code} -> %{redirect_url}\n" \
  -d "userName=ldapuser&password=badpass&hash=" http://127.0.0.1:8097/signin
# login=302 -> http://127.0.0.1:8097/signin;jsessionid=node0rmya...

日志:

13:05:15.018 [qtp20132171-20] INFO  gitbucket.core.util.LDAPUtil$ - LDAPException: Unable to connect to server 127.0.0.1:389 (91) Connect Error
java.net.ConnectException: Connection refused
13:05:15.018 [qtp20132171-20] INFO  g.core.service.AccountService - LDAP error: System LDAP authentication failed.
13:05:15.489 [qtp20132171-16] INFO  g.core.service.AccountService - Failed to authenticate: ldapuser

结论:开启 LDAP 后所有登录都会先走 LDAP(包括本地 root),LDAP 不可达就一律失败。所以务必先留一个本地管理员账号、或准备好 LDAP 排障窗口,不要在远程 LDAP 没通的情况下打开开关然后重启。

⚠️ 提示:LDAP 错误只打到 INFO 级别、不带 HTTP 错误码(登录失败仍是 302 回登录页),只从浏览器看不出是「密码错」还是「LDAP 连不上」,排障必须看服务端日志。

六、OIDC / OAuth 登录

6.1 键与默认值

键默认值说明
oidc_authenticationfalse总开关
oidc.issuer空提供发现文档的 issuer URL
oidc.client_id空客户端 ID
oidc.client_secret空客户端密钥
oidc.jws_algorithm空(默认 RS256)ID Token 签名算法

6.2 实测

oidc_authentication = true
oidc.issuer = http://127.0.0.1:9999
oidc.client_id = gitbucket-client
oidc.client_secret = s3cr3t

登录页出现了入口:

curl -s http://127.0.0.1:8097/signin | grep -o -E "(/signin/oidc|Sign in with[^<]*)"
# /signin/oidc
# Sign in with OpenID Connect

后台表单回填:

oidcIssuer = http://127.0.0.1:9999
oidcClientID = gitbucket-client
oidcAuthentication checked: True

结论:OIDC 开关与 issuer 配置在登录页渲染阶段就生效,不需要等用户点击;issuer 地址不通时按钮仍在,点击才会报错。生产对接 Keycloak/Auth0 时,oidc.issuer 必须是带 https:// 且能被服务端访问到的 discovery 根地址。

七、邮件(SMTP)

7.1 键与默认值

键默认值说明
useSMTPfalse总开关,关闭时所有通知静默丢弃
smtp.host空SMTP 服务器
smtp.port空(25)端口
smtp.user空认证账号
smtp.password空认证密码
smtp.sslfalse直连 SSL(465)
smtp.starttlsfalseStartTLS(587)
smtp.from_address空发件地址
smtp.from_name空发件人显示名

7.2 实测:完整收发链路

起一个本地假 SMTP(监听 2525,打印每行命令),配置写入 gitbucket.conf,然后用后台「Test mail」接口发送:

curl -s -b e.txt -X POST \
  -d "smtp.host=127.0.0.1&smtp.port=2525&smtp.user=noreply@example.com&smtp.password=smtppass&smtp.ssl=false&smtp.starttls=false&smtp.fromAddress=noreply@example.com&smtp.fromName=GitBucket+Notify&testAddress=admin@example.com" \
  http://127.0.0.1:8096/admin/system/sendmail
# Test mail has been sent to: admin@example.com

SMTP 会话实录:

CMD|EHLO gb-b1
CMD|MAIL FROM:<noreply@example.com>
CMD|RCPT TO:<admin@example.com>
CMD|DATA
DATA|Date: Tue, 27 Oct 2026 13:04:50 +0000 (UTC)
DATA|From: GitBucket Notify <noreply@example.com>
DATA|To: admin@example.com
DATA|Message-ID: <822637135.1.1793106290562@gb-b1>
DATA|Subject: Test message from GitBucket
DATA|MIME-Version: 1.0
DATA|Content-Type: multipart/mixed;
DATA|	boundary="----=_Part_0_1261056815.1793106290493"
DATA|
DATA|------=_Part_0_1261056815.1793106290493
DATA|Content-Type: text/plain; charset=UTF-8
DATA|Content-Transfer-Encoding: 7bit
DATA|
DATA|This is a test message from GitBucket.
DATA|------=_Part_0_1261056815.1793106290493--
DATA|.
CMD|QUIT

结论:不需要真正发到外部邮箱,/admin/system/sendmail 用表单里提交的 SMTP 参数即时发信,是验证 SMTP 配置的最快方式。注意它不落库——只验证参数,不改保存的配置。

7.3 常见坑

  • useSMTP = false 时通知全部静默丢弃,日志无报错,表现为「有 issue 但没人收到邮件」;
  • 465 端口要 smtp.ssl = true 且 starttls = false;587 端口反过来;
  • smtp.from_address 必填,很多 SMTP 服务(如企业邮局)会校验发件人与认证账号一致;
  • 算术:notification = true 只是开启站内通知,邮件还需要 useSMTP = true 才算完整。

八、反向代理与 base URL

8.1 base_url 必须与外部访问地址一致

GitBucket 生成绝对链接(重定向、webhook payload、邮件里的链接、RSS)都用 base_url。反代到 HTTPS 域名时必须显式配置,否则用户会被重定向回 http://内网IP:8080。

base_url = https://git.example.com

实测生效表现(登录成功后 302 的目标即 base_url):

Location: https://gitbucket.example.com/;jsessionid=node0hmn...

8.2 反代到子路径:prefix + base_url 组合

--prefix=/gitbucket 让所有路由挂在子路径下,实测:

java -jar gitbucket.war --port=8094 --prefix=/gitbucket
curl -s -o /dev/null -w "prefix/signin=%{http_code} " http://127.0.0.1:8094/gitbucket/signin
curl -s -o /dev/null -w "root/signin=%{http_code}\n" http://127.0.0.1:8094/signin
# prefix/signin=200 root/signin=404

组合配置:

base_url = https://git.example.com/gitbucket

再加 --prefix=/gitbucket。两者路径必须一致,只配一个会出现「页面能开、静态资源和重定向全错」的半残状态。

8.3 反代要点

  • X-Forwarded-Proto https 必须透传,否则 GitBucket 认为自己是 http;
  • client_max_body_size 按 upload.maxFileSize 设置,默认 3 MB 的上传上限在反代层先被 1 MB 的 nginx 默认值拦住;
  • proxy_read_timeout 要覆盖大仓库 clone 时间;
  • HTTPS 由反代终结时,GitBucket 自身仍监听 http 即可,不必配 keystore。

8.4 SSH 的对外地址

SSH 若启用(ssh = true),要给客户端一个可连的地址:ssh.publicAddress.host / ssh.publicAddress.port。这两项与 base_url 无关,反代不会自动推导,必须单独配。

九、JVM 内存与 GC

9.1 参数位置

生产实例把 JVM 参数集中在 systemd 的环境变量文件里,改参数不动单元文件:

cat /etc/default/gitbucket
# JAVA_OPTS="-Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError"
# GITBUCKET_HOME=/opt/gitbucket/data
ExecStart=/bin/sh -c "exec /usr/bin/java $JAVA_OPTS -jar /opt/gitbucket/gitbucket.war --port=8080"

9.2 堆大小实测

  • -Xms512m -Xmx512m 固定堆,进程常驻内存 423 MB 左右(systemctl status 的 Memory: 423.8M);
  • 集群/多实例部署时按「实例数 × 512 MB」预留,另加 150–250 MB 的元空间与线程栈开销;
  • 堆不建议低于 256 MB:H2 建库 + 插件加载 + Liquibase 迁移会短时吃满小堆,表现为启动阶段频繁 Full GC 甚至 OutOfMemoryError: Metaspace。

jps -v 交叉验证:

6745 war -Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError

-XX:+ExitOnOutOfMemoryError 的用意是 OOM 时直接退出交给 systemd 重启,而不是留一个僵死但「还在监听」的进程。

9.3 GC 实测

4.48.0 在 JDK 17 上默认 G1。打开 GC 日志:

java -Xms256m -Xmx256m -Xlog:gc -jar gitbucket.war --port=8093
[0.004s][info][gc] Using G1
[0.917s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 21M->2M(256M) 3.917ms
[1.045s][info][gc] GC(1) Pause Young (Normal) (G1 Evacuation Pause) 46M->2M(256M) 1.842ms

启动阶段两次 Young GC 都在 4 ms 内,256 MB 堆启动无压力。内存更大的宿主可以把 -XX:MaxGCPauseMillis 设为 100–200 ms 优化停顿,但 GitBucket 这类 IO 型应用收益有限,不建议盲调。

💡 技术拓展:JVM 收集器选型上,GitBucket 属于「低分配速率 + 大量小对象 + 长连接」的服务,G1 是默认也是合理选择。ZGC 需要更大堆且对小堆收益不明显;SerialGC 在单核小内存环境下反而更省;ParallelGC 吞吐高但停顿不可控,不适合 Web 交互。除非有明确的停顿指标,保持 G1 即可。

9.4 systemd 层的第二道闸

MemoryMax=512M
MemoryHigh=384M

MemoryHigh 是软限(超过后节流),MemoryMax 是硬限(超过后 OOM kill)。若设置了 MemoryMax=512M 且堆也是 512 MB,JVM 会因为元空间/栈开销被 systemd 杀掉——两者要留 30% 余量,例如堆 512 MB + MemoryMax=768M。

十、日志

10.1 输出去向

systemd 托管时全部进 journald:

journalctl -u gitbucket -n 20 --no-pager
journalctl -u gitbucket -f

启动日志开头的三条告警是 4.48.0 的固有现象:

SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.

业务日志实际由 logback 输出,这三条只说明 SLF4J 的绑定探测没找到 provider,不影响日志完整性,不必修。

10.2 调整日志级别

GitBucket 用 logback,可通过外部配置文件覆盖(不动 war):

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - %msg%n</pattern></encoder>
  </appender>
  <logger name="gitbucket" level="DEBUG"/>
  <root level="INFO"><appender-ref ref="STDOUT"/></root>
</configuration>
java -Dlogback.configurationFile=/opt/gitbucket/logback-debug.xml -jar gitbucket.war --port=8095
grep -c " DEBUG " /tmp/t8.log        # 1
grep -m1 " DEBUG " /tmp/t8.log
# 13:03:23.532 [main] DEBUG g.c.s.Database$ - load database connection pool

实测 DEBUG 级别在启动阶段只多出 1 行(load database connection pool),说明 GitBucket 4.48.0 本身的 DEBUG 日志很少;排查 SQL 或认证细节主要靠 INFO 级别的业务日志。

10.3 活动流水 activity.log

$GITBUCKET_HOME/activity.log 是 JSON Lines 格式的审计流水,独立于运行日志,按行追加、不会自动轮转:

{"userName":"root","repositoryName":"demo","activityUserName":"root","activityType":"create_repository","message":"[user:root] created [repo:root/demo]","activityDate":"2026-10-27T12:29:43.408Z","activityId":"5b1e3109-7a97-4986-8bfb-88e5445f3575"}
{"userName":"root","repositoryName":"demo","activityUserName":"root","activityType":"create_branch","message":"[user:root] created branch [branch:root/demo#main] at [repo:root/demo]","activityDate":"2026-10-27T12:29:52.974Z","activityId":"f79ab798-ab6c-4ee5-946a-7b113ba56bcf"}

生产环境要给它配 logrotate(按天切分 + 保留 14 天),否则长期运行会持续膨胀。

十一、实测结论汇总

待验证的问题实测结果
-Dgitbucket.home vs GITBUCKET_HOME系统属性优先,其次环境变量,默认 ~/.gitbucket
端口的三层优先级命令行 > 环境变量 > -Dgitbucket.port
base_url 的三层优先级-Dgitbucket.base_url > GITBUCKET_BASE_URL > gitbucket.conf
gitbucket.conf 值加引号引号被当作内容,base_url 直接 500(URISyntaxException)
database.conf 值加引号必须加引号(Typesafe Config 解析)
gitbucket.conf 的默认值是否回填后台是,SMTP/LDAP/OIDC 各项均能在表单看到
后台设置能否用 curl 保存不能,POST /admin/system 缺字段返回 400
LDAP 开关打开后本地账号能否登录不能,所有登录先走 LDAP
OIDC 开关是否影响登录页是,出现 /signin/oidc 入口
SMTP 配置是否真的发信是,实测完整 SMTP 会话
prefix 是否隔离路由是,/gitbucket/signin 200、/signin 404
PostgreSQL 切换成功,43 张表,伴随 Driver2 WARN
--save_sessions / --disable_cache / --disable_news_feed启动参数存在(JettyLauncher 解析),未在本轮逐一验证

十二、常见问题

Q1:配置写了却不生效? A:先判断属于哪条链。换端口/前缀/监听地址 → 命令行 > 环境变量 > -D;改站点行为 → -D > 环境变量 > gitbucket.conf。用 ps -ef | grep gitbucket.war 看实际命令行,用 journalctl 看 Hikari 的 JDBC URL 确认数据目录,两头对齐再改。

Q2:改了 gitbucket.conf 一定要重启吗? A:要。配置在启动时读取,运行中不会热加载。systemctl restart gitbucket 后再验证。

Q3:base_url 一填就 500? A:检查引号。base_url = https://x 对,base_url = "https://x" 错。日志里会出现 java.net.URISyntaxException: Illegal character in scheme name at index 0。

Q4:数据目录跑偏到 ~/.gitbucket? A:没设 -Dgitbucket.home 也没设 GITBUCKET_HOME,用的默认值。systemd 下检查 EnvironmentFile 是否被正确 EnvironmentFile= 引用、变量名是否拼错。

Q5:Driver2 那条 WARN 要不要处理? A:不用,是 GitBucket 4.48.0 内部把 org.postgresql.Driver 写成了 org.postgresql.Driver2,HikariCP 会回落并成功连接。监控侧加白名单即可。

Q6:开了 LDAP 之后自己也登不进去了? A:LDAP 不可达时所有登录失败。停服务临时把 ldap_authentication = false 改回、重启,用本地管理员修好 LDAP 配置再开。

Q7:邮件发了但收不到? A:先确认 useSMTP = true,再用后台 Test mail 验证。测试接口不落库,能发出说明参数对;发不出就看 smtp.host/port/ssl/starttls 四件套是否与服务商要求一致。

Q8:反代后页面样式丢失、跳转到内网地址? A:base_url 没配或配错,且 X-Forwarded-Proto 没透传。配 base_url = https://对外域名,nginx 加 proxy_set_header X-Forwarded-Proto https。

十三、参考链接