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이 정상적으로 됩니다!
동작 확인
모든 설정이 끝났으면 테스트해봅니다:
- 웹 브라우저 접속: 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
마무리
도움이 되었다면 추천 댓글 부탁 드리고, 시간을 아끼셨다면 비밀 댓글로 커피 한잔 부탁 드립니다 ^^
'Linux > CentOS Stream 9' 카테고리의 다른 글
SVN https 서버 설정 (Centos Stream 9) (0) | 2024.05.10 |
---|---|
[오류 수정] 'pgdg-common': repomd.xml GPG signature verification error: Bad GPG signature (0) | 2024.01.24 |
CentOS stream 9 - 인터넷공유가 안되고 오류 (Packet filtered) (1) | 2023.03.10 |
이메일 postfix(smtp) + dovecot(imap/pop3) 에 SSL 보안 적용하기 (0) | 2023.03.04 |
Centos Stream 9 - 메일 서버에 OpenDKIM Install 설치 (0) | 2023.02.28 |