0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitLab コンテナ構築手順(19.5.3-ee)

0
Last updated at Posted at 2026-11-01

1. 概要

前回作成した Hyper-V 上の VM に GitLab コンテナを構築します。

なお本記事は、上記の構築手順(リンク先)で 外部仮想スイッチも有効化している(内部スイッチ+外部スイッチの 2 枚構成) 場合の手順です。

※自分用の学習手順です。

2. 構築手順

コンテナなので、VM の作成に比べると手作業の設定は少なめです。
↑「コンテナ以外」の手順が多めですね…

2.1. IP アドレスの固定

自宅内の他の PC からも利用できるよう、(外部スイッチ側の)IP アドレスを固定します。内部+外部の 2 枚構成では、どちらの NIC に固定するかを先に特定してから設定します。

2.1.1. どの NIC が外部スイッチかを特定する

MAC アドレスを使用して、仮想スイッチが、VM のどの vNIC に紐づいているかを調べます。

なぜ MAC アドレスで特定できるのか

VM の仮想 NIC(vNIC)には焼き込み MAC アドレスが無く、ホストの Hyper-V が MAC アドレスを払い出します。1。

そのため、ホスト側 Get-VMNetworkAdapter に出る MAC(=VM アダプタの MAC)と、VM 内 ip link に出る MAC は一致します。

これは「仮想スイッチ自身の MAC アドレス」ではなく、同じ1枚の vNIC を、ホスト側と VM 側の両方から見ているだけです。

インターフェース名(eth0/eth1)は起動順で入れ替わりうるため、名前で決め打ちせず、この一致する MAC を手がかりに「どの NIC がどのスイッチに繋がっているか」を特定します。

2.1.1.1. ホスト側:MAC アドレスと接続先スイッチの対応を確認(PowerShell)

まずホスト側で、各 vNIC の MAC アドレスと接続先スイッチを確認します。

Get-VMNetworkAdapter -VMName "Rocky-Podman" | Format-Table Name, SwitchName, MacAddress
Name                    SwitchName           MacAddress
----                    ----------           ----------
ネットワーク アダプター InternalSwitch       00155D208614
ネットワーク アダプター ExternalSwitch       00155D208615
  • InternalSwitch(MAC 00155D208614)=管理用の内部スイッチ側
  • ExternalSwitch(MAC 00155D208615)=今回 IP を固定する外部スイッチ側

こちらはホストマシン側で確認しましたが、以降の手順は、VM に SSH 接続を行ったうえで実施します。

2.1.1.2. VM 側 の NIC の MAC アドレスと接続名の確認

VM 内で、各 NIC の MACアドレス(上記手順で調べた MAC アドレスと突き合わせる)と、NetworkManager の接続名を確認します。

ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:15:5d:20:86:14 brd ff:ff:ff:ff:ff:ff
    altname enx00155d208614
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:15:5d:20:86:15 brd ff:ff:ff:ff:ff:ff
    altname enx00155d208615
nmcli connection show
NAME        UUID                                  TYPE      DEVICE
有線接続 1  811d1f97-3615-3894-8a76-a82a35d6d732  ethernet  eth1
eth0        86dc9713-9dcf-3d24-a78b-37b39a3bfc2f  ethernet  eth0
lo          9ff953ee-925b-47b4-8e6e-8aedd3560d7b  loopback  lo

MAC アドレスを突き合わせると、外部スイッチ側(00:15:5d:20:86:15)は eth1 で、接続名は「有線接続 1」 だと特定できます(内部スイッチ側(00:15:5d:20:86:14)は eth0)。

2.1.2. 静的 IP とデフォルトルートの設定

2.1.2.1. 外部 NIC に静的 IP アドレスを設定

特定した外部側の接続名「有線接続 1」に、静的 IP アドレスを設定します。外部スイッチ側は既定の経路(デフォルトルート)を持たせたいので ipv4.never-default no にします。

sudo nmcli connection modify "有線接続 1" \
  ipv4.method manual \
  ipv4.addresses 192.168.11.200/24 \
  ipv4.gateway 192.168.11.1 \
  ipv4.dns "192.168.11.1 8.8.8.8" \
  ipv4.never-default no
sudo nmcli connection up "有線接続 1"
ip addr show eth1

2.1.2.2. デフォルトルートを1本に絞る(内部側を外す)

内部仮想スイッチ+外部仮想スイッチの2枚構成では、両方の NIC がデフォルトルートを持つ可能性があり、そうなると、外向きの通信が、どちらの NIC を通るか判別しにくくなります(Linux はメトリックの小さい方を既定にしますが、メトリックの大きさではなく、意図した経路に固定したい)。

そこで 内部スイッチ側(eth0)は管理専用としてデフォルトルートを持たせず、外部仮想スイッチ側(eth1)を既定の経路にします。

まず現状を確認します。

手順の通りに VM を作成するとデフォルトルートが2本できるはずです。

ip route show default
default via 192.168.100.1 dev eth0 proto static metric 100
default via 192.168.11.1 dev eth1 proto dhcp src 192.168.11.200 metric 101

内部側(eth0)のゲートウェイを外し、既定経路にならないようにします。

sudo nmcli connection modify "eth0" \
  ipv4.gateway "" \
  ipv4.never-default yes
sudo nmcli connection up "eth0"

設定後、デフォルトルートが外部側(eth1)の 1 本になっていることを確認します。

ip route show default
default via 192.168.11.1 dev eth1 proto static metric 103

経路が 1 本になったら、ゲートウェイ(192.168.11.1)へ実際に到達できるかを確認します。

