こんにちは。テクマトリックスの長久保です。
私は、JenkinsとGitLabを組み合わせたCI/CD環境の構築を行うことがあります。
JenkinsとGitLabの連携における代表的なプラグインとしてGitLab Branch Sourceプラグインがあります。こちらはJenkinsからジョブを作成すると、GitLabのプロジェクトにWebhookを自動的に作成してくれる便利なプラグインです。
ただ、先日Multibranch Pipelineを構成した際に「GitLab Branch SourceプラグインがWebhookを自動作成してくれるはずなのに、なぜか作成されない」という事象に遭遇しました。
厄介なことに、この事象はUIに原因のわかるエラーが表示されません。保存時に500エラーの画面が一度出るだけで、ジョブ自体は保存され、ブランチスキャンもビルドも正常に成功します。それなのに、GitLab側のWebhook一覧だけが空のまま、という状態になります。
この記事では、検証で確認できたWebhookが自動作成されない理由について、プラグインのソースコードと実際のログを添えて紹介します。
同じ事象でハマっている方の参考になれば嬉しいです。
目次
前提
本記事は2026/07/23時点の以下のバージョンで検証しています。
GitLabとJenkinsはDockerで起動しています。
| 対象 | 使用イメージ | 検証時点のバージョン |
|---|---|---|
| Jenkins | jenkins/jenkins:lts-jdk21 | 2.568.1 |
| gitlab-branch-sourceプラグイン | 740.v04f287f9194d | |
| GitLab | gitlab/gitlab-ce:latest (CE) | 19.2.0 |
基本のWebhook自動設定
原因の話に入る前に、正常系について説明します。
自動作成のトリガーは「ジョブの保存」
まず、押さえておきたいのは、Webhookが作られるタイミングです。
ブランチスキャンの実行時でもビルド時でもなく、Multibranch Pipelineジョブの設定を保存した瞬間にプラグインが動きます。Multibranch PipelineでBranch Sourceに「GitLab Project」が設定されている場合、保存のたびに以下の処理が走ります(このあたりプラグインや機能によって更新タイミングが異なるのでややこしいなぁと思います)。

プラグインのコードを確認すると、次の流れで処理が書かれていました。
ジョブ設定を保存
→ GitLabSCMSource.afterSave()
→ GitLabHookCreator.register(...)
├─ GitLab Serverの「Manage Web Hooks」が有効か確認 ← ①
├─ getHookUrl(server, true)
│ ├─ checkURL(Jenkins URL) ← ②
│ └─ Jenkins URL + "gitlab-webhook/post" を組み立て
└─ PATで認証してGitLabのAPIを呼ぶ ← ③④
POST /projects/:id/hooks (既存があれば更新)
正常系では、Jenkinsに設定されたJenkins URLからWebhook用のURLを組み立てて、それをGitLabに登録する、という流れになっています。Jenkins URLがhttp://jenkins.local:8080/なら、登録されるURLはhttp://jenkins.local:8080/gitlab-webhook/postになります。
正常系で動作するための4つの条件
Webhookが自動作成されるには、次の4つが成立している必要があります。
- GitLab Servers設定の「Manage Web Hooks」が有効であること(①)
- Jenkins URLがプラグインのFQDNチェックを通ること(②)
- 認証に使うPATが書き込み可能なapiスコープであること(③)
- GitLab側がそのURL宛のWebhook登録を許可していること(④)
こちらを満たすために、実際の設定方法を説明します。
設定自体は非常にシンプル
プラグインの設定に難しい内容はありません。
- GitLab側でapiの権限を持つPersonal Access Tokenを発行
- Jenkinsダッシュボード > Jenkinsの管理 > System > GitLabセクション
Credentialsに発行したPersonal Access Tokenを登録
「Manage Web Hooks」にチェックを入れる

