
Docker Compose로 설치한 GitLab에 Let’s Encrypt를 이용해 무료 SSL 인증서를 발급하고 자동으로 갱신하는 방법을 정리합니다.
GitLab은 ECDSA 키를 지원하지 않고 RSA 방식의 인증서만 지원하기 때문에 꼭 --key-type rsa 옵션을 설정해야 합니다.
certbot/certbot)/etc/letsencrypt/live/your-domain.com아래와 같은 디렉터리 구조를 사용합니다.
.
├── certbot
│ ├── conf
│ └── www
├── config
│ └── nginx
│ └── conf.d
│ └── certbot.conf
├── data
├── logs
└── docker-compose.yml
services:
gitlab:
image: 'gitlab/gitlab-ee:17.8.5-ee.0'
container_name: gitlab
ports:
- '80:80'
- '443:443'
- '22:22'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://your-domain.com'
nginx['ssl_certificate'] = "/etc/letsencrypt/live/your-domain.com/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/your-domain.com/privkey.pem"
nginx['http2_enabled'] = true
nginx['custom_nginx_config_location'] = "include /etc/gitlab/nginx/conf.d/*.conf;"
volumes:
- './config:/etc/gitlab'
- './logs:/var/log/gitlab'
- './data:/var/opt/gitlab'
- './certbot/conf:/etc/letsencrypt'
- './certbot/www:/var/www/certbot'
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- './certbot/conf:/etc/letsencrypt'
- './certbot/www:/var/www/certbot'
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 48h & wait $${!}; done;'"
restart: unless-stopped
external_url, 이메일 등은 실제 도메인과 본인 정보로 변경합니다.
GitLab 내장 Nginx에 Certbot 인증 시 사용할 경로를 설정합니다.
config/nginx/conf.d/certbot.conf 파일을 생성합니다.
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type "text/plain";
try_files $uri =404;
}
GitLab이 RSA만 지원하므로 아래와 같이 명령어에 꼭 --key-type rsa 옵션을 추가해야 합니다.
docker run --rm \
-v "$(pwd)/certbot/conf:/etc/letsencrypt" \
-v "$(pwd)/certbot/www:/var/www/certbot" \
certbot/certbot certonly \
--webroot \
--key-type rsa \
-w /var/www/certbot \
--email your@email.com \
--agree-tos \
--no-eff-email \
-d your-domain.com
/etc/letsencrypt/live/your-domain.com/fullchain.pem/etc/letsencrypt/live/your-domain.com/privkey.pem인증서의 남은 기간이 20일 이하일 때만 자동 갱신하도록 스크립트를 작성합니다.
renew-cert.sh 파일 생성:
#!/bin/bash
expiry_date=$(openssl x509 -enddate -noout -in ./certbot/conf/live/your-domain.com/fullchain.pem | cut -d= -f2)
expiry_seconds=$(date --date="$expiry_date" +%s)
current_seconds=$(date +%s)
diff_days=$(( (expiry_seconds - current_seconds) / 86400 ))
if [ "$diff_days" -le 20 ]; then
echo "인증서 유효기간이 $diff_days일 남아 갱신을 진행합니다."
docker run --rm \
-v "$(pwd)/certbot/conf:/etc/letsencrypt" \
-v "$(pwd)/certbot/www:/var/www/certbot" \
certbot/certbot renew --webroot -w /var/www/certbot
docker exec gitlab gitlab-ctl hup nginx
else
echo "인증서가 아직 유효합니다. ($diff_days일 남음)"
fi
스크립트 권한 설정:
chmod +x renew-cert.sh
Cron 등으로 한 달에 한 번 정도 주기적으로 실행합니다.
기본적으로 만료일까지 30일 이상 남으면 갱신하지 않습니다.
강제로 갱신이 필요하면 --force-renewal 옵션을 사용합니다.
certbot renew --force-renewal
Certbot이 standalone 방식으로 실행되면 80포트를 직접 사용하므로 충돌합니다.
이때는 GitLab을 잠시 중단하거나, webroot 방식으로 인증을 진행하면 충돌을 피할 수 있습니다.
GitLab이 RSA 키만 지원하기 때문에 발생하는 문제입니다.
반드시 --key-type rsa 옵션을 설정해야 합니다.
설정 변경 후 Nginx가 설정을 다시 로드해야 합니다.
docker exec gitlab gitlab-ctl hup nginx
브라우저 캐시도 영향을 줄 수 있으므로 브라우저 캐시를 비우거나 강력 새로고침을 시도해 보세요.
docker exec -it gitlab openssl x509 -in /etc/letsencrypt/live/your-domain.com/fullchain.pem -noout -dates
echo | openssl s_client -connect your-domain.com:443 -servername your-domain.com | openssl x509 -noout -dates
--key-type rsa 필수)gitlab-ctl hup nginx를 실행합니다.