ping -c 3 192.168.11.1
64 bytes from 192.168.11.1: icmp_seq=1 ttl=64 time=0.481 ms
64 bytes from 192.168.11.1: icmp_seq=2 ttl=64 time=0.402 ms
64 bytes from 192.168.11.1: icmp_seq=3 ttl=64 time=0.395 ms

--- 192.168.11.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

0% packet loss で応答が返れば、eth1 のリンクとゲートウェイ設定が正しく、外部 LAN へ出られる状態です(外向きまで確かめるなら ping -c 3 8.8.8.8 も通るはずです)。

設定後は以下のような構成になります。

SSH 先 どこから SSH の可否 理由
192.168.100.10(内部) Windows ホスト(.100.1) ✅ 通る 同じ内部セグメント(eth0 直結)
192.168.11.200(外部) 家 LAN の PC(.11.x) ✅ 通る 同じ物理 LAN(eth1 直結)
192.168.100.10(内部) 家 LAN の PC(.11.x) ❌ 届かない 内部スイッチは物理 LAN から隔離。経路が無く VM に到達しない

2.2. GitLab コンテナの作成

2.2.1. ディレクトリの作成

公式手順2に従い、任意の作業ディレクトリを作成し、その中に data, logs, config の3つのディレクトリを作成します。

# このコマンドで全て作成できます
mkdir -p ~/src/container/gitlab/volumes/{data,config,logs}

2.2.2. docker-compose.yaml の作成

直近で発生した脆弱性への対策を行っている gitlab-ee:19.5.3-ee.0 を使って、GitLab コンテナを作成します。

設定手順は後述しますが、http://gitlab.local でアクセス可能な構成にします(https://gitlab.local 化は §2.4・任意)。

cd ~/src/container/gitlab
# sudo dnf install nano
nano ./docker-compose.yaml
services:
  gitlab:
    image: gitlab/gitlab-ee:19.5.3-ee.0
    container_name: gitlab
    restart: unless-stopped
    hostname: gitlab.local
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.local'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        gitlab_rails['time_zone'] = 'Asia/Tokyo'
        gitlab_rails['trusted_proxies'] = ['127.0.0.1', '192.168.100.10']
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
    ports:
      - "9080:80"
      - "9443:443"
      - "2222:22"
    volumes:
      - ./volumes/config:/etc/gitlab:Z
      - ./volumes/logs:/var/log/gitlab:Z
      - ./volumes/data:/var/opt/gitlab:Z
    shm_size: '256m'
    init: true
docker-compose.yaml の各要素の解説

2.2.2.1. image: gitlab/gitlab-ee:19.5.3-ee.0

使うコンテナイメージと版。gitlab-ee はライセンス未投入なら CE 相当の無償機能で動く。版は執筆時点の最新パッチ(構築時は最新を確認)。本番環境では版を特定して固定するのが公式推奨3。

2.2.2.2. container_name: gitlab

コンテナ名を固定。podman exec -it gitlab … のように名前で操作できる。

2.2.2.3. restart: unless-stopped

明示的に停止した場合を除き自動再起動。VM 再起動後もコンテナが復帰する。

2.2.2.4. hostname: gitlab.local

コンテナ自身のホスト名。

2.2.2.5. environment: GITLAB_OMNIBUS_CONFIG

GitLab の設定(gitlab.rb 相当)を環境変数でまとめて事前投入する。

2.2.2.5.1. external_url 'http://gitlab.local'

GitLab が生成する URL(clone URL・メール・Webhook 等)の基準。ブラウザで実際にアクセスする URL と一致させる必要がある4。

2.2.2.5.2. gitlab_rails['gitlab_shell_ssh_port'] = 2222

git の SSH クローン URL に出るポート。ホストの sshd:22 と衝突しないよう 2222 にずらしている。

2.2.2.5.3. gitlab_rails['time_zone'] = 'Asia/Tokyo'

表示・記録時刻を JST にする。

2.2.2.5.4. gitlab_rails['trusted_proxies'] = ['127.0.0.1', '192.168.100.10']

前段のリバースプロキシ(httpd)の IP を信頼する設定。これで実クライアント IP を X-Forwarded-For から正しく取得できる。この IP は後述の httpd 構成に合わせる。

2.2.2.5.5. nginx['listen_port'] = 80

内蔵 nginx の Listen ポート。external_url からポート番号を外したことに合わせる(コンテナ内部の話)。

2.2.2.5.6. nginx['listen_https'] = false

内蔵 nginx の HTTPS を無効化(HTTPS は前段の httpd 側で終端する設計余地を残す)。

2.2.2.6. ports:

ホスト:コンテナ でポートを公開。9080→80(HTTP)・9443→443(HTTPS)・2222→22(git SSH)。rootless では 80/443 等の低ポートを直接公開しづらいため高番ポートに寄せている。

2.2.2.7. volumes:

永続データのマウント。config→/etc/gitlab(設定・secrets)・logs→/var/log/gitlab・data→/var/opt/gitlab(リポジトリ・DB)。

末尾の :Z は SELinux のラベル付け(Rocky など enforcing 環境で必要)5。

2.2.2.8. shm_size: '256m'

/dev/shm(共有メモリ)のサイズ。

GitLab が要求するため明示。

2.2.2.9. init: true

PID 1 に init プロセスを置き、ゾンビプロセスを回収する。

上記以外の標準キー(restart/ports/volumes/shm_size/init)は Docker 公式 Compose file reference — Services、説明文を割愛した GitLab 固有設定(gitlab_shell_ssh_port/time_zone/trusted_proxies/nginx['listen_port']/nginx['listen_https'])は GitLab 公式の Docker 設定・NGINX settings・SSL を参照。

