GitBucketをDockerで動かす記事の多くは docker run gitbucket/gitbucket から始まります。ところがこのDocker Hubのイメージは、2022年12月25日のGitBucket 4.38.4を最後に更新が止まっています。本家は2026年4月18日に4.46.1をリリースしており、そのイメージはGitHub Container Registry(ghcr.io)で配布されています。本稿では配布先の移行を踏まえた構築手順と、Jenkinsと連携させるときにプラグイン選定でつまずくポイントを、公式リポジトリとJenkinsのセキュリティ情報をもとに整理しました。
まとめ
作業前に押さえるべき結論は次の5点です。
| 論点 | 結論 |
|---|---|
| 使うイメージ | ghcr.io/gitbucket/gitbucket:4.46.1(Docker Hub側は4.38.4で停止) |
| 永続化 | コンテナ内 /gitbucket を名前付きボリュームへ。ここにDB・Gitリポジトリ・プラグインが入る |
| Jenkins側 | jenkins/jenkins:lts(2026年8月時点で2.568.1)。JENKINS_HOMEは /var/jenkins_home |
| 連携プラグイン | GitBucket Plugin(0.8)とGitHub Pull Request Builder(1.42.2)は脆弱性が未修正。Generic Webhook Triggerを使う |
| Webhookの形式 | 既定はform-urlencoded。JSONPathで値を取るならContent typeを application/json へ変更 |
| プルリクエストのマージ | push と pull_request(closed)の両方が飛ぶ。マージだけを拾うなら merged が true か判定 |
GitBucketはScalaで書かれたGitホスティングサーバーで、Issue・プルリクエスト・Wiki・GitHub互換のREST APIを1つのwarファイルで提供します。単体で完結するためDockerとの相性が良く、社内向けのGitサーバーを最短で立てたい場面で選ばれます。
Docker HubとGHCRで割れた公式イメージの現状
GitBucketのDockerイメージは配布先が2つに割れており、片方が3年半以上放置されています。両レジストリのタグ情報は次のとおりです(2026年8月2日時点)。
| 配布先 | latestの中身 | 最新リリースタグの公開日 | 置かれているバージョンタグ |
|---|---|---|---|
| docker.io/gitbucket/gitbucket | 4.38.4 | 2022-12-25 | 4.29.0〜4.38.4の13タグ、ほかに3・4・latest・master・nightly(全18) |
| ghcr.io/gitbucket/gitbucket | 4.46.1 | 2026-04-19 | 4.39.0〜4.46.1、ほかにmaster・nightly |
移行の理由はビルド定義そのものにあります。公式イメージのビルドリポジトリ gitbucket/gitbucket-docker のGitHub Actionsワークフローは、プッシュ先を ghcr.io/gitbucket/gitbucket だけに指定しており、Docker Hubへプッシュする処理を持ちません。4.39.0以降のタグがDocker Hub側に増えていないのは、そのためです。
「なぜかバージョンが古い」「新しい機能の説明どおりに動かない」という詰まり方をしたら、まず自分が引いたイメージの出所を疑ってください。ghcr.ioの latest は4.46.1と同一ダイジェスト(sha256:e30a8a61…)を指しており、本家リリースに追随しています。amd64とarm64の両方がビルドされているため、Apple Siliconでもエミュレーションなしで動きます。
イメージの中身と公開ポート
4.46.1のイメージ構成は次のとおりです。ベースは eclipse-temurin:17 で、GitBucket本体がJava 17を必須にしている要件と一致します。
CMD sh -c "java -jar /opt/gitbucket.war"
EXPOSE 8080/tcp, 29418/tcp
VOLUME /gitbucket
29418はGit over SSH用のポートです。ポートを開けただけでは有効になりません。管理画面の Administration にある System Settings でSSHアクセスを有効化し、あわせてBase URLを設定する必要があります。SSHを使わずHTTP経由でcloneするだけなら、8080だけの公開で構いません。
docker runでの最短起動とデータの置き場所
まず単体で挙動を確かめる場合は、ボリュームを1つ与えるだけで起動します。
docker run -d --name gitbucket \
-p 8080:8080 \
-v gitbucket_home:/gitbucket \
ghcr.io/gitbucket/gitbucket:4.46.1
ブラウザで http://localhost:8080/ を開き、ID root / パスワード root でログインします。初回ログイン後にパスワードを変更してください。
永続化の対象は /gitbucket ひとつだけです。ここに設定ファイル、H2データベース、Gitリポジトリの実体、追加プラグインがまとめて入ります。イメージ側では /root/.gitbucket が /gitbucket へのシンボリックリンクになっているため、データディレクトリを意識せずにボリュームを当てられます。バインドマウントにするとホスト側のパーミッション次第で書き込みに失敗するので、名前付きボリュームが無難です。run・start・execの使い分けや起動しない場合の確認手順は別記事にまとめています。
設定はコマンドライン引数と環境変数のどちらでも渡せます。Dockerでは環境変数のほうが扱いやすく、対応関係は次のとおりです。
| CLIオプション | 環境変数 | 既定値 |
|---|---|---|
--gitbucket.home |
GITBUCKET_HOME |
~/.gitbucket |
--port |
GITBUCKET_PORT |
8080 |
--prefix |
GITBUCKET_PREFIX |
/ |
--connectors |
GITBUCKET_CONNECTORS |
http |
--jetty_idle_timeout |
GITBUCKET_JETTYIDLETIMEOUT |
300000(5分) |
Docker ComposeでGitBucketとJenkinsを並べる構成
CI連携まで見据えるなら、最初からComposeで2コンテナを定義したほうが手戻りがありません。次が最小構成です。version のトップレベル要素はCompose仕様で廃止扱いになっており、書いても警告が出るだけなので入れません。
services:
gitbucket:
image: ghcr.io/gitbucket/gitbucket:4.46.1
ports:
- "8080:8080"
- "29418:29418"
volumes:
- gitbucket_home:/gitbucket
restart: unless-stopped
jenkins:
image: jenkins/jenkins:lts
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
restart: unless-stopped
volumes:
gitbucket_home:
jenkins_home:
両方ともコンテナ内では8080で待ち受けるため、ホスト側でJenkinsを8081にずらしています。同じComposeプロジェクト内のサービスはサービス名で名前解決できるので、GitBucketからJenkinsを呼ぶURLは http://jenkins:8080/ です。ホスト側のポート番号(8081)ではありません。docker-composeで複数コンテナをymlに定義して一括管理する仕組みは別記事で解説しています。
Jenkins側の初期セットアップ
起動後、Jenkinsの初期管理者パスワードはコンテナ内のファイルから取り出します。
docker compose up -d
docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
jenkins/jenkins:lts は2026年8月時点でJenkins 2.568.1を指しています。イメージ内のJENKINS_HOMEは /var/jenkins_home、公開ポートは8080(Web UI)と50000(エージェント接続用)、実行ユーザーは jenkins です。50000番はエージェントを別コンテナやマシンに置くときだけ必要で、単体運用なら閉じて構いません。Jenkins本体のインストール方法と初期設定は別記事を参照してください。
Jenkins連携プラグインの現況と、避けるべき2つ
古い解説記事と現実が最も乖離しているのがこの部分です。「GitBucket Plugin を入れる」「GitHub Pull Request Builder でプルリクエストをビルドする」と書かれた手順は、いま新規に採用すべきではありません。Jenkinsの更新センターが配信しているプラグイン情報とセキュリティ警告を照合すると、次の状態です。
| プラグイン | 最新版 | リリース | 状態 |
|---|---|---|---|
| GitBucket Plugin(gitbucket) | 0.8 | 2015-09-10 | SECURITY-3249(Stored XSS)が全バージョン該当・修正版なし |
| GitHub Pull Request Builder(ghprb) | 1.42.2 | 2021-02-13 | deprecated指定。SECURITY-2789の2件が全バージョン該当 |
| Generic Webhook Trigger | 2.4.2 | 2026-05-16 | 現行メンテナンス中。必要コアは2.479.3以上 |
GitBucket Pluginが要求するJenkinsコアは1.609.3で、これは2015年当時のバージョンです。約11年更新されておらず、2024年3月6日のアドバイザリで報告されたStored XSSも未修正のまま残っています。ghprbのほうはプラグインサイト上で「GitHub Branch Source Plugin に置き換えられた」と明記され、既知の脆弱性を抱えたままメンテナンスが終了しました。
では何を使うか。GitBucketはGitHub互換APIを持つため、選択肢は実質2つに絞られます。
| 方式 | 使うプラグイン | 向く場面 |
|---|---|---|
| Webhookで直接ジョブを起動 | Generic Webhook Trigger | リポジトリ数が少なく、ポート構成を変えたくない |
| ブランチ・組織を自動検出 | GitHub Branch Source(Multibranch Pipeline) | ブランチやリポジトリが多く、ジョブ定義を手で増やしたくない |
Dockerで手早く立てた環境なら、Generic Webhook Triggerを選んでください。次に述べるとおり、Multibranch側にはDocker構成と正面衝突する制約があります。
Multibranch Pipelineを選ぶと効いてくるポート80の制約
GitBucketの公式Wikiは、Multibranch PipelineとOrganization Folderを使う前提条件として、Jenkinsが「ポート番号もコンテキストパスも付かないURL」でGitBucketへ到達できることを要求しています。具体的には次の縛りです。
- GitBucketをポート80で起動すること。ポートマッピング経由では動作しない
--prefix(コンテキストパス)を付けないこと- 管理画面のBase URLを空欄にせず、到達可能なURLを明示すること
Wikiはその理由を、GitHub系プラグインがGitBucketへ接続する際にURLからカスタムポートを取り除いてしまうこと、およびWebhookのURLと検出済みリポジトリURLを完全一致で照合することだと説明しています。APIエンドポイントには http://gitbucket.example.com/api/v3 のような形を登録します。
Dockerでは -p 8080:8080 のようなマッピングが当たり前なので、この条件は素直には満たせません。どうしてもMultibranchを使うなら、GITBUCKET_PORTを80に変更したうえでホスト側も80で公開し、JenkinsからもブラウザからもDNS名で同じURLに到達できるよう揃えます。次はGitBucketサービスの差分だけを示したもので、volumes などの残りは前掲の定義をそのまま引き継いでください。
services:
gitbucket:
image: ghcr.io/gitbucket/gitbucket:4.46.1
environment:
GITBUCKET_PORT: "80"
ports:
- "80:80"
逆に、ポート80を他のサービスに使っている、社内DNSを整備していない、リポジトリが数個しかない、のいずれかに当てはまるなら、Multibranchは選ばないほうが安全です。URLの一致条件を満たせないまま導入すると、ジョブは作れてもWebhookが素通りし、原因の切り分けに時間を取られます。
Generic Webhook Triggerでpush・プルリクエストを拾う設定
Generic Webhook Triggerは、任意のJSONを受け取ってJSONPathで変数に展開し、その値で発火条件を絞れるプラグインです。GitBucketのWebhookペイロードはGitHub互換なので、そのまま扱えます。
GitBucket側のWebhook登録とContent typeの変更
対象リポジトリの Settings から Service Hooks を開き、Webhookを追加します。Composeで並べた構成なら、Payload URLはサービス名を使って次の形になります。
http://jenkins:8080/generic-webhook-trigger/invoke?token=gitbucket-hook
ここで必ず Content type を application/json に変更してください。GitBucketの新規Webhook作成画面は application/x-www-form-urlencoded が既定で、この形式ではリクエストボディが payload=<URLエンコード済みJSON> という1個のフォームパラメータとして送られます。Generic Webhook Trigger側はそれをフォームパラメータとして受け取り、{"payload":["…"]} という形に組み直してからJSONPathを評価します。そのため $.ref は解決できず、ジョブが永久に発火しません。printPostContent の出力にこの payload でくるまれたJSONが見えたら、Content typeの設定漏れが原因です。
トリガーするイベントは Push と Pull Request を選びます。GitBucketが送出できるイベントは push pull_request issues issue_comment release など19種類で、名称はGitHubのWebhookと同じです。
なお、Webhook設定画面にある token 欄は、Generic Webhook Triggerの認証トークンではありません。GitBucketはこの値をHMACの鍵として使い、X-Hub-Signature と X-Hub-Signature-256 ヘッダーを付けて送ります。Generic Webhook Triggerはこの署名を検証しないため、プラグイン側のトークンはPayload URLのクエリ文字列で渡すことになります。GitBucketのWebhookフォームにカスタムヘッダーの入力欄が無い以上、ヘッダー渡しは選べません。ジョブ側の tokenCredentialId はJenkinsfileへのトークン直書きを避けるための機能で、URL上の露出そのものは消えない点に注意してください。露出を嫌うなら、Jenkinsを内部ネットワークに閉じる、あるいはリバースプロキシでアクセスログのクエリをマスクする対処になります。
Jenkinsfileでの受け取りとブランチ絞り込み
宣言的パイプラインでは triggers ブロックに書きます。regexpFilterText と regexpFilterExpression の組み合わせで、対象ブランチ以外のpushを無視できます。
pipeline {
agent any
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
causeString: 'Triggered by GitBucket push on $ref',
token: 'gitbucket-hook',
tokenCredentialId: '',
printContributedVariables: true,
printPostContent: true,
regexpFilterText: '$ref',
regexpFilterExpression: 'refs/heads/main'
)
}
stages {
stage('build') {
steps {
sh 'echo build from $ref'
}
}
}
}
宣言的パイプラインの triggers はJenkinsfileを一度読み込んで初めてジョブに登録されます。作成直後に手動で1回ビルドしておかないとWebhookを送っても反応しません。初回は printPostContent を有効にしておくと、受信したJSONがコンソール出力にそのまま出ます。期待した変数が入らないときは、ここでペイロードの実物を見てJSONPathを直すのが最短です。
プルリクエストのマージを起点にする場合の発火イベント
「プルリクエストがマージされたらデプロイしたい」という要件では、どのイベントが飛ぶかを正確に押さえておく必要があります。GitBucketの MergeService.scala を読むと、画面上のマージ操作は push と pull_request(action は closed)の両方を送出します。マージ方式がマージコミット・rebase・squashのいずれでも同じです。
ここで注意したいのは、closed がマージ以外でも飛ぶことです。プルリクエストをマージせずに閉じた場合も同じ closed になります。GitHubと同様、ペイロードには merged merged_at merged_by が含まれるので、マージだけを拾うなら $.action が closed かつ $.pull_request.merged が true という2条件で判定します。
| 操作 | 飛ぶイベント | ジョブ側の絞り込み |
|---|---|---|
| プルリクエスト作成 | pull_request(opened) |
$.action が opened |
| 対象ブランチへの追加push | pull_request(synchronize) |
$.action が synchronize |
| マージせずに閉じる | pull_request(closed) |
$.pull_request.merged が false |
| 閉じたものを再オープン | pull_request(reopened) |
$.action が reopened |
| 画面上でマージ | push と pull_request(closed) |
$.ref がマージ先ブランチ、または merged が true |
マージ後のデプロイジョブは、pushの $.ref で受けても pull_request の merged で受けても組めます。ただし両方のイベントを1つのジョブで購読すると、1回のマージで二重に起動します。検証ジョブは synchronize、デプロイジョブは refs/heads/main のpush、というように購読するイベントを分けておくと事故が起きません。パイプラインの検証段にコンテナイメージの脆弱性スキャンを挟むなら、Trivyの使い方とインストール手順が参考になります。
GitBucketのアクセストークンとJenkins資格情報
Jenkinsからプライベートリポジトリをcloneしたり、GitHub互換APIを叩いたりするには、パスワードではなくアクセストークンを使います。GitBucketでは画面右上のアカウントメニューから Applications を開くか、/<ユーザー名>/_application へ直接アクセスして発行します。
発行時の挙動で注意すべき点が1つあります。生成されたトークン文字列が画面に表示されるのは、発行直後の1回だけです。実装上もリダイレクト時のフラッシュメッセージで一度渡されるだけで、後から一覧画面を開いても用途を示すメモ(note)しか確認できません。控え忘れたら削除して再発行することになります。
Jenkins側では、この文字列をUsername with passwordの資格情報として登録するのが扱いやすい形です。ユーザー名にGitBucketのアカウント名、パスワード欄にトークンを入れます。HTTPでcloneする際はそのまま認証に使えます。Freestyleジョブやパイプラインからは資格情報IDで参照し、Jenkinsfileに直書きしないでください。
H2からの移行とバックアップ
既定のデータベースは組み込みH2で、そのまま /gitbucket 配下に置かれます。利用者やリポジトリが増えてきたら、GitBucket 4.0以降で対応した外部データベースへ移せます。対応はMySQL 5.7以上とPostgreSQL 14以上で、設定ファイルは GITBUCKET_HOME/database.conf、Dockerでは /gitbucket/database.conf です。
接続設定は次の内容を database.conf として用意します。接続先ホストはComposeのサービス名です。
db {
url = "jdbc:postgresql://db/gitbucket"
user = "gitbucket_user"
password = "YOUR_PASSWORD"
}
PostgreSQL側は、前掲のComposeに次の差分を足します。gitbucket サービスの image 以下や jenkins サービスは前掲の定義をそのまま引き継ぎ、トップレベルの volumes には db_data を追記してください。イメージタグをメジャー番号で固定しているのは、GitBucket本体のアップグレードとデータベースのメジャーアップグレードを別々のタイミングで実施できるようにするためです。
services:
gitbucket:
depends_on:
- db
db:
image: postgres:17
environment:
POSTGRES_DB: gitbucket
POSTGRES_USER: gitbucket_user
POSTGRES_PASSWORD: YOUR_PASSWORD
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
配置はホスト側で書いたファイルをコンテナへコピーする形が安全です。コピー先は名前付きボリュームの中なので、コンテナを作り直しても設定は残ります。
docker compose cp database.conf gitbucket:/gitbucket/database.conf
docker compose restart gitbucket
MariaDBは公式サポート対象外です。公式Wikiは10.2.1以上なら動く可能性があるとしつつ、10.4.4以降で不具合の報告があると注意を促しています。新規採用は避けてください。
H2に既存データがある場合は、管理画面のデータエクスポート・インポート機能で移行できます。バックアップで守るべき対象は、Gitリポジトリの実体とデータベースの状態の2つです。両者の時点がずれるとIssueやプルリクエストの参照関係が壊れます。公式Wikiのバックアップスクリプトも、全リポジトリのcloneと更新を挟んでからDBバックアップを取り、再度リポジトリを更新するという順序でこのずれを最小化しています。ただしWiki自身が「定期的に更新・保守されているものではなく、ミッションクリティカルな場面で頼るべきではない」と断っているため、そのまま本番運用に載せるのではなく、順序の考え方だけを取り込むのが現実的です。
アップグレードはwarの差し替えなので、Dockerではイメージタグの変更とコンテナの作り直しに相当します。ghcr.io/gitbucket/gitbucket:4.46.1 のようにタグを固定しておけば、意図しないタイミングでのバージョン変動を避けられます。プラグインを追加している場合は、本体の更新に合わせて対応版へ入れ替える必要があります。
つながらないときの切り分け
構築中に起きやすい症状と、最初に見るべき場所をまとめました。
| 症状 | 確認する場所 | 典型的な原因 |
|---|---|---|
| Webhookが届かない | GitBucketのWebhook設定画面の配信履歴 | Payload URLにホスト側ポート(8081)を書いている |
| Jenkinsが404を返す | invokeのパスとtoken | Generic Webhook Trigger未インストール、tokenの不一致 |
| 200が返るのにビルドが起動しない | WebhookのContent type | x-www-form-urlencoded のままでJSONPathが解決できない |
| 変数が空のまま発火しない | printPostContentの出力 | regexpFilterExpressionがrefと一致していない |
| Multibranchがリポジトリを検出しない | APIエンドポイントのURL | ポート番号やprefixが付いている |
| SSHでcloneできない | System SettingsのSSHアクセス | 29418を公開しただけで機能を有効化していない |
| 再起動でデータが消える | docker volume ls | /gitbucket をボリューム化していない |
Webhook関連は、GitBucketの管理画面で送信結果のレスポンスコードを確認できます。ここが接続エラーならネットワークの問題、200以外のHTTPステータスならJenkins側の設定の問題、と切り分けの向きが決まります。
よくある質問
GitBucketとは何ですか
Scalaで開発されたオープンソースのGitプラットフォームです。リポジトリ管理、Issue、プルリクエスト、Wiki、アカウント・グループ管理、LDAP連携、プラグイン機構を備え、GitHub互換のAPIを提供します。1つのwarファイルで動くため導入が軽く、社内にGitサーバーを置きたい場合に選ばれます。
docker run gitbucket/gitbucket で入るのはどのバージョンですか
Docker Hub側の latest は4.38.4で、2022年12月25日から更新されていません。最新版を使うなら ghcr.io/gitbucket/gitbucket:4.46.1 を指定してください。
JenkinsのGitBucket Pluginは今も使えますか
新規導入は避けてください。未修正の脆弱性を抱えたまま更新が止まっているためです。Webhook起点でジョブを動かす目的なら、Generic Webhook Triggerで代替できます。
プルリクエストのマージだけを条件にビルドするにはどうしますか
マージ操作では push と pull_request(action は closed)の両方が飛びます。closed はマージせずに閉じた場合も同じ値なので、$.action が closed かつ $.pull_request.merged が true で判定するか、マージ先ブランチへのpush($.ref が refs/heads/main)を条件にします。両方を同じジョブで購読すると二重起動します。
Jenkinsで使うアクセストークンはどこで作りますか
GitBucket側で発行します。アカウントメニューのApplications、URLでは /<ユーザー名>/_application です。トークン文字列は発行直後にしか表示されないため、その場で控えてJenkinsの資格情報へ登録してください。