Certbot SSL 인증서 발급부터 자동 갱신까지 한 번에
certbot ssl 인증서 발급이 생각보다 복잡하다고 느끼는 사람이 많다. 처음 서버를 세팅할 때 nginx 설정도 손봐야 하고, 포트도 열어야 하고, 인증서 경로도 신경 써야 하고… 하나씩 따라가다 보면 어느 순간 오류 메시지가 반겨주는 그 기분. 나도 처음엔 그랬다.
그런데 솔직히 말하자면, Certbot은 한 번 제대로 이해하고 나면 그다음부터는 정말 간단하다. Let’s Encrypt 덕분에 무료로 SSL 인증서를 발급받을 수 있고, 90일마다 갱신해야 한다는 것도 자동화만 잘 해두면 전혀 신경 쓸 일이 없다. 이 글에서는 Ubuntu 24.04 기준으로 Certbot 설치부터 nginx 연동, 자동 갱신 설정, 그리고 실제 운영 중에 자주 마주치는 갱신 오류 대처법까지 한 번에 정리한다.
직접 서버를 운영하면서 겪은 경험을 바탕으로 썼기 때문에, 공식 문서에는 잘 안 나와 있는 실전 팁들도 중간중간 넣어뒀다. Nginx와 Certbot 조합으로 처음 HTTPS를 세팅하는 분이라면 이 글 하나로 충분할 거라고 생각한다.
운영체제: Ubuntu 24.04 LTS
웹서버: Nginx (최신 안정 버전)
인증서: Let’s Encrypt (Certbot 공식 플러그인)
자동 갱신: systemd timer 방식 (cron 병행 설명)
전제 조건: 도메인이 서버 IP로 A레코드 연결되어 있어야 함
목차
서버 보안 강화에 관심 있다면 이전 글인 우분투 서버 보안 설정 가이드도 함께 읽어보길 추천한다. SSL 인증서 설정 이전에 방화벽과 SSH 보안부터 잡아두는 게 순서상 맞다. 이 글에서도 UFW 방화벽이 기본으로 설정되어 있다는 전제 하에 진행하니까 참고해두자.
Certbot이란? Let’s Encrypt와의 관계 이해하기
certbot ssl 인증서 발급을 처음 시도하는 분들이 자주 헷갈리는 게 있다. Certbot이랑 Let’s Encrypt가 같은 건지, 다른 건지. 결론부터 말하자면 다르다. Let’s Encrypt는 무료 SSL 인증서를 발급해주는 인증 기관(CA, Certificate Authority)이고, Certbot은 그 인증서를 자동으로 발급받고 갱신해주는 클라이언트 도구다.
비유하자면 Let’s Encrypt는 여권 발급 기관이고, Certbot은 여권 발급 창구에서 대신 서류를 처리해주는 에이전트 같은 역할이다. 직접 Let’s Encrypt API를 두드려서 인증서를 받을 수도 있긴 한데, 그걸 사람이 일일이 할 필요 없도록 자동화해주는 게 Certbot이다.
비영리 인증 기관. 무료 DV 인증서 발급. 90일 유효기간 정책 운영.
EFF(전자프론티어재단)가 개발한 ACME 클라이언트. 발급·갱신·nginx 설정 자동화.
도메인 소유권 자동 검증 표준 프로토콜. Certbot이 이 방식으로 Let’s Encrypt와 통신.
90일이라는 유효기간이 짧다고 느낄 수 있는데, 이건 Let’s Encrypt의 철학이다. 짧은 유효기간을 강제해서 자동 갱신 문화를 만들겠다는 의도다. 실제로 한 번 자동 갱신 설정만 해두면 이 90일이 전혀 부담이 안 된다. 오히려 갱신을 까먹어서 인증서가 만료되는 상황을 방지해주는 장치이기도 하다.
Let’s Encrypt가 발급하는 건 DV(Domain Validation) 인증서다. 도메인 소유권만 확인하는 방식으로, 개인 블로그·개발 서버·소규모 서비스에는 충분하다. 금융기관이나 결제 시스템처럼 조직 신원까지 검증해야 하는 경우에는 OV나 EV 인증서가 필요한데, 그건 유료 CA를 이용해야 한다. 대부분의 일반적인 웹서비스라면 Let’s Encrypt로 충분하다.
사전 준비 – 도메인 연결과 Nginx 기본 설정 확인
Certbot을 실행하기 전에 반드시 확인해야 할 것들이 있다. 이걸 빠뜨리고 certbot을 돌리면 바로 오류가 나는데, 대부분의 초보 오류가 여기서 나온다. 순서대로 체크해보자.
1단계: 도메인 A레코드 확인
Certbot의 HTTP-01 챌린지 방식은 외부에서 해당 도메인으로 접속해서 소유권을 확인한다. 그러니까 도메인이 서버 IP로 정확하게 연결되어 있어야 한다. 확인하는 방법은 간단하다.
DNS 전파에 시간이 걸리는 경우도 있다. 도메인 등록사에서 A레코드를 방금 바꿨다면 최대 48시간까지 기다려야 할 수 있는데, 대부분은 몇 분~1시간 이내에 반영된다. DNS 전파 확인 도구(whatsmydns.net)에서 글로벌 전파 상황을 빠르게 체크할 수 있다.
2단계: UFW 방화벽에서 80, 443 포트 개방
인증서 발급 과정에서 Let’s Encrypt 서버가 80번 포트로 접근한다. 443은 HTTPS 서비스용이다. 둘 다 열려 있어야 한다.
sudo ufw delete allow 'Nginx HTTP'
3단계: Nginx 동작 및 기본 설정 확인
Certbot –nginx 플러그인을 사용할 경우 Nginx가 실행 중이어야 하고, 해당 도메인에 대한 server block이 존재해야 한다. 아직 server block을 만들지 않았다면 지금 만들어두자.
server_name이 정확히 도메인으로 지정되어 있는지 먼저 확인하자. server_name _;처럼 와일드카드로만 잡혀 있으면 Certbot이 해당 도메인을 인식하지 못하고 오류를 낸다. 서버 세팅 전체 과정이 궁금하다면 Nginx + PHP8.3 + MariaDB 설치 가이드를 참고하면 된다.
Certbot 설치 및 SSL 인증서 발급 (certbot –nginx)
사전 준비가 끝났다면 이제 본격적으로 certbot ubuntu 설치를 시작한다. Ubuntu 24.04에서는 snap을 통한 설치가 공식 권장 방법이다. apt로 설치하는 구버전 certbot은 더 이상 업데이트가 잘 안 되기 때문에 snap 방식을 쓰는 게 맞다.
snapd 최신 상태 확인
snap으로 공식 버전 설치
certbot 명령어 전역 등록
certbot –nginx 실행
Certbot 설치
apt 저장소의 certbot 패키지는 업데이트 속도가 느리고, Ubuntu 버전에 따라 구버전이 설치될 수 있다. Certbot 공식 문서에서도 snap 설치를 권장하고 있으며, snap 버전은 자동으로 최신 상태를 유지한다. Certbot 공식 설치 가이드에서 OS와 웹서버를 선택하면 맞춤 설치 명령어를 확인할 수 있다.
SSL 인증서 발급 – certbot –nginx
설치가 끝났으면 이제 실제로 certbot ssl 인증서 발급을 해보자. –nginx 플러그인을 사용하면 Certbot이 알아서 Nginx 설정 파일을 읽고, 인증서 발급 후 HTTPS 설정까지 자동으로 넣어준다.
첫 실행 시 이메일 입력, 이용약관 동의, EFF 뉴스레터 수신 여부를 묻는다. 모두 입력하면 잠시 후 Let’s Encrypt 서버와 통신하면서 도메인 소유권 검증이 진행된다. 성공하면 아래 같은 메시지가 나온다.
인증서 발급 오류 시 먼저 확인할 것
No match for domain: Nginx server block에 해당 도메인이 server_name으로 지정되어 있지 않은 경우.
Rate limit exceeded: 단시간에 동일 도메인으로 발급 요청을 여러 번 했을 때. 1주일에 도메인당 5회 제한이 있다. 테스트할 때는 –staging 옵션을 쓰자.
sudo certbot delete --cert-name example.com으로 테스트 인증서를 지우고 실제 발급을 진행하면 된다.
Nginx SSL 설정 확인 및 443 포트 최적화
certbot –nginx로 발급을 마치면 Nginx 설정 파일이 자동으로 수정된다. 그런데 Certbot이 자동으로 넣어주는 기본 설정이 사실 최소한의 구성이라서, 운영 환경에서는 몇 가지를 더 손봐줘야 한다. nginx ssl 설정을 직접 확인하고 최적화하는 방법을 살펴보자.Certbot이 자동으로 수정한 Nginx 설정 확인
Certbot 실행 후 server block이 어떻게 바뀌었는지 먼저 확인해보자.SSL 설정 강화 – 권장 추가 항목
기본 설정으로도 HTTPS는 동작하지만, 보안 등급을 올리고 성능을 개선하려면 아래 항목들을 추가하는 게 좋다. 특히 HSTS와 OCSP Stapling은 실제 운영 서버라면 거의 필수다.| 설정 항목 | 역할 | 중요도 |
|---|---|---|
| http2 | HTTP/2 프로토콜 활성화 – 페이지 로딩 속도 향상 | 권장 |
| HSTS | 브라우저가 항상 HTTPS로만 접속하도록 강제 | 권장 |
| OCSP Stapling | 인증서 유효성 검증 속도 향상, 프라이버시 보호 | 권장 |
| X-Frame-Options | 클릭재킹 공격 방지 | 선택 |
| X-Content-Type-Options | MIME 스니핑 방지 | 선택 |
SSL 등급 확인
설정을 완료했으면 실제로 SSL 보안 등급이 어떻게 나오는지 확인해볼 수 있다. 위 설정을 그대로 적용했다면 A 이상이 나올 것이다.max-age를 짧게(예: 300초) 설정하고 테스트한 다음, 문제 없으면 15768000(6개월)로 늘리는 게 안전하다. HSTS를 한 번 적용하면 브라우저 캐시 기간 동안 HTTP로 되돌리기가 어렵기 때문이다. 특히 서브도메인까지 포함하는 includeSubDomains는 모든 서브도메인이 HTTPS로 돌아가고 있다는 확신이 있을 때 추가하자.Let’s Encrypt 자동 갱신 설정 (systemd timer / cron)
let’s encrypt 자동 갱신은 Certbot을 설치하면 사실 snap이 자동으로 처리해준다. snap 버전 Certbot은 설치 시 systemd timer를 자동으로 등록하는데, 이게 하루에 두 번씩 certbot renew를 실행해서 만료 30일 전부터 갱신을 시도한다. 그러니까 이미 설정이 되어 있다는 이야기다.
하지만 “자동으로 설정됐겠지” 하고 넘어가지 말고, 직접 확인하고 동작 테스트까지 해봐야 한다. 나중에 갱신이 실패했는데 그걸 모르고 있다가 인증서 만료 경고 메일을 받는 상황은 꽤 당황스럽다.
systemd timer 상태 확인
정상이라면 Active: active (waiting) 상태로 표시되고, 다음 실행 예정 시간이 나온다. 만약 inactive나 failed 상태라면 아래 명령어로 다시 활성화하자.
갱신 동작 테스트 (dry-run)
실제 갱신을 실행하지 않고 갱신 과정이 정상 동작하는지 시뮬레이션할 수 있다. –dry-run 옵션을 쓰면 된다.
cron으로 갱신 + Nginx 재시작 자동화
systemd timer가 기본이지만, cron을 추가로 설정해서 갱신 후 Nginx를 재시작하는 hook을 걸어두는 방식도 많이 쓴다. 특히 OCSP Stapling 캐시 갱신까지 확실하게 처리하고 싶다면 권장된다.
/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh 파일을 만들고 아래 내용을 넣어두면 된다.#!/bin/bash
systemctl reload nginx파일 권한도 실행 가능하게 설정:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
갱신 이력 및 만료일 확인
certbot –nginx 실행. 90일 유효기간 시작. /etc/letsencrypt/live/ 에 인증서 저장.
만료 30일 전부터 systemd timer가 매일 2회 certbot renew 실행. 갱신 성공 시 새 인증서 자동 적용.
갱신이 안 됐을 때 Let’s Encrypt에서 등록된 이메일로 만료 임박 경고 발송. 이 시점에 받으면 뭔가 문제가 있다는 신호.
갱신 실패 상태라면 이날부터 브라우저에 보안 경고. 자동 갱신이 정상이라면 Day 60~70 사이에 이미 새 인증서로 교체 완료.
sudo certbot certificates 명령어 실행 후 Expiry Date가 현재로부터 90일 가까이 남아 있다면 갱신이 정상적으로 이뤄진 것이다. 반대로 30일 이하가 남아 있는데 갱신 로그에 오류가 있다면 수동으로 sudo certbot renew를 실행해보자.
SSL 인증서 갱신 오류 원인과 실전 해결법
자동 갱신이 설정되어 있어도 오류가 나는 경우가 꽤 있다. ssl 인증서 갱신 오류의 원인은 대부분 몇 가지로 정해져 있어서, 패턴을 알면 금방 해결할 수 있다. 오류 메시지를 보고 당황하지 말고 하나씩 체크해보자.
오류 로그 먼저 확인하기
가장 흔한 오류 1: 80포트 차단 문제
Nginx가 443을 잘 서비스하고 있어도 갱신 시점에 80포트가 막혀 있으면 챌린지 검증이 실패한다. 특히 방화벽 규칙을 수정하다가 80포트를 실수로 닫는 경우가 있다.
가장 흔한 오류 2: acme-challenge 경로 차단
WordPress나 다른 CMS를 사용 중인 경우, .htaccess나 Nginx 설정에서 /.well-known/ 경로를 의도치 않게 차단하는 경우가 있다. Certbot은 이 경로에 검증 파일을 두고 Let’s Encrypt 서버가 접근하도록 해서 소유권을 증명한다.
location ^~ /.well-known/를 return 301 지시어보다 위에 두거나, 별도 server 블록에서 처리해야 한다.
수동 갱신 및 강제 갱신
- sudo ufw status – 80, 443 포트 모두 열려 있는지 확인
- sudo systemctl status nginx – Nginx 실행 중인지 확인
- dig example.com +short – DNS A레코드가 서버 IP와 일치하는지 확인
- curl -I http://example.com/.well-known/acme-challenge/test – 경로 접근 가능 여부 확인
- sudo certbot renew –dry-run – 갱신 시뮬레이션으로 오류 메시지 확인
- sudo tail -100 /var/log/letsencrypt/letsencrypt.log – 상세 오류 로그 확인
- 위 모두 정상인데도 실패 시 sudo certbot renew –force-renewal 시도
/etc/letsencrypt/cli.ini 파일에 post-hook = systemctl reload nginx를 추가하면 갱신 성공 시 Nginx가 자동으로 재로드된다. 갱신 실패 알림은 Let’s Encrypt 계정 이메일로 자동 발송되므로, 처음 certbot 설치 시 입력한 이메일 주소가 실제로 수신 가능한 메일인지 확인해두자.
FAQ – 자주 묻는 질문
sudo certbot certonly --dns-cloudflare -d "*.example.com" -d "example.com"
sudo certbot delete --cert-name example.com으로 한다. 도메인을 추가하거나 변경하려면 기존 인증서를 삭제한 후 새로 발급하거나, –expand 옵션으로 기존 인증서에 도메인을 추가할 수 있다. sudo certbot --nginx --expand -d example.com -d newdomain.com
sudo certbot certificates로 현재 인증서 만료일을 확인한다. 만료일이 갱신 전보다 90일에 가까워졌다면 정상적으로 갱신된 것이다. 또는 openssl s_client -connect example.com:443 < /dev/null 2>&1 | grep -i expire 명령으로 실제 연결된 인증서 만료일을 직접 확인할 수 있다.
전체 핵심 정리
- snap으로 certbot 설치 (apt 버전 비권장)
- 발급 전 DNS A레코드 + UFW 80포트 필수 확인
- certbot –nginx로 발급 + Nginx 설정 자동화
- 테스트는 반드시 –staging 옵션 사용
- 발급 성공 후 HTTPS 리다이렉트 자동 적용됨
- snap 설치 시 systemd timer 자동 등록됨
- 만료 30일 전부터 하루 2회 갱신 시도
- dry-run으로 갱신 동작 사전 검증 필수
- deploy hook으로 갱신 후 Nginx 자동 재로드
- 갱신 실패 시 Let’s Encrypt 이메일로 알림 발송
- 먼저 letsencrypt.log 확인으로 원인 파악
- 80포트 차단 여부 + Nginx 실행 상태 체크
- acme-challenge 경로 Nginx 설정 확인
- DNS 변경 후 충분한 전파 시간 대기
- rate limit 걸리면 7일 대기 후 재시도