Linux/CentOS Stream 9

GitLab Docker 설치하고 Apache 리버스 프록시로 HTTPS 적용하기

Ryan's Tech Note 2025. 5. 24. 21:09

GitLab Docker 설치하고 Apache 리버스 프록시로 HTTPS 적용하기 (feat. ModSecurity 403 에러 해결)

GitLab 서버를 구축하면서 삽질했던 내용을 정리합니다.

 

공유기 아래, 서버가 2대 있는데, 서버1에서 기존 웹 서비스를 운영하다가 gitlab을 설치하려고 보니 메모리를 4GB~8GB 먹어서 메모리가 부족해서 서버2로 gitlab 을 설치하려는 상황인데, 서버2에는 이미 80 서비스를 하고 있었습니다. 그래서 gitlab 이 서버2의 8080 포트를 쓰게된 상황입니다.

 

이때, git.example.com 도메인 인증서가 서버1에서 통합되서 관리되고 있고 80포트가 서버1로 가게 되어 있었기에, 공유기에서 바로 서버2로 오지 않고, 서버1로 간 후 Apache로 Reserver Proxy 를 타고 서버2로 오게된 상황입니다.

 

이 구성을 설치하는데 하루정도, git clone 할 때 서버1에서 서버2로 Apache로 Reserver Proxy 를 타는 구간에서 403 에러로 거의 꼬박 하루 다해서 이틀 정도 삽질하며 고생했네요. 이 글 보시고 저처럼 삽질하지 마시고 시간 아끼시길 바랍니다.

전체 시스템 구성도

인터넷
  ↓
[공유기 192.168.0.1]
  ├─ 80 포트 → 192.168.0.2:80 (HTTP)
  ├─ 443 포트 → 192.168.0.2:443 (HTTPS)
  └─ 2222 포트 → 192.168.0.3:2222 (Git SSH)

[Apache 서버 192.168.0.2]
  - SSL 인증서 처리
  - 리버스 프록시
  - ModSecurity WAF

[GitLab 서버 192.168.0.3]
  - Docker GitLab CE
  - 8080번: HTTP
  - 2222번: SSH

접속 흐름도

1. 웹 GUI 접속 흐름 (관리자)

사용자 브라우저
    ↓
https://git.example.com (443포트)
    ↓
[공유기 192.168.0.1]
    ↓ (443 → 192.168.0.2:443 포워딩)
[Apache 서버 192.168.0.2]
    - SSL 인증서 처리
    - HTTPS → HTTP 변환
    - ModSecurity 검사
    ↓ (프록시: 192.168.0.3:8080)
[GitLab 서버 192.168.0.3:8080]
    - 웹 인터페이스 제공
    - 사용자 인증 처리

2. Git HTTPS Clone/Push 흐름

Git 클라이언트
    ↓
git clone https://git.example.com/repos/myproject.git
    ↓
[공유기 192.168.0.1]
    ↓ (443 → 192.168.0.2:443 포워딩)
[Apache 서버 192.168.0.2]
    - SSL 처리
    - Git HTTP 프로토콜 프록시
    - ModSecurity OFF (Git 경로)  ← 중요!
    ↓ (프록시: 192.168.0.3:8080)
[GitLab 서버 192.168.0.3:8080]
    - Git 저장소 접근
    - 인증 확인

3. Git SSH Clone/Push 흐름 (옵션) - Gitlab 은 SSH 사용시 공개키 인증만 가능해서 실제 사용은 안함

Git 클라이언트
    ↓
git clone ssh://git@git.example.com:2222/repos/myproject.git
    ↓
[공유기 192.168.0.1]
    ↓ (2222 → 192.168.0.3:2222 직접 포워딩)
[GitLab 서버 192.168.0.3:2222]
    - SSH 키 인증
    - Git 저장소 접근
    (Apache 거치지 않음)

서버 환경

  • CentOS Stream 9
  • Docker 24.0 LTS (2023년 5월 출시)
  • Docker Compose v2.20
  • Apache 2.4
  • 공유기: 192.168.0.1
  • Apache 웹서버: 192.168.0.2 (기존에 운영중)
  • GitLab 서버: 192.168.0.3 (Docker로 구성)

공유기에서 포트포워딩 설정:

  • 80 → 192.168.0.2:80 (HTTP)
  • 443 → 192.168.0.2:443 (HTTPS)
  • 2222 → 192.168.0.3:2222 (Git SSH - 나중에 쓸수도 있으니 설정만 해둠)

GitLab Docker 설치

GitLab 서버(192.168.0.3)에서 gitlab-ce.yaml 파일을 만듭니다:

# gitlab-ce.yaml
version: '3.8'
services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab-ce
    restart: always
    hostname: 'git.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        # 외부 URL (Apache가 SSL 처리)
        external_url 'https://git.example.com'
        
        # Nginx는 HTTP만 수신 (Apache가 프록시)
        nginx['listen_port'] = 8080
        nginx['listen_https'] = false
        
        # SSH 포트 설정
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
    
    ports:
      - '8080:8080'    # HTTP (Apache 프록시 대상)
      - '2222:22'      # SSH (직접 연결)
    
    volumes:
      - nv_gitlab-config:/etc/gitlab
      - nv_gitlab-logs:/var/log/gitlab
      - nv_gitlab-data:/var/opt/gitlab
volumes:
  nv_gitlab-config:
  nv_gitlab-logs:
  nv_gitlab-data:

실행합니다:

docker compose -f gitlab-ce.yaml up -d

주의: 최신 Docker에서는 docker-compose 대신 docker compose를 사용합니다.

Apache 리버스 프록시 설정

Apache 서버(192.168.0.2)에서 설정합니다. 제가 쓴 설정 파일을 참고해서 만들었습니다.

/etc/httpd/conf.d/git.example.com.conf 파일:

# HTTP to HTTPS Redirect (Port 80)
<VirtualHost *:80>
    ServerName git.example.com
    
    # Let's Encrypt 인증서 갱신을 위해 이 경로는 80번에서 처리
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
    
    <Location /.well-known/acme-challenge/>
        Satisfy Any
        Allow from all
    </Location>
    
    ErrorLog /var/log/httpd/git.example.com-error.log
    CustomLog /var/log/httpd/git.example.com-access.log combined
</VirtualHost>

# HTTPS Configuration (Port 443)
<VirtualHost *:443>
    ServerName git.example.com
    
    # SSL 설정
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/git.example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/git.example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/git.example.com/chain.pem
    
    # Git 관련 경로에 대해 ModSecurity 비활성화
    <LocationMatch "^/.*\.git/(info/refs|git-upload-pack|git-receive-pack)">
        SecRuleEngine Off
    </LocationMatch>
    
    # 프록시 설정
    ProxyPreserveHost On
    ProxyPass / http://192.168.0.3:8080/
    ProxyPassReverse / http://192.168.0.3:8080/
    RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>

SELinux 설정도 필요합니다:

setsebool -P httpd_can_network_connect 1
systemctl restart httpd

ModSecurity 403 에러 해결

여기까지 설정하면 웹 브라우저로는 잘 들어가지는데, git clone 하려고 하면 403 에러가 납니다.

$ git clone https://git.example.com/repos/myproject.git
Username for 'https://git.example.com': git_user
Password for 'https://git_user@git.example.com': 
error: RPC failed; HTTP 403 curl 22 The requested URL returned error: 403
fatal: expected flush after ref listing

Apache 에러 로그를 확인해보니:

ModSecurity: Warning. Match of "within %{tx.allowed_request_content_type}" against "TX:content_type" required.
[data "|application/x-git-upload-pack-request|"] 
[msg "Request content type is not allowed by policy"]

ModSecurity가 Git의 특수한 content-type을 차단하고 있었습니다. 그래서 위 설정에서 Git 경로에 대해서만 ModSecurity를 꺼버렸습니다:

<LocationMatch "^/.*\.git/(info/refs|git-upload-pack|git-receive-pack)">
    SecRuleEngine Off
</LocationMatch>

이렇게 하니까 git clone이 정상적으로 됩니다!

동작 확인

모든 설정이 끝났으면 테스트해봅니다:

  1. 웹 브라우저 접속: https://git.example.com
docker exec -it gitlab-ce grep 'Password:' /etc/gitlab/initial_root_password

  

   2. Git HTTPS clone:

git clone https://git.example.com/repos/myproject.git

 

SSH 클론 방법은 현재는 사용하지 않으므로 생략함.

 

유용한 명령어들

GitLab 백업:

docker exec -t gitlab-ce gitlab-backup create

로그 확인:

# GitLab 로그
docker logs -f gitlab-ce

# Apache 로그
tail -f /var/log/httpd/git.example.com-error.log
tail -f /var/log/httpd/error_log

Docker Compose 명령어:

# 상태 확인
docker compose -f gitlab-ce.yaml ps

# 재시작
docker compose -f gitlab-ce.yaml restart

# 중지
docker compose -f gitlab-ce.yaml down

마무리

도움이 되었다면 추천 댓글 부탁 드리고, 시간을 아끼셨다면 비밀 댓글로 커피 한잔 부탁 드립니다 ^^