2.2.3. コンテナの起動

作成した docker-compose.yaml があるディレクトリ(~/src/container/gitlab)で、コンテナを起動します。

docker-compose up -d
[+] up 13/13
 ✔ Image gitlab/gitlab-ee:19.5.3-ee.0 Pulled    74.3s
 ✔ Network gitlab_default             Created     0.0s
 ✔ Container gitlab                   Started     0.3s

初回は、イメージの取得に加えて GitLab が内部の初期化(reconfigure)を行うため、使えるようになるまで数分かかります。この reconfigure の中で、データディレクトリの所有者の調整(fixing permissions … ok)も行われます。

2.2.4. 起動確認

2.2.4.1. コンテナの健全性

docker-compose ps

STATUS が Up … になっていれば、コンテナは起動しています(Podman では (healthy) 表示が出ないこともあるので、確実な判定は次の 2.2.4.2)。

2.2.4.2. GitLab 内部サービスの状態

podman exec gitlab gitlab-ctl status
run: alertmanager: (pid 689) 284s; run: log: (pid 679) 284s
run: gitaly: (pid 558) 285s; run: log: (pid 555) 285s
run: gitlab-exporter: (pid 692) 284s; run: log: (pid 677) 284s
run: gitlab-kas: (pid 553) 285s; run: log: (pid 550) 285s
run: gitlab-workhorse: (pid 681) 284s; run: log: (pid 674) 284s
run: logrotate: (pid 554) 285s; run: log: (pid 551) 285s
run: nginx: (pid 675) 284s; run: log: (pid 672) 284s
run: postgres-exporter: (pid 690) 284s; run: log: (pid 678) 284s
run: postgresql: (pid 559) 285s; run: log: (pid 556) 285s
run: prometheus: (pid 671) 284s; run: log: (pid 670) 284s
run: puma: (pid 833) 266s; run: log: (pid 676) 284s
run: redis: (pid 557) 285s; run: log: (pid 552) 285s
run: redis-exporter: (pid 669) 284s; run: log: (pid 668) 284s
run: sidekiq: (pid 882) 256s; run: log: (pid 673) 284s
run: sshd: (pid 36) 291s; run: log: (pid 35) 291s

すべて run: になっていれば OK です(down: があれば、そのサービス名でログを確認します)。

2.2.4.3. HTTP の応答確認(ヘルスチェック)

GitLab が Web として応答するかを確認します。監視用のエンドポイントは既定で ローカル IP からのみ アクセスできるので6、コンテナの中(localhost)から叩きます(ホストから :9080 経由だと送信元がローカル扱いにならず 404 になります)。

podman exec gitlab curl -s -X GET http://localhost/-/health && echo
GitLab OK

2.2.4.4. 依存サービス(DB・Redis・Gitaly 等)も含めた確認(readiness)

上記の /-/health で、アプリケーションサーバの稼働については確認できますが、データベース等の依存サービスは検証しません。

各サービスまで含めて確認するには readiness を使います。?all=1 で依存サービスも検証です7。

1 行で返るので python3 -m json.tool で整形します。

podman exec gitlab curl -s -X GET 'http://localhost/-/readiness?all=1' | python3 -m json.tool
出力結果

以下のように、すべて "status": "ok" なら、依存サービスまで含めて正常です。

{
    "status": "ok",
    "master_check": [
        {
            "status": "ok"
        }
    ],
    "db_check": [
        {
            "status": "ok"
        }
    ],
    "cache_check": [
        {
            "status": "ok"
        }
    ],
    "concurrency_limit_check": [
        {
            "status": "ok"
        }
    ],
    "db_load_balancing_check": [
        {
            "status": "ok"
        }
    ],
    "feature_flag_check": [
        {
            "status": "ok"
        }
    ],
    "queues_check": [
        {
            "status": "ok"
        }
    ],
    "queues_metadata_check": [
        {
            "status": "ok"
        }
    ],
    "rate_limiting_check": [
        {
            "status": "ok"
        }
    ],
    "repository_cache_check": [
        {
            "status": "ok"
        }
    ],
    "sessions_check": [
        {
            "status": "ok"
        }
    ],
    "shared_state_check": [
        {
            "status": "ok"
        }
    ],
    "trace_chunks_check": [
        {
            "status": "ok"
        }
    ],
    "chat_check": [
        {
            "status": "ok"
        }
    ],
    "workhorse_check": [
        {
            "status": "ok"
        }
    ],
    "gitaly_check": [
        {
            "status": "ok",
            "labels": {
                "shard": "default"
            }
        }
    ]
}

2.2.4.5. アプリケーションサーバーの稼働確認(liveness)

liveness で、アプリケーションサーバ(Rails)がマルチスレッドでデッドロックしていないかを確認できます8。

podman exec gitlab curl -s -X GET 'http://localhost/-/liveness' | python3 -m json.tool
{
    "status": "ok"
}

2.2.5. 初期パスワード

初期管理者(root)のパスワードは、config 配下に自動生成されています9。

cat ~/src/container/gitlab/volumes/config/initial_root_password

この値は §2.3.6 でブラウザからログインするときに使います(パスワードの変更は §2.3.7)。なお このファイルは、初回起動から 24 時間経過後の最初のコンテナ再起動で自動削除されます10。

ブラウザから http://gitlab.local で開けるようにする設定(名前解決+リバースプロキシ)は、次の §2.3(リバースプロキシとブラウザアクセス)で行います。ここでは「コンテナが起動し、GitLab が応答する」ところまでを確認しました。

2.3. リバースプロキシとブラウザアクセス

§2.2.2(docker-compose.yaml の作成)では、external_url 'http://gitlab.local'(ポート番号なし)で構成しています。

