Ubuntu 22.04 安装 GitBucket 4.48.0 指南

在 Ubuntu 22.04 上以裸机 JVM + systemd 方式从 0 到 1 安装 GitBucket 4.48.0:OpenJDK 17 准备、war 获取与校验、前台试跑、systemd 单元与环境变量、H2→PostgreSQL 切换实测(43 张表)、升级备份与卸载排障,含 java -version、启动日志、curl 与 systemctl status 真实回显。

GitBucketGitBucket版本控制Git 服务2026/10/27

目标:在一台全新的 Ubuntu 22.04 LTS 上完成 GitBucket 4.48.0 从环境准备、war 获取、裸机 JVM 进程运行到 systemd 托管的完整流程,并给出外置 PostgreSQL 切换、升级、卸载的实测记录。

Ubuntu 22.04 安装 GitBucket 4.48.0 指南

GitBucket 是一个 Scala 编写、以单个 gitbucket.war 分发的 Git 托管服务,内嵌 Jetty 与 JGit,启动后自带 Web UI、REST API、仓库与 issue 管理。本文按「基础环境 → 获取 war → 前台试跑 → systemd 托管 → 外置数据库 → 升级/卸载」的顺序,在一台 Ubuntu 22.04 上从 0 到 1 装一遍,所有命令与回显均为 2026-10-27 的实测结果。

一、环境信息

项值
操作系统Ubuntu 22.04.4 LTS(Jammy,x86_64)
GitBucket4.48.0(2026-09-20 发布)
JavaOpenJDK 17.0.20.1(GitBucket 4.42 起要求 Java 17,Java 8/11 无法启动)
运行形态单个 JVM 进程,java -jar gitbucket.war,内嵌 Jetty
程序路径/opt/gitbucket/gitbucket.war(69 MB)
数据目录/opt/gitbucket/data(由 -Dgitbucket.home 指定)
监听0.0.0.0:8080(HTTP)
系统用户gitbucket(--system,不可登录)
JVM 堆-Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError
初始管理员root / root,登录后改为 q1w2e3r4

💡 技术拓展:GitBucket 的数据库层是三选一的可插拔设计——内置 H2(默认,文件型,零运维)、PostgreSQL、MySQL。三者的差异集中在并发写入与备份方式上:

维度H2(默认)PostgreSQL 15MySQL 8
存储形态单文件 data.mv.db,随数据目录一起备份独立服务,需 pg_dump/物理备份独立服务,需 mysqldump/XtraBackup
并发写入单写者,团队 > 20 人易锁等待MVCC,适合中大型团队MVCC,适合中大型团队
升级风险4.43+ 需手动做 H2 1.x → 2.x 迁移无额外迁移无额外迁移
运维成本最低中中

本文默认走 H2,第六节给出切 PostgreSQL 的实测过程。GitBucket 本身不感知数据库类型,切换只改一个 database.conf 文件。

二、前置条件

  1. Java 17:必须 17 及以上,低于 17 启动直接抛 UnsupportedClassVersionError;
  2. 端口:8080 空闲;
  3. 内存:≥ 1 GB 可用(war 解包 + 512 MB 堆 + JGit 工作区);
  4. 磁盘:≥ 5 GB(仓库数据 + H2 文件 + 插件);
  5. 可选:git 命令行,用于后续仓库操作验证。
uname -m                                  # x86_64
. /etc/os-release && echo "$PRETTY_NAME"  # Ubuntu 22.04.4 LTS
free -h | head -2
df -h /opt | tail -1
ss -ltn | grep 8080                        # 无输出 = 端口空闲

实测回显:

x86_64
Ubuntu 22.04.4 LTS
               total        used        free      shared  buff/cache   available
Mem:            18Gi       9.9Gi       2.5Gi       241Mi       6.7Gi       8.6Gi
overlay         295G   89G  191G  32% /

三、安装 Java 17 与获取 gitbucket.war

3.1 安装 OpenJDK 17

sudo apt update
sudo apt install -y openjdk-17-jre-headless
java -version

实测回显:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)

只要 java -version 显示 17 即可;如果系统里同时装了 8/11,用 sudo update-alternatives --config java 切到 17,否则 systemd 拉起时会用错版本。

3.2 创建目录与系统用户

