무료 SSL(HTTPS) 적용: Certbot 자동 갱신 + 자주 나는 오류 해결(Ubuntu 24.04, Nginx)
도메인을 Nginx에 연결했다면 이제 HTTPS(SSL/TLS)로 암호화를 적용할 차례입니다. 이 글은 Ubuntu 24.04 + Nginx 환경에서 Certbot으로 무료 인증서 발급과 자동 갱신을 설정하고, 현장에서 가장 자주 겪는 오류 원인과 해결법을 한 번에 정리합니다. 명령어는 그대로 복붙해도 동작하도록 구성했습니다.
1) 사전 점검(필수 체크)
- DNS:
example.com,www.example.com이 서버 IP(A/AAAA)로 정확히 향함 - 방화벽:
80/tcp,443/tcp허용(UFW/보안그룹 모두) - Nginx 서버 블록: 도메인
server_name이 설정되어 있고nginx -t가 통과
# DNS & 포트 확인(외부 PC에서)
dig +short A example.com
curl -I http://example.com # 200 또는 301/302 OK
2) Certbot 설치(Nginx 플러그인)
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
Nginx 플러그인을 사용하면 서버 블록 수정·HTTP→HTTPS 리다이렉트를 자동으로 처리할 수 있습니다.
3) 첫 발급 & 자동 설정(가장 쉬운 방법)
sudo certbot --nginx -d example.com -d www.example.com
- 이메일/약관 동의 → 리다이렉트(redirect) 옵션을 선택하면 HTTP→HTTPS가 자동으로 설정됩니다.
- 성공 후 인증서 경로:
/etc/letsencrypt/live/example.com/{fullchain.pem,privkey.pem}
검증
curl -I http://example.com # 301 → https://example.com
curl -I https://example.com # 200 OK, 인증서 유효
4) Webroot 방식(프록시/특수 구성용)
게이트웨이/리버스 프록시가 Nginx 외부에 있거나, Nginx 플러그인을 쓰기 어렵다면 webroot 모드가 안전합니다.
- Nginx 서버 블록에 ACME 경로 노출
# /etc/nginx/sites-available/example.com (HTTP 서버 블록)
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type "text/plain";
}
sudo mkdir -p /var/www/certbot
sudo nginx -t && sudo systemctl reload nginx
- webroot로 발급
sudo certbot certonly --webroot -w /var/www/certbot \
-d example.com -d www.example.com
이후 HTTPS 서버 블록(443)에 인증서 경로를 수동으로 지정합니다.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
5) 자동 갱신 확인(타이머·드라이런)
Certbot는 시스템 타이머로 자동 갱신합니다(보통 하루 2회 점검, 만료 30일 이내면 갱신 시도).
systemctl list-timers | grep certbot
sudo systemctl status certbot.timer
sudo certbot renew --dry-run # 갱신 리허설(중요)
갱신 후 자동으로 Nginx를 reload해야 합니다. 대부분의 Debian/Ubuntu 패키지는 훅이 설정되어 있지만, 확실히 하려면 다음 훅을 사용하세요.
# Nginx reload 훅(갱신 시마다 실행)
echo -e '#!/bin/sh\nnginx -t && systemctl reload nginx' | \
sudo tee /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh >/dev/null
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
6) HTTP→HTTPS(301)와 보안 헤더
Certbot 자동 구성으로도 되지만, 수동으로 작성한다면 다음을 참고하세요.
# HTTP → HTTPS 리다이렉트
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# HTTPS 서비스
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 보안 헤더(스니펫 활용 권장)
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
client_max_body_size 20m;
}
}
7) 자주 나는 오류와 해결
7-1) Connection refused 혹은 timeout (HTTP-01 챌린지 실패)
- 원인: 80 포트가 닫혀 있거나 다른 서비스가 점유
- 해결:
sudo ufw allow 80/tcp, 클라우드 보안그룹에서도 80 허용ss -lntup | grep :80로 점유 확인 → Nginx가 뜨는지nginx -t && systemctl reload nginx
7-2) CDN/프록시(예: “오렌지 구름”)가 가로막는 경우
- 원인: 인증 기관이 서버의 80로 직접 접근해야 하는데, 프록시 설정이나 방화벽이 챌린지를 가림
- 해결:
- 일시적으로 프록시 해제(회색 구름) 또는 “웹서버로 직접 라우팅” 설정
- 가능하면 webroot 모드로 발급
7-3) Unauthorized / Invalid response (404)
- 원인:
/.well-known/acme-challenge/경로가 실제로 외부에서 접근되지 않음 - 해결:
- webroot 경로가 서버 블록에 정확히 매핑됐는지 확인(오탈자·중복 location 주의)
curl http://example.com/.well-known/acme-challenge/test로 200 응답 확인
7-4) DNS/CAA 문제
- 원인: 잘못된 A/AAAA 또는 CAA 레코드가 ACME 발급을 제한
- 해결: A/AAAA가 실제 서버 IP인지 재확인, CAA를 쓰는 경우
letsencrypt.org허용
7-5) 권한/소유권 문제
- 원인:
/var/www/certbot또는/etc/letsencrypt권한 불일치 - 해결:
sudo chown -R www-data:www-data /var/www/certbot, 기본 권한 유지(/etc/letsencrypt는 root)
7-6) 갱신은 되는데 Nginx가 오래된 인증서를 계속 쓰는 경우
- 원인: 갱신 후
nginx reload미실행 - 해결: 위 renewal hook 스크립트 적용, 또는
/lib/systemd/system/certbot.service의 --deploy-hook 확인
8) 운영 점검 루틴(월 1회 권장)
sudo certbot renew --dry-run: 갱신 리허설sudo systemctl status certbot.timer: 타이머 정상 여부sudo ls -l /etc/letsencrypt/live/example.com/: 갱신일자 확인curl -I https://example.com: 200/리다이렉트/헤더 확인- 만료 15일 이내 알람: 모니터링/채팅봇 알림 연동
9) 수동 복구/재발급 팁
- 완전 초기화(비추):
sudo rm -rf /etc/letsencrypt후 재발급(이전 데이터 모두 삭제되니 주의) - 문제만 재현:
sudo certbot -vv --nginx -d example.com --dry-run로 디버그 로그 확보 - 대체 챌린지: DNS-01(와일드카드 필요 시). 단, DNS 제공자 API 연동이 요구됨
10) 최종 체크리스트
- DNS A/AAAA 정확, 80/443 방화벽 허용
- Certbot 발급 성공,
nginx -t통과 - HTTP→HTTPS 301 정상, 보안 헤더 적용
- 자동 갱신 타이머 정상,
renew --dry-runOK - 갱신 후
nginx reload자동화(renewal hook)
여기까지 설정하면 무료 SSL과 자동 갱신이 안정적으로 동작합니다. 이후에는 HSTS, TLS 강제 버전 정책, 보안 헤더 스니펫 등을 더해 운영 보안을 한 단계 끌어올리세요.
'서버 인프라 실무' 카테고리의 다른 글
| 리눅스 파일 권한 이해: chmod/chown/umask 한 번에 끝내기(실무 예제·함정·점검 루틴) (0) | 2025.10.21 |
|---|---|
| Docker 설치부터 Compose v2로 서비스 올리기(Nginx+PostgreSQL, Ubuntu 24.04) (0) | 2025.10.21 |
| Nginx 서버 블록(server_name)로 도메인 연결: WWW/비WWW 선택과 301 리다이렉트, HTTP→HTTPS까지 (0) | 2025.10.20 |
| UFW 방화벽 실전: 웹(80/443)만 열고 나머지 닫기 + 포트스캔 방어(IPv4/IPv6, 로그, 테스트까지) (0) | 2025.10.19 |
| 서버 첫 보안: SSH 포트 변경 + 공개키 로그인 + 루트 접속 차단(Ubuntu 24.04 기준) (0) | 2025.10.19 |