ブラウザから http://gitlab.local でアクセスできるよう、VM 上に httpd(Apache) を置き、ポート 80 でリクエストを受けて、GitLab コンテナ(:9080)へ転送します。

rootless コンテナは :80 を直接は扱えませんが、httpd(root 権限)なら :80 を受けられます。

作業前に補足 — プロキシとは(リバース/フォワード)

「プロキシ(proxy)」は、通信を代理で受けて中継する役のことです。向きで2種類あります。

  • フォワードプロキシ:利用者(クライアント)側の代理の役割(利用者を隠す・制御する)を担います。社内 PC から外部サイトへのアクセスをまとめて中継し、社内 PC そのものを特定できないようにします(プロキシサーバーが代わりになる)。
  • リバースプロキシ:サーバー(※ここではハードウェアではなくソフトウェアのこと)側の代理の役割(サーバーの内部構成を隠す・保護する)を担います。外部からのアクセスをサーバーの代わりにまとめて受け、裏にある実サーバーへ取り次ぎます。利用者からは代理(プロキシ)しか見えず、その裏にいるサーバーの構成やポートは分かりません。

今回置く httpd はリバースプロキシです。

ブラウザからは手前の httpd しか見えず、裏の GitLab コンテナ(:9080)やポート番号は隠れます。「:80 の受付係が、裏の GitLab に取り次ぐ」イメージです。

2.3.1. httpd のインストール

sudo dnf install -y httpd

(mod_proxy / mod_proxy_http / mod_headers は Rocky では同梱・有効です。)

2.3.2. リバースプロキシ設定

設定ファイルを作成します。

sudo nano /etc/httpd/conf.d/gitlab.conf
<VirtualHost *:80>
    ServerName gitlab.local

    # GitLab コンテナへ転送
    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass        / http://127.0.0.1:9080/
    ProxyPassReverse / http://127.0.0.1:9080/

    # 元のホスト情報を GitLab に伝える
    RequestHeader set X-Forwarded-Proto "http"
    RequestHeader set X-Forwarded-Ssl   "off"

    # 大きい push に備える
    LimitRequestBody 0
    ProxyTimeout 300

    ErrorLog  /var/log/httpd/gitlab_error.log
    CustomLog /var/log/httpd/gitlab_access.log combined
</VirtualHost>
gitlab.conf の各要素の解説

2.3.2.1. <VirtualHost *:80> / ServerName gitlab.local

:80 に来たリクエストのうち、ホスト名が gitlab.local のものに対する設定をまとめる仮想ホスト。ServerName がこのブロックの対象ホスト名。

仮想ホストについて

1台の Apache で複数のサイト(ホスト名)を扱い分ける仕組みです。

届いた HTTP リクエストの Host: ヘッダを見て、合致する <VirtualHost> ブロックで処理します11。

今回の場合、*:80 となっているので、*(全 IP アドレス)で、ポート 80 に来たリクエストを対象にします。

そして、そのリクエストのうち、ホスト名が gitlab.local のリクエストを対象とします。複数のサービスがある場合は、フィルタのように機能します(一致するものだけを見る)12。

※先頭の1つ目が既定値となり、一致するものが無い場合は、それが参照されます13。

2.3.2.2. ProxyPreserveHost On

受信した Host: ヘッダ(gitlab.local)を、そのまま背後の GitLab へ渡す(既定は Off=転送先 URL のホスト名に書き換わる)。GitLab は external_url と来訪ホストの一致を前提にするため On にする14。

2.3.2.3. ProxyRequests Off

フォワードプロキシ(クライアント→外部を中継する一般プロキシ)機能を無効化する。リバースプロキシ構成では Off が推奨で、これは ProxyPass による転送を妨げない15。

2.3.2.4. ProxyPass / http://127.0.0.1:9080/

転送の本体。/(全パス)への要求を、背後の 127.0.0.1:9080(公開した GitLab コンテナのポート)へ中継する16。

2.3.2.5. ProxyPassReverse / http://127.0.0.1:9080/

背後が返す応答ヘッダ(Location など)に含まれる URL を、クライアントから見える URL に書き換える。リダイレクト時の URL ずれを防ぐ17。

2.3.2.6. RequestHeader set X-Forwarded-Proto "http" / X-Forwarded-Ssl "off"

「元はどのプロトコルで来たか」を背後の GitLab に伝えるヘッダ。ここは HTTP なので http/off(HTTPS 化する §2.4 では https/on に変える)18。

2.3.2.7. LimitRequestBody 0

リクエストボディのサイズ上限(バイト)。0 は無制限。大きな git push が弾かれないようにする19。

2.3.2.8. ProxyTimeout 300

プロキシ要求のネットワークタイムアウト(秒)。重い処理で途中切断されないよう余裕を取る20。

2.3.2.9. ErrorLog / CustomLog

このバーチャルホスト専用のログ出力先(Rocky は /var/log/httpd/ 配下)21。CustomLog の combined はアクセスログの標準フォーマット22。

2.3.3. httpd の起動

2.3.3.1. 自動起動設定

設定ファイルの文法を確認してから起動します。

sudo httpd -t

Syntax OK が出たら、起動して自動起動も有効化します。

sudo systemctl enable --now httpd

:80 で待ち受けている(LISTEN)か確認します。

sudo ss -ltnp | grep ':80'
LISTEN 0      511                *:80              *:*    users:(("httpd",pid=51649,fd=4),("httpd",pid=51638,fd=4),("httpd",pid=51637,fd=4),("httpd",pid=51634,fd=4))

出力のように httpd が *:80 で LISTEN していれば、起動成功です(pid は環境により異なります)。