sudo useradd --system --home /opt/gitbucket --shell /usr/sbin/nologin gitbucket
sudo mkdir -p /opt/gitbucket/data
sudo chown -R gitbucket:gitbucket /opt/gitbucket
ls -ld /opt/gitbucket /opt/gitbucket/data
drwxr-xr-x 3 gitbucket gitbucket 4096 Oct 27 12:23 /opt/gitbucket
drwxr-xr-x 6 gitbucket gitbucket 4096 Oct 27 12:29 /opt/gitbucket/data

数据目录只放 data 一层,war 直接放在 /opt/gitbucket/gitbucket.war,与 systemd 单元的 WorkingDirectory=/opt/gitbucket 对齐。

3.3 下载 war 包

cd /opt/gitbucket
sudo -u gitbucket curl -L -o gitbucket.war \
  https://github.com/gitbucket/gitbucket/releases/download/4.48.0/gitbucket.war

⚠️ 网络说明:本环境实测直连 github.com 的 Release 下载 12 秒无任何响应(curl: (28) Connection timed out,HTTP 码 000),必须走代理:

# 实测可用:代理 192.168.1.62:7897
sudo -u gitbucket curl -x http://192.168.1.62:7897 -L -o gitbucket.war \
  https://github.com/gitbucket/gitbucket/releases/download/4.48.0/gitbucket.war

下载完成后核对体积与文件类型:

ls -lh /opt/gitbucket/gitbucket.war
file /opt/gitbucket/gitbucket.war
-rw-r--r-- 1 gitbucket gitbucket 69M Oct 27 12:17 /opt/gitbucket/gitbucket.war
/opt/gitbucket/gitbucket.war: Zip archive data, at least v2.0 to extract

war 是标准 zip 归档,69 MB 属于正常范围(含内嵌 Jetty、H2 与 4 个内置插件)。若只有几 MB 或百来 KB,基本是下载到了 HTML 错误页,用 file 一看便知。

四、方案 A:前台/后台直接运行(快速验证)

适用场景:首次验证、调试参数。生产请用第五节 systemd 托管。

4.1 前台启动

sudo -u gitbucket /usr/bin/java \
  -Dgitbucket.home=/opt/gitbucket/data \
  -Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError \
  -jar /opt/gitbucket/gitbucket.war \
  --port=8080

首次启动会建库、解包内置插件、初始化 43 张表,全过程约 4 秒(实测 12:25:54 起进程、12:25:57 完成插件初始化)。日志节选:

12:23:43.601 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
12:23:43.978 [main] INFO  com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn0: url=jdbc:h2:/opt/gitbucket/data/data user=SA
12:23:43.981 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
12:23:44.013 [main] INFO  g.core.servlet.InitializeListener - Check version
12:23:44.013 [main] INFO  g.core.servlet.InitializeListener - Start schema update
12:23:46.641 [main] INFO  g.core.servlet.InitializeListener - Extract bundled plugins...
12:23:46.667 [main] INFO  g.core.servlet.InitializeListener - Extract to /opt/gitbucket/data/plugins/gitbucket-notifications-plugin-1.11.0.jar
12:23:46.668 [main] INFO  g.core.servlet.InitializeListener - Extract to /opt/gitbucket/data/plugins/gitbucket-gist-plugin-4.26.0.jar
12:23:46.668 [main] INFO  g.core.servlet.InitializeListener - Extract to /opt/gitbucket/data/plugins/gitbucket-emoji-plugin-4.6.0.jar
12:23:46.674 [main] INFO  g.core.servlet.InitializeListener - Extract to /opt/gitbucket/data/plugins/gitbucket-pages-plugin-1.11.0.jar
12:23:47.643 [Thread-9] INFO  g.core.plugin.PluginWatchThread - Start PluginWatchThread: /opt/gitbucket/data/plugins
12:23:47.649 [main] INFO  o.scalatra.servlet.ScalatraListener - The cycle class name from the config: ScalatraBootstrap
12:23:47.656 [main] INFO  o.scalatra.servlet.ScalatraListener - Initializing life cycle class: ScalatraBootstrap

日志里 HikariPool-1 - Added connection conn0: url=jdbc:h2:/opt/gitbucket/data/data 这一行同时说明两件事:数据目录被正确解析到 /opt/gitbucket/data(否则会落到 ~/.gitbucket),且默认 H2 生效。

4.2 启动后验证

curl -s -D- -o /dev/null http://localhost:8080/
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 12:51:58 GMT
Set-Cookie: JSESSIONID=node01cdg3dgo0rc8r18q8txe7wneoi13.node0; Path=/; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=utf-8
Content-Length: 8505