- Jenkinsへのジョブ追加時に、Multibranch Pipelineを選択し、Branch SourcesにGitLab Projectを選択して登録する
以上で設定は完了です。これで正常系であれば、自動的にGitLabにWebhookが登録されます。
では実際にうまく自動作成されない例を見ていきます。
①GitLab Servers設定の「Manage Web Hooks」が無効
これは単純に設定漏れに近い内容ですが、初めてこのプラグインを利用する方は忘れるかもしれない内容です。
Jenkinsダッシュボード > Jenkinsの管理 > System > 「GitLab Servers」欄にある「Manage Web Hooks」のチェックがされていないと、そもそも自動登録の処理が走りません。
当たり前の話ではあるのですが、ロジック上は
case SYSTEM:
if (!server.isManageWebHooks()) {
break;
}となっており、何もログは出ないので、焦っているときはハマるかもしれないですね。
②Jenkins URLがFQDNでない
今回私がハマったポイントになります。
今回Docker ComposeでJenkinsとGitLabを構築したので、Jenkins URLはコンテナ間で解決できるhttp://jenkins:8080/で設定しました。そこまで変な設定ではないと思います。
直接インストールした場合はhttp://localhost:8080/で動作させる場合もあるかと思います。
この状態でジョブを保存すると、保存時に一度500エラーになります。一瞬「何かあったのか」と思うのですが、ジョブ自体は保存されており、ブランチスキャンは成功しビルドまで正常に走ります。そして、Webhookだけが作成されません。500エラーの画面にも原因は表示されず、その後はジョブ画面にも設定画面にもエラーが残らないため、最初はプラグインのバグなどでWebhook作成処理がそもそも動いていないのかと疑ったほどでした。
どこかにlogが出ていないかと確認すると、以下のjenkins.log(今回はdockerで動かしていたので、docker logs jenkins)にログが出力されていました。なお、同じ内容はJenkinsダッシュボード > Jenkinsの管理 > システムログの画面からも確認できます。
2026-07-27 17:45:08 2026-07-27 08:45:08.049+0000 [id=34] WARNING h.i.i.InstallUncaughtExceptionHandler#handleException: Caught unhandled exception with ID f487b66e-1908-4046-90c3-89988ba1fdaf
2026-07-27 17:45:08 java.lang.IllegalStateException: You must use a fully qualified domain name for Jenkins URL, this is required by GitLab
2026-07-27 17:45:08 [LF]> URL is: http://jenkins:8080/プラグインのソースコードを確認すると、GitLabHookCreator.checkURL()がJenkins URLを検証しています。
static void checkURL(String url) {
try {
URL anURL = new URL(url);
if ("localhost".equals(anURL.getHost())) {
throw new IllegalStateException("Jenkins URL cannot start with http://localhost \nURL is: " + url);
}
if (!anURL.getHost().contains(".")) {
throw new IllegalStateException(
"You must use a fully qualified domain name for Jenkins URL, this is required by GitLab"
+ "\nURL is: " + url);
}
} catch (MalformedURLException e) {
throw new IllegalStateException("Bad Jenkins URL\nURL is: " + url);
}
}上記のように
- ホスト名がlocalhostそのものなら拒否
- ホスト名にドット(.)が1つも含まれないなら「FQDNでない」として拒否
という仕様になっています。
そのため、Jenkins URLをhttp://jenkins.local:8080/に変更すれば(ドットを含む形にすれば)、無事Webhookが自動的に登録されました。
もう少し掘ってみる
ジョブ設定を保存
→ GitLabSCMSource.afterSave()
→ GitLabHookCreator.register(...)
→ getHookUrl(server, true)
→ checkURL(rootUrl) ← ここで IllegalStateException
register()の中にはtry/catchがあるのですが、対象としているのはGitLab API呼び出し時のGitLabApiExceptionだけで、checkURL()はそのtryブロックの外で呼ばれています。そのためこの例外はプラグインのWARNINGログを一切通らず、保存後のフック処理からそのまま上に投げられて、jenkins.logに書き出されるだけになっていました。結果として、「保存は成功したように見えるのにWebhookだけ作られない」という状況になっていたようです。
ちなみに、Jenkins URLが未設定の場合は、getHookUrl()が空文字を返し、register()が何もせずにreturnするので、例外すら出ません。
そもそもなぜプラグインはFQDNを要求するのか
例外メッセージは「this is required by GitLab」となっており、GitLab側の要求とのことです。
GitLab側の設定で、ローカルネットワークへのリクエストを許可していれば、手動で登録した場合、Jenkins URLが「http://jenkins:8080/」や「http://localhost:8080/」であってもWebhookは登録が可能です。
また、プラグインを介さずGitLabのAPIに直接非FQDNのURLでWebhook作成を投げてみました。
curl.exe -s -X POST -H "PRIVATE-TOKEN: *************" `
-H "Content-Type: application/json" `
-d '{"url": "http://jenkins:8080/gitlab-webhook/post"}' `
"http://localhost:8929/api/v4/projects/root%2Fwebhook-test/hooks"結果としては、APIでも問題なくWebhookを登録することができました。少なくともバージョン19.2.0で、ローカルネットワークへのリクエストを許可済みのセルフマネージドGitLabは、非FQDNのURLを拒否しません。
ではなぜ「required by GitLab」なのかというと、「gitlab.comから実際に到達できるURLである必要がある = 運用上FQDNでないと意味がない」という前提があるからだと推測しました。
たしかにgitlab.comの場合は、「jenkins」のようなパブリックDNSで解決できないショートネームやプライベートアドレスに解決される名前はSSRF対策(『④GitLab側がローカルネットワークへのWebhookを拒否している』で扱う仕組みと同じもの)で弾かれるため、「gitlab.comから届くURL=FQDN」が事実上の前提になります。そのためプラグインはこの仕様を汲んで、GitLabに問い合わせる前に一律チェックしているのだと思います。
ただ、このチェックが厳しすぎるといった報告(JENKINS-59759:localhost not allowed for jeknins with gitlab-branch-source-plugin)も上がっています。
とはいえ、少なくとも現時点のプラグインで、自動Webhook作成の機能を使う場合は、Jenkins URLをドット入りのURLにするか、自動Webhook作成を使わずに手動でWebhookを登録する必要があります。
③Personal Access Tokenのスコープがapiを許可していない
Webhookの作成はGitLabのREST API(POST /projects/:id/hooks)で行われるため、認証に使うPersonal Access Tokenには書き込みができるapiスコープが必要です。ブランチスキャン自体はread_apiでも動いてしまうので、「GitLabプロジェクトのスキャンは成功するのにWebhookは403」という中途半端な状態になります。
WARNING i.j.p.g.GitLabHookCreator#register: Could not manage project hooks for root/webhook-test on http://gitlab:8929
org.gitlab4j.api.GitLabApiException: 403 Forbiddenレスポンスボディには insufficient_scope が入っており、スコープ不足であることがわかります。
こちらはPersonal Access Token作成時にapiの権限も付与して作成することで解消します。

④GitLab側がローカルネットワークへのWebhookを拒否している
GitLabはデフォルトで、SSRF対策としてローカルネットワーク宛のWebhook作成を拒否します。
WARNING i.j.p.g.GitLabHookCreator#register: Could not manage project hooks for root/webhook-test on http://gitlab:8929
org.gitlab4j.api.GitLabApiException: Invalid url givenこの場合、GitLab側で設定を修正する必要があります。ブラウザで確認・変更する場合は、rootなどの管理者でGitLabにログインし、左メニューのAdmin Area > Settings > Network > 「Outbound requests」を展開して、「Allow requests to the local network from webhooks and integrations」にチェックを入れて保存します。

また、地味な注意点として、この設定はGitLab側で60秒キャッシュされています(gitlab.ymlのapplication_settings_cache_seconds)。そのため、保存後に少し待機してから実行する必要があります。
社内ネットワークやローカル環境にGitLabとJenkinsを立てている場合、一度はハマったことがあるのではないでしょうか。
まとめ
今回の検証で確認した4つの原因を整理します。ログが出力される場合は〇、出力されない場合は×を付けます。
| 番号 | 原因 | ログの内容 | System Log/Jenkinsの管理 > システムログ | Scan Project Logやビルドコンソール | 対処法 |
|---|---|---|---|---|---|
| ① | GitLab Servers設定の「Manage Web Hooks」が無効 | 何も表示されない | × | × | GitLab Servers設定で「Manage Web Hooks」にチェックを入れる |
| ② | Jenkins URLがFQDNでない | IllegalStateException: You must use a fully qualified domain name~ | 〇 | × | ドット入りのホスト名/FQDNにする |
| ③ | Personal Access Tokenのスコープがapiを許可していない | WARNING … GitLabApiException: 403 Forbidden | 〇 | × | apiスコープでPersonal Access Tokenを作り直す |
| ④ | GitLab側がローカルネットワークへのWebhookを拒否している | WARNING … GitLabApiException: Invalid url given | 〇 | × | Outbound requestsの許可設定を有効化 |
私個人として、「なんかうまくいくときといかないときがある」という感じで、なんとなくGitLab Branch Sourceプラグインにいいイメージを持っていなかったのですが、コードを見たら「なんかうまくいくときといかないときがある」の原因もわかりすっきりしました(特に②が原因でした)。
問題があったときにはコードを読むのも大切だなぁと改めて実感した次第です。
宣伝
CI環境の構築は、一度動き始めてしまえば便利な反面、そこに至るまでの道のりは意外と険しいものです。本記事で紹介したような落とし穴は、実際に手を動かしてみて初めて気づくことも多く、「なぜか動かない」「なぜか結果が変わる」といった問題に頭を抱えた経験をお持ちの方も多いのではないでしょうか。
弊社テクマトリックスでは、JenkinsをはじめとしたCI環境の構築・導入支援を行っています。「自社でCI環境を整えたいが、何から始めればよいかわからない」「構築は進めているが、うまく動かずに困っている」といったお悩みをお持ちの場合は、ぜひお気軽にご相談ください。

また、Jenkinsのトレーニングも提供しています。Jenkinsの管理・運用の基礎から、パイプラインの書き方のベストプラクティス、チーム間でパイプラインの処理を再利用するための共有ライブラリの書き方まで、実践的な内容を幅広く扱っています。「社内でJenkinsを使いこなせるエンジニアを育てたい」「自分たちで運用・改善できる体制を整えたい」とお考えの方は、こちらもぜひご活用ください。