ss -ltnp の出力の読み方

列は左から State / Recv-Q / Send-Q / Local Address:Port / Peer Address:Port / Process(この Recv-Q/Send-Q 列の定義は netstat(8) に記載されており、ss も同じ列を表示します)23。

  • LISTEN(State)=接続を待ち受けている状態。
  • 0(Recv-Q)=待ち受けソケットでは 現在の接続待ちキュー(backlog)の長さ。0 は処理待ちなし(正常)。
  • 511(Send-Q)=待ち受けソケットでは backlog の最大値。
  • ***:80=全アドレスの :80 で待ち受け/*:***=相手(Peer)は未定なのでワイルドカード。
  • **users:(("httpd",pid=…))**=そのソケットを持つプロセス(-p で表示)。

なお Recv-Q/Send-Q は確立済み接続では意味が変わり、それぞれ「未コピーの受信バイト数/未 ACK の送信バイト数」になります。

2.3.3.2. 動作確認

動作確認として、httpd 経由で localhost にアクセスします。

curl -I http://localhost/
HTTP/1.1 302 Found
Server: nginx
Location: http://localhost/users/sign_in
...(ヘッダは省略)

Server: nginx と GitLab 由来のヘッダ(Location: …/users/sign_in など)が返れば、httpd → GitLab の転送は成功です。次は、2.3.4.2. ファイアウォール(他の PC から開くため :80 を開放) を実施してください(§2.3.4.1 の SELinux 設定は不要です)。

一方、ここで curl が失敗(502/503)した場合、2.3.4.1. SELinux の確認 から実施してください。

2.3.4. SELinux とファイアウォール

SELinux とは

SELinux(Security-Enhanced Linux)は、各プロセスが「何にアクセスしてよいか」を強制的に制限する Linux のセキュリティ機構です(RHEL 系では既定で有効=Enforcing)。許可は ブール(boolean) で on/off スイッチで切り替えます。

リバースプロキシでは「httpd が裏のポート(127.0.0.1:9080)へ接続してよいか」が SELinux で問われることがあり、環境によっては httpd_can_network_connect というブールの有効化が必要になります24。

2.3.4.1. SELinux の確認

このステップは、§2.3.3.2 の curl が 502/503 で失敗した場合に実施します(成功していれば不要なので §2.3.4.2 へ)。SELinux が httpd の外向き接続(→ 127.0.0.1:9080)を拒否している可能性があるので、まず拒否が記録されているかを確認します。

sudo ausearch -m avc -ts recent

ausearch と AVC とは

ausearch は、監査ログ(auditd が記録するログ)から記録を検索するコマンドです。SELinux が何かの操作を拒否すると、AVC(Access Vector Cache)denial という監査ログが残ります。

  • -m avc … メッセージ種別を AVC(SELinux の拒否)だけに絞る。
  • -ts recent … 直近ぶんだけに絞る(recent は「10 分前以降」)25。

拒否があると type=AVC … denied { name_connect } … comm="httpd" のような行が出ます。何も無ければ <no matches>(直近に SELinux の拒否は記録されていない)と表示されます。

確認結果で分岐します。

  • httpd の拒否(denied { name_connect } など)が出ている → 下の手順でブールを許可します。
  • <no matches>(拒否が無い) → 原因は SELinux ではありません。GitLab コンテナの起動状況(docker-compose ps/gitlab-ctl status)や ProxyPass の 9080 を見直してください。

httpd の外向き接続を許可します24(-P は再起動後も維持する恒久指定)。

sudo setsebool -P httpd_can_network_connect on

許可後、再度 curl -I http://localhost/ が 302/200 を返せば OK です。続いて 2.3.4.2. ファイアウォール(他の PC から開くため :80 を開放) へ進んでください。

2.3.4.2. ファイアウォール(他の PC から開くため :80 を開放)

localhost からのテストには不要ですが、他の PC のブラウザから http://gitlab.local を開くには :80 の開放が必要です。

sudo firewall-cmd --permanent --add-service=http && sudo firewall-cmd --reload

2.3.5. 名前解決(gitlab.local)

gitlab.local は実在ドメインではないので、アクセスする PC の hosts に VM の IP(§2.1 で固定した外部 IP)を登録します。

  • Windows:C:\Windows\System32\drivers\etc\hosts(管理者権限で編集)
  • macOS / Linux:/etc/hosts
192.168.11.200  gitlab.local

2.3.6. 動作確認(ブラウザ)

ここまでで、2.3.3.2. 動作確認 で VM 内の curl -I http://localhost/ が 302 を返す(httpd → GitLab の転送が成功する)ことは確認済みです。

次は、アクセスする PC のブラウザに http://gitlab.local を入力し、GitLab のログイン画面が出ることを確認しましょう。ログイン情報は以下の通りです。

ログインできれば、リバースプロキシ経由のアクセスは完成です。続けて初期設定を行います。

2.3.7. 初期設定

ログイン直後にやっておきたい初期設定です。以降の画面を日本語で進められるよう、まず表示言語を日本語に切り替えます。

2.3.7.1. 表示を日本語・JST にする

① 表示言語を日本語に(初回ログイン時は英語表示なので、英語メニューで操作します)

右上のアバター → Preferences → ページ下部の Localization → Language で「日本語」を選び、Save changes。これで以降の画面が日本語になります。

Language のドロップダウンには「翻訳は実験的で未完成」という注記があり、実際に管理エリアなどは日本語と英語が混在します(Access などは未翻訳のまま)。本記事はこれ以降、UI ラベルを 日本語(英語) で併記します。

② 表示タイムゾーンを JST に

右上のアバター → プロフィールの編集(Edit profile)→ タイムゾーンの設定 → タイムゾーン で (UTC+09:00) Osaka, Sapporo, Tokyo を選び、保存します。

サーバ側の時刻は §2.2.2 の gitlab_rails['time_zone'] = 'Asia/Tokyo' で既に JST です。ここで変えるのは表示(自分のアカウント)側のタイムゾーンです。時刻を 24 時間表示にしたい場合は、設定(Preferences)→ 時間設定(Time preferences)で切り替えられます。

2.3.7.2. プロフィールの設定

右上のアバター → プロフィールの編集(Edit profile)で、表示名などを設定します(初回ログイン直後に Set up your profile が英語で表示された場合は、そこで入力しても構いません)。

  • フルネーム(Full name)… 表示名
  • メールアドレス(Email)
  • 組織(Organization)… 任意。1人運用では表示ラベルにすぎないので HomeLab など何でもよい(後から変更可)
  • ユーザー名(Username)は root

2.3.7.3. パスワードの変更

初期パスワード(2.2.5. 初期パスワード)は自動生成の暫定値なので、自分のパスワードに変更します(セキュリティのため)。

右上のアバター → プロフィールの編集(Edit profile)→ 左メニュー アクセス(Access)→ パスワードと認証(Password and authentication)→ パスワードを変更(Change password)。

2.3.7.4. サインアップ(新規登録)の無効化

GitLab は既定で 新規アカウント作成(サインアップ)が可能です(既定では作成時に管理者の承認が必要なので即利用はされませんが26)。公開を想定しない自宅 LAN の個人インスタンスでは、サインアップ自体を無効化しておくのが簡潔で安全です(公式も、公開ユーザーの登録を想定しないなら無効化の検討を推奨しています)26。

管理エリア(Admin)→ 設定(Settings)> 一般(General)→「新しいユーザーアカウントの制限」(New user account restrictions)を開き、「新規ユーザーアカウントを許可する」(Allow new user accounts)のチェックを外して保存します26。

管理エリアのダッシュボード「概要」パネルにある サインアップ 行の歯車アイコンからも、この設定へ直接ジャンプできます。

2.3.7.5. Web IDE のシングルオリジンフォールバックを無効化

管理ダッシュボードに「Web IDE and single origin fallback is enabled」という警告が出ることがあります。これは、Web IDE(VS Code ベース)の拡張ホストが読み込めないときに VS Code のアセットを同一オリジンで肩代わりする機能(single origin fallback)が既定で有効なためで、攻撃面が増えるセキュリティリスクがあります27。

Web IDE を使わない想定なので、このフォールバックを無効化しておきます。

管理エリア(Admin)→ 設定(Settings)> 一般(General)→ Web IDE を開き、「単一オリジンフォールバックを有効にする」(Enable single origin fallback)のチェックを外して 変更を保存(Save changes)します27。

2.3.7.6. 最初のプロジェクトを作成(任意)

Create your first project(最初のプロジェクトを作成)から、動作確認用のプロジェクトを作ってみましょう(スキップしても構いません)。

2.4. HTTPS 化(自己署名証明書・任意)

任意ステップです。 HTTP(§2.3)のままでも GitLab は使えます。ここでは https://gitlab.local でアクセスできるようにします。

gitlab.local は公開ドメインではないため公的証明書(Let's Encrypt 等)は取得できません。そこで 自己署名証明書 を使います。ブラウザは「この接続ではプライバシーが保護されません」と警告しますが、これは仕様です(閉じた環境では「詳細 → 続行」で進めます)。暗号化は httpd の :443 で終端し、内部の GitLab へは平文 HTTP で取り次ぎます。

ブラウザ → :443 暗号化(TLS) → httpd(TLS 終端)→ 127.0.0.1:9080 → GitLab コンテナ

2.4.1. 自己署名証明書の作成

証明書と TLS のしくみ(自己署名とは)

HTTPS は、通信を暗号化し「接続先が本物か」を確かめる仕組み(TLS)です。その中心が サーバー証明書で、「このドメイン名(gitlab.local)は、この公開鍵の持ち主のものだ」という対応を示します。

  • 証明書は 公開鍵と秘密鍵のペアで機能します。ここで作る gitlab.local.crt(証明書=公開鍵入り)と gitlab.local.key(秘密鍵)がそれです。秘密鍵は門外不出(だから後で chmod 600、Git にも上げない)。
  • 通常は 認証局(CA) が「この証明書は本物」と署名し、ブラウザは最初から主要 CA を信頼しているため警告は出ません(Let's Encrypt などの公的 CA)。
  • 自己署名(self-signed) は、CA を通さず自分で自分の証明書に署名したものです。暗号化はできますが「第三者(CA)のお墨付き」が無いため、ブラウザは「信頼できない」と警告します(閉じた自宅用途では許容)。
  • SAN(subjectAltName) は、証明書が「どのホスト名に有効か」を書く欄です。SAN のホスト名がアクセス先と一致するかで本人性が照合され、古い CN 欄は非推奨です28。だから SAN に DNS:gitlab.local を必ず入れます。
  • コマンドの -x509 は「証明書そのものを出力(=自己署名)」、rsa:2048 は鍵長、-nodes は秘密鍵を暗号化しない(起動時パスフレーズ不要)、-days 825 は有効期限(日)です。

subjectAltName(SAN)に DNS:gitlab.local を必ず含めます(近年のブラウザは CN ではなく SAN で照合するため)。

openssl コマンドが無い場合は先に入れます(Rocky の最小構成では未インストールのことがあります)。

sudo dnf install -y openssl

続けて、証明書と秘密鍵を作成します。

sudo openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout /etc/pki/tls/private/gitlab.local.key \
  -out    /etc/pki/tls/certs/gitlab.local.crt \
  -days 825 \
  -subj "/C=JP/ST=Tokyo/L=Tokyo/O=Home/CN=gitlab.local" \
  -addext "subjectAltName=DNS:gitlab.local"
sudo chmod 600 /etc/pki/tls/private/gitlab.local.key

秘密鍵(gitlab.local.key)は Git に上げないこと(volumes/ と同様、リポジトリ管理外に置く)。

2.4.2. mod_ssl の導入

sudo dnf install -y mod_ssl
sudo systemctl restart httpd

mod_ssl を入れると /etc/httpd/conf.d/ssl.conf が自動生成され、サンプルの <VirtualHost _default_:443> が含まれます。次の gitlab.conf の :443 と二重定義にならないよう、ssl.conf 側の <VirtualHost> はコメントアウトしておきます。

2.4.3. :443 VirtualHost を追加

§2.3.2 で作った /etc/httpd/conf.d/gitlab.conf を、次の 2 ブロック構成に書き換えます(:80 は :443 へリダイレクト、:443 で TLS 終端)。

sudo nano /etc/httpd/conf.d/gitlab.conf
# ① HTTP(:80) は HTTPS(:443) へリダイレクト
<VirtualHost *:80>
    ServerName gitlab.local
    Redirect permanent / https://gitlab.local/
</VirtualHost>

# ② HTTPS(:443) で TLS 終端し、GitLab コンテナへ取り次ぐ
<VirtualHost *:443>
    ServerName gitlab.local

    SSLEngine on
    SSLCertificateFile    /etc/pki/tls/certs/gitlab.local.crt
    SSLCertificateKeyFile /etc/pki/tls/private/gitlab.local.key

    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass        / http://127.0.0.1:9080/
    ProxyPassReverse / http://127.0.0.1:9080/

    # 「HTTPS で来た」と GitLab に伝える
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Ssl   "on"

    LimitRequestBody 0
    ProxyTimeout 300

    ErrorLog  /var/log/httpd/gitlab_ssl_error.log
    CustomLog /var/log/httpd/gitlab_ssl_access.log combined
</VirtualHost>
sudo httpd -t && sudo systemctl reload httpd

Syntax OK を確認してから reload します。

2.4.4. compose を HTTPS 既定に変更

2.2.2. docker-compose.yaml の作成 で作成した docker-compose.yaml を、HTTPS 用に下記へ書き換えます(external_url を https にし、Let's Encrypt の自動取得を無効化。gitlab.local は外部到達不可で取得に失敗するため)。

nano docker-compose.yaml
services:
  gitlab:
    image: gitlab/gitlab-ee:19.5.3-ee.0
    container_name: gitlab
    restart: unless-stopped
    hostname: gitlab.local
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.local'  # ← https に変更(§2.2.2 では http)
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        gitlab_rails['time_zone'] = 'Asia/Tokyo'
        gitlab_rails['trusted_proxies'] = ['127.0.0.1', '192.168.100.10']
        nginx['listen_port'] = 80  # 内部は HTTP のまま(TLS は前段の httpd で終端)
        nginx['listen_https'] = false  # HTTPS は httpd が担当するので無効
        letsencrypt['enable'] = false  # ← 追加:自己署名で終端するため Let's Encrypt の自動取得を無効化(必須)
    ports:
      - "9080:80"
      - "9443:443"
      - "2222:22"
    volumes:
      - ./volumes/config:/etc/gitlab:Z
      - ./volumes/logs:/var/log/gitlab:Z
      - ./volumes/data:/var/opt/gitlab:Z
    shm_size: '256m'
    init: true

external_url を https:// にしたのに nginx['listen_https'] = true だと、GitLab が自前の証明書を要求して起動に失敗します。TLS は httpd 側で終端するので listen_https = false / listen_port = 80 を維持します。

変更後に再起動します。

cd ~/src/container/gitlab && docker-compose down && docker-compose up -d

コンテナを作り直すと、GitLab の再構成(reconfigure)に数分かかります。

その間に https://localhost/ を叩くと 502 Proxy Error(httpd は動いているが GitLab がまだ応答できない)になります。

docker-compose ps が Up かつ、podman exec gitlab gitlab-ctl status が全て run: になってから、次に進んでください。

2.4.5. ファイアウォール(:443 を開放)

sudo firewall-cmd --permanent --add-service=https && sudo firewall-cmd --reload

2.4.6. 動作確認

VM 内で HTTPS 応答と証明書の SAN を確認します(-k は自己署名警告を無視)。

curl -kI https://localhost/
HTTP/1.1 302 Found
Server: nginx
Location: https://localhost/users/sign_in
...(ヘッダは省略)
echo | openssl s_client -connect localhost:443 -servername gitlab.local 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
            X509v3 Subject Alternative Name:
                DNS:gitlab.local

HTTP/1.1 302(または 200)で Location: が https:// になり、SAN に DNS:gitlab.local が表示されれば OK です。あとはブラウザで https://gitlab.local を開き、警告を「続行」すればログイン画面が出ます(http://gitlab.local は https へ自動リダイレクトされます)。

再起動直後に 502 Proxy Error(Server: Apache …)が返るのは、GitLab がまだ起動(再構成)中なだけです。数分待って docker-compose ps が Up・gitlab-ctl status が全て run: になってから、もう一度 curl -kI https://localhost/ を叩くと Server: nginx の 302 が返ります。

3. 脚注

  1. https://learn.microsoft.com/ja-jp/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn425042(v=ws.11)#mac-addressing-in-hyper-v — With Hyper-V, you can configure a virtual machine to use a dynamic or a static MAC address. The default option is to use a dynamic MAC address, which means that Hyper-V will generate a MAC address for the network adapter. ↩

  2. https://docs.gitlab.com/19.5/install/docker/installation/#create-a-directory-for-the-volumes — Create a directory for the configuration files, logs, and data files. The directory can be in your user’s home directory (for example ~/gitlab-docker), or in a directory like /srv/gitlab. If you’re running Docker with a user other than root, grant the appropriate permissions to the user for the new directory. ↩

  3. https://docs.gitlab.com/19.5/install/docker/installation/ — In a production environment, you should pin your deployment to a specific GitLab version. ↩

  4. https://docs.gitlab.com/19.5/install/docker/configuration/ — Set the external_url field to a valid URL for your GitLab instance. ↩

  5. https://docs.podman.io/en/latest/markdown/podman-run.1.html — add either of two suffixes :z or :Z to the volume mount. These suffixes tell Podman to relabel file objects on the shared volumes. ↩

  6. https://docs.gitlab.com/19.5/administration/monitoring/health_check/#using-the-endpoints-locally — With default allowlist settings, the probes can be accessed from localhost using the following URLs: GET http://localhost/-/health, GET http://localhost/health_check, GET http://localhost/-/readiness, GET http://localhost/-/liveness ↩

  7. https://docs.gitlab.com/19.5/administration/monitoring/health_check/#readiness — The readiness probe checks whether the GitLab instance is ready to accept traffic via Rails Controllers. If the all=1 parameter is specified, the check also validates the dependent services (Database, Redis, Gitaly etc.) and gives a status for each. ↩

  8. https://docs.gitlab.com/19.5/administration/monitoring/health_check/#liveness — Checks whether the application server is running. This probe is used to know if Rails Controllers are not deadlocked due to a multi-threading. ↩

  9. https://docs.gitlab.com/19.5/install/docker/installation/#install-gitlab-by-using-docker-engine — Visit the GitLab URL, and sign in with the username root and the password from the following command: sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password ↩

  10. https://docs.gitlab.com/19.5/install/docker/installation/ — The password file is automatically deleted in the first container restart after 24 hours. ↩

  11. https://httpd.apache.org/docs/2.4/en/vhosts/name-based.html#namevip — With name-based virtual hosting, the server relies on the client to report the hostname as part of the HTTP headers. Using this technique, many different hosts can share the same IP address. ↩

  12. https://httpd.apache.org/docs/2.4/en/vhosts/name-based.html#alg — When a request arrives, the server will find the best (most specific) matching <VirtualHost> argument based on the IP address and port used by the request. If there is more than one virtual host containing this best-match address and port combination, Apache will further compare the ServerName and ServerAlias directives to the server name present in the request. ↩

  13. https://httpd.apache.org/docs/2.4/en/vhosts/name-based.html#defaultvhost — If no matching ServerName or ServerAlias is found in the set of virtual hosts containing the most specific matching IP address and port combination, then the first listed virtual host that matches that will be used. ↩

  14. https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypreservehost — Use incoming Host HTTP request header for proxy request ↩

  15. https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxyrequests — Enables forward (standard) proxy requests ↩

  16. https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypass — Maps remote servers into the local server URL-space ↩

  17. https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypassreverse — Adjusts the URL in HTTP response headers sent from a reverse proxied server ↩

  18. https://httpd.apache.org/docs/2.4/mod/mod_headers.html#requestheader — Configure HTTP request headers ↩

  19. https://httpd.apache.org/docs/2.4/mod/core.html#limitrequestbody — Restricts the total size of the HTTP request body sent from the client ↩

  20. https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxytimeout — Network timeout for proxied requests ↩

  21. https://httpd.apache.org/docs/2.4/mod/core.html#errorlog — Location where the server will log errors ↩

  22. https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#customlog — Sets filename and format of log file ↩

  23. https://www.mankier.com/8/netstat — Recv-Q — Established: The count of bytes not copied by the user program connected to this socket. Listening: Since Kernel 2.6.18 this column contains the current syn backlog. Send-Q — Established: The count of bytes not acknowledged by the remote host. Listening: Since Kernel 2.6.18 this column contains the maximum size of the syn backlog. ↩

  24. https://www.mankier.com/8/httpd_selinux — If you want to allow HTTPD scripts and modules to connect to the network using TCP, you must turn on the httpd_can_network_connect boolean. Disabled by default. ↩ ↩2

  25. https://www.mankier.com/8/ausearch — -m (message type): Message types are also known as record types. -ts (start time): ... equal to or after the given start time. ... Recent is 10 minutes ago. ↩

  26. https://docs.gitlab.com/19.5/administration/settings/sign_up_restrictions/ — Require administrator approval for new user accounts — This setting is enabled by default for new GitLab instances. ... recommend that you consider disabling new accounts if you do not expect public users to create accounts. ... prevent new account creation: In the upper-right corner, select Admin. In the left sidebar, select Settings > General. Expand New user account restrictions. Clear the Allow new user accounts checkbox, then select Save changes. ↩ ↩2 ↩3

  27. https://docs.gitlab.com/19.5/administration/settings/web_ide/ — The single origin fallback is enabled by default and has security risks. ... In the upper-right corner, select Admin. In the left sidebar, select Settings > General. Expand Web IDE. ... Select or clear the Enable single origin fallback checkbox ... Select Save changes. ↩ ↩2

  28. https://www.rfc-editor.org/rfc/rfc2818#section-3.1 — If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. ↩

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?