Set-Cookie: JSESSIONID + 200 就代表 Jetty 与 Scalatra 路由已就绪;此时抓首页能看到 <title>GitBucket</title>。

登录页表单实测只有三个字段(userName、password、隐藏的 hash),没有 CSRF token,可直接用 curl 验证账号:

curl -s -c /tmp/c.txt -o /dev/null -w "login=%{http_code} -> %{redirect_url}\n" \
  -d "userName=root&password=root&hash=" http://localhost:8080/signin
login=302 -> http://localhost:8080/signin;jsessionid=node01oezn4s7upuj8a3fjppw7fsnm19.node0

302 且带 jsessionid 即登录成功,Cookie 已写入 /tmp/c.txt。

4.3 后台临时运行(不建 systemd)

sudo -u gitbucket nohup /usr/bin/java \
  -Dgitbucket.home=/opt/gitbucket/data \
  -Xms512m -Xmx512m \
  -jar /opt/gitbucket/gitbucket.war --port=8080 \
  > /opt/gitbucket/gitbucket.out 2>&1 &
disown
ps -ef | grep '[g]itbucket.war'

这种方式重启机器即失效、崩溃也不拉起,仅用于验证,长期运行务必走下一节。

五、方案 B:systemd 托管(生产推荐)

5.1 环境变量文件

JVM 参数放在 EnvironmentFile 里,升级 war 时不必改单元文件:

sudo tee /etc/default/gitbucket > /dev/null <<'EOF'
JAVA_OPTS="-Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError"
GITBUCKET_HOME=/opt/gitbucket/data
EOF

5.2 单元文件

sudo tee /etc/systemd/system/gitbucket.service > /dev/null <<'EOF'
[Unit]
Description=GitBucket 4.48.0
After=network.target postgresql.service

[Service]
Type=simple
User=gitbucket
Group=gitbucket
EnvironmentFile=/etc/default/gitbucket
WorkingDirectory=/opt/gitbucket
ExecStart=/bin/sh -c "exec /usr/bin/java $JAVA_OPTS -jar /opt/gitbucket/gitbucket.war --port=8080"
Restart=on-failure
RestartSec=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

几点说明:

  • ExecStart 用 /bin/sh -c "exec ..." 包一层,才能让 $JAVA_OPTS 展开;exec 保证 java 取代 sh 成为主进程,systemctl stop 才能把信号直接送到 JVM。
  • After=network.target postgresql.service:不切外置库时可删掉 postgresql.service。
  • LimitNOFILE=65536:每个 git push/fetch 都占文件句柄,默认 1024 在大仓库并发下会报 Too many open files。
  • 堆固定 512 MB,-XX:+ExitOnOutOfMemoryError 让 OOM 时进程退出而不是僵死,由 systemd 的 Restart=on-failure 拉起。

5.3 启动与状态验证

sudo systemctl daemon-reload
sudo systemctl enable --now gitbucket
systemctl is-active gitbucket
systemctl status gitbucket --no-pager -l

实测回显:

active
● gitbucket.service - GitBucket 4.48.0
     Loaded: loaded (/etc/systemd/system/gitbucket.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-10-27 12:25:53 UTC; 25min ago
   Main PID: 6745 (java)
      Tasks: 42 (limit: 2932)
     Memory: 423.8M
        CPU: 16.040s
     CGroup: /system.slice/gitbucket.service
             └─6745 /usr/bin/java -Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError -jar /opt/gitbucket/gitbucket.war --port=8080

Main PID: 6745 (java) 说明主进程就是 JVM(不是被 sh 包着),Memory: 423.8M 与 512 MB 堆上限相符。

端口与 HTTP:

ss -ltn | grep 8080
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8080/
LISTEN 0      50                 *:8080             *:*                  
HTTP 200

5.4 堆参数是否真的生效

systemctl status 只显示进程命令行,再补一条 jps -v 交叉确认 JVM 实际拿到了参数:

sudo -u gitbucket jps -v
6745 war -Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError
7116 Jps -Dapplication.home=/usr/lib/jvm/java-17-openjdk-amd64 -Xms8m -Djdk.module.main=jdk.jcmd

💡 技术拓展:jps -v 第一列显示的 war 是 jar 的 manifest 里没有 Main-Class 时 JVM 的兜底显示(GitBucket 用的是 Jetty 的 launcher 式入口),不代表进程异常。要确认是 GitBucket,看 -jar /opt/gitbucket/gitbucket.war 参数或 ps -ef | grep gitbucket.war 即可。

5.5 日志

journalctl -u gitbucket -n 20 --no-pager
journalctl -u gitbucket -f              # 实时追踪

首次启动的日志会包含 Started GitBucket 4.48.0.、Hikari 建池、插件解包三段(见 4.1 节回显)。注意:日志开头的

SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation

是 GitBucket 自身依赖里 SLF4J 绑定缺失导致的告警,不影响业务日志(业务日志由 logback 输出到 journald),可以忽略。

5.6 日常运维命令

sudo systemctl stop gitbucket
sudo systemctl restart gitbucket
sudo systemctl disable gitbucket
journalctl -u gitbucket --since "10 min ago"

六、切换到外置 PostgreSQL(实测)

默认 H2 支撑小团队够用;仓库数上百、并发写入变多后建议换 PostgreSQL。切换只需在 $GITBUCKET_HOME 下放一个 HOCON 格式的 database.conf。

6.1 准备数据库

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;"

6.2 写 database.conf

sudo tee /opt/gitbucket/data/database.conf > /dev/null <<'EOF'
db {
  url = "jdbc:postgresql://127.0.0.1:5432/gitbucket"
  user = "gitbucket"
  password = "gb_pg_2026"
  maximumPoolSize = 10
}
EOF
sudo chown gitbucket:gitbucket /opt/gitbucket/data/database.conf

6.3 重启并验证

sudo systemctl restart gitbucket
journalctl -u gitbucket --since "2 min ago" --no-pager | grep -E "Hikari|postgres"

实测回显:

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

Added connection org.postgresql.jdbc.PgConnection 即已连上 PostgreSQL。建表结果可反查:

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

43 张表与 H2 初始化时一致,说明 schema 迁移完成。

⚠️ 实测真问题:日志里的 driverClassName=org.postgresql.Driver2 was not found 是 GitBucket 4.48.0 在 HikariCP 里写死了 org.postgresql.Driver2 这个不存在的类名导致的告警。它只是 WARN——HikariCP 会退回直接实例化 org.postgresql.Driver,连接照常建立,可忽略;但如果你的监控把 WARN 当故障,需要给它单独配忽略规则。

⚠️ 另一个坑:database.conf 里的密码是明文,database.conf 必须 chown gitbucket:gitbucket 且权限收到 600,否则同机其他用户可读。

6.4 MySQL 8 的等价配置

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

MySQL 需要提前 CREATE DATABASE gitbucket CHARACTER SET utf8mb4,且 JDBC 串必须带 characterEncoding=UTF-8,否则中文仓库名/issue 会乱码。

6.5 从 H2 迁移已有数据

换库不是改配置就完事,历史数据要迁:

  1. 停服务 sudo systemctl stop gitbucket;
  2. 备份整个数据目录 sudo cp -a /opt/gitbucket/data /opt/gitbucket/data.bak;
  3. 用 H2 工具把数据导成 SQL:java -cp /opt/gitbucket/gitbucket.war org.h2.tools.Script -url jdbc:h2:/opt/gitbucket/data/data -user sa -password sa -script /tmp/dump.sql;
  4. 把 dump.sql 里的 H2 方言(CREATE CACHED TABLE、IDENTITY 等)改成 PostgreSQL/MySQL 方言后导入;
  5. 起服务并核对仓库数量、issue 数量。

⚠️ H2 1.x → 2.x 的升级迁移(4.42 及更早升级到 4.43+ 仍用内置 H2 时必须做)不在本节范围,见第十节 Q3。

七、验收清单

安装完成后按下面五项逐条确认,全部通过即可交付:

systemctl is-active gitbucket                                  # active
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/  # 200
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/api/v3  # 200
sudo -u gitbucket jps -v | grep gitbucket.war                  # 带 -Xms512m -Xmx512m
sudo ls /opt/gitbucket/data                                    # data.mv.db repositories plugins

实测回显(逐条):

active
200
200
6745 war -Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError
activity.log  data.mv.db  database.conf  gist  plugins  repositories  tmp

data.mv.db 是 H2 数据文件(切 PostgreSQL 后该文件不再增长,可保留作回滚用),repositories 下是实际 git 仓库,plugins 下是自动解包的 4 个内置插件。

登录 Web UI 后第一件事:右上角 Settings → Account 把 root 的密码从默认 root 改成 q1w2e3r4,并新建一个日常使用的普通账号,避免长期用管理员账号做 git 操作。

八、升级

# 1. 停服务 + 备份数据目录(H2 场景必须停服后再拷,避免拷到半个事务)
sudo systemctl stop gitbucket
sudo cp -a /opt/gitbucket/data /opt/gitbucket/data.backup.$(date +%Y%m%d-%H%M%S)

# 2. 换 war
sudo -u gitbucket curl -x http://192.168.1.62:7897 -L -o /opt/gitbucket/gitbucket.war.new \
  https://github.com/gitbucket/gitbucket/releases/download/4.48.0/gitbucket.war
sudo -u gitbucket mv /opt/gitbucket/gitbucket.war.new /opt/gitbucket/gitbucket.war

# 3. 起服务 + 验证
sudo systemctl start gitbucket
sleep 5
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8080/
journalctl -u gitbucket --since "1 min ago" --no-pager | grep -E "Check version|schema update"

4.48.0 升级注意点:4.47.0/4.48.0 带大表迁移,首次启动会在 Start schema update 处停留较久(实测 2.6 秒),期间不要 kill 进程;升级前必须备份数据目录,降级只能靠回滚备份。

九、卸载与清理

sudo systemctl stop gitbucket
sudo systemctl disable gitbucket
sudo rm -f /etc/systemd/system/gitbucket.service /etc/default/gitbucket
sudo systemctl daemon-reload

sudo rm -rf /opt/gitbucket
sudo userdel gitbucket

systemctl status gitbucket 2>&1 | head -2
Unit gitbucket.service could not be found.

若只是换机器迁移,不要 rm -rf,改为 tar -czf gitbucket-data.tar.gz -C /opt/gitbucket data 打包带走,新机器解压到同路径即可。

十、常见问题

Q1:启动后 curl 不是 200,而是 Connection refused? A:先看 journalctl -u gitbucket -n 100。三类原因:(1)端口被占,改 --port=8081 并同步 ss -ltn 确认;(2)Java 版本低于 17,java -version 核对;(3)数据目录权限不对,sudo chown -R gitbucket:gitbucket /opt/gitbucket。另注意首次启动建库约 4 秒,脚本里 curl 前至少 sleep 5。

Q2:root 账号登录不了? A:默认 root/root,实测 POST /signin 返回 302 即成功。若改过密码又忘了,可停服后用 H2 Shell 改:java -cp /opt/gitbucket/gitbucket.war org.h2.tools.Shell -url jdbc:h2:/opt/gitbucket/data/data -user sa -password sa,在 ACCOUNT 表里重置。4.47.0+ 有「最后一个管理员不可删除」约束,所以不能靠删账号绕过。

Q3:从 H2 1.x 升级到 4.43+ 后启动报 H2 错误? A:4.43+ 内置 H2 2.x,旧库必须手动迁移:用 h2-1.4.199.jar 的 Script 工具导出 SQL,再用 h2-2.3.232.jar 的 RunScript 导入,参考 https://www.h2database.com/html/migration-to-v2.html。GitBucket 的自动 schema update 依赖数据库本身能起来,库起不来它也无能为力。

Q4:systemd 启动报 ExecStart=... $JAVA_OPTS ... 参数没生效? A:systemd 不会展开 ExecStart 里的变量,除非显式走 shell。本文单元用 /bin/sh -c "exec ... $JAVA_OPTS" 正是为此;若写成 ExecStart=/usr/bin/java $JAVA_OPTS -jar ...,$JAVA_OPTS 会被当成一个名为 $JAVA_OPTS 的畸形参数传给 JVM,启动即失败。

Q5:怎么让 GitBucket 跑在 80/443? A:80 端口给 java 进程加 capability:sudo systemctl edit gitbucket 加 AmbientCapabilities=CAP_NET_BIND_SERVICE;443 需 HTTPS,启动参数追加 --connectors=http,https --secure_port=443 --key_store_path=/opt/gitbucket/keystore.jks --key_store_password=... --key_manager_password=...,keystore 用 keytool -genkeypair 生成。

Q6:git clone 提示 remote: Repository not found 但网页能看到仓库? A:GitBucket 的 HTTP 克隆路径是 http://<host>:8080/<owner>/<repo>.git,少了 .git 后缀或 owner 大小写不对都会 404;私有仓库还需要用 用户名:密码 或 Personal Access Token 做 Basic Auth。

十一、参考链接