서버 공인 주소를 가리키는 관리 가능한 도메인 A 레코드와 사용 중이면 올바른 AAAA 레코드
WEB & TLS
NGINX와 Certbot HTTPS 설정
Ubuntu 24.04에 NGINX를 설치하고 도메인 서버 블록을 검증한 뒤 Certbot으로 TLS 인증서를 발급해 자동 갱신과 외부 HTTPS 접속까지 확인합니다.BEFORE YOU START
시작 전에 준비하세요
인터넷에서 서버의 TCP 80·443에 도달하도록 설정할 방화벽·보안그룹 권한
sudo 권한과 NGINX 설정 변경·reload가 가능한 점검 시간
기존 웹 서버·인증서가 있다면 설정 파일, 인증서 이름, 서비스 영향 백업
권장 대상 Ubuntu 웹 서버에 도메인을 연결하고 NGINX와 Let’s Encrypt 인증서를 안전하게 처음 구성하려는 개발자·운영자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
OS·도메인·네트워크 전제 확인
이 가이드는 Ubuntu 패키지의 NGINX와 Certbot snap을 기준으로 합니다. 도메인이 실제 서버를 가리키고 외부 검증이 가능한 환경인지 먼저 확인합니다.
cat /etc/os-release
dpkg --print-architectureip -brief address
ip routegetent ahosts <DOMAIN>A와 AAAA가 있다면 모두 이 서버에서 요청을 받을 수 있어야 합니다.timedatectl status- Ubuntu 24.04 LTS임을 확인했습니다.
- 도메인의 모든 A·AAAA 주소가 의도한 서버 또는 프록시를 가리킵니다.
- 서버 시간이 동기화돼 있습니다.
잘못된 AAAA 레코드도 인증서 검증 실패 원인이 됩니다. DNS 전파와 외부 경로가 확실하지 않으면 인증서 발급을 시도하지 않습니다.
기존 80·443 사용 프로세스, NGINX 설정, Certbot 설치와 인증서를 조사합니다.
기존 웹 서버·포트·인증서 사전 점검
포트 충돌과 기존 설정 덮어쓰기를 막기 위해 리슨 프로세스, 설치 패키지, NGINX 전체 설정, 기존 인증서를 확인합니다.
sudo ss -lntp | grep -E ':(80|443)\b'출력이 없으면 아직 해당 포트를 사용하지 않는 상태입니다.dpkg -l | grep -E 'nginx|apache2|certbot|python3-certbot-nginx'
snap list certbot
command -v certbot
readlink -f "$(command -v certbot)"/usr/bin/certbot 또는 apt Certbot 패키지가 발견되면 여기서 중단합니다. 기존 인증서·갱신 설정을 조사하고 승인된 snap 이관 계획 없이 두 방식을 혼용하지 않습니다. 미설치 환경의 출력 없음은 정상입니다.sudo nginx -t
sudo nginx -TNGINX가 이미 설치된 경우에만 실행하며 출력에 인증서 경로가 포함될 수 있으므로 안전하게 보관합니다.sudo /snap/bin/certbot certificatesreadlink 결과가 /snap/bin/certbot이고 snap 설치가 확인된 경우에만 실행합니다. apt 설치본이면 이 레시피를 중단하고 기존 방식으로 별도 조사합니다.sudo ufw status verbose- 80·443 포트의 기존 소유 프로세스와 중단 영향을 확인했습니다.
- apt Certbot과 snap Certbot을 혼용하지 않도록 현재 설치 방식을 확인했습니다.
- 기존 NGINX server_name과 인증서 이름이 새 도메인과 충돌하지 않습니다.
Apache·기존 NGINX·프록시가 포트를 사용 중이면 강제 종료하지 않습니다. 현재 트래픽과 전환 계획을 먼저 확정합니다.
Ubuntu 저장소의 NGINX와 공식 권장 Certbot snap을 설치합니다.
NGINX와 Certbot 설치
NGINX는 Ubuntu APT 패키지로, Certbot은 Certbot 공식 안내가 권장하는 classic snap으로 설치합니다. 기존 apt Certbot이 있으면 먼저 사용 현황과 인증서를 확인합니다.
sudo apt update
apt-cache policy nginx snapdsudo apt install nginx snapdsystemctl is-active snapd.service
systemctl is-enabled snapd.socketsudo apt remove certbot python3-certbot-nginxapt 설치본이 발견됐고 기존 인증서·갱신 설정 백업과 snap 이관이 명시적으로 승인된 경우에만 snap 설치 전에 실행합니다. 미설치라면 건너뜁니다.sudo snap install --classic certbot/snap/bin/certbot --version
readlink -f /snap/bin/certbot이후 모든 Certbot 명령은 PATH나 심볼릭 링크에 의존하지 않고 /snap/bin/certbot을 명시합니다.- apt의 certbot 패키지와 snap Certbot을 혼용하지 않습니다.
- nginx와 certbot 버전 명령이 정상 출력됩니다.
- 기존 인증서 디렉터리를 삭제하거나 덮어쓰지 않았습니다.
snap 설치가 실패하면 프록시·DNS·snapd 상태를 먼저 확인합니다. 다른 비공식 설치 스크립트로 우회하지 않습니다.
도메인별 server block과 테스트 콘텐츠를 별도 파일로 구성합니다.
도메인 server block 구성
기본 설정을 직접 덮지 않고 sites-available에 도메인별 파일을 만든 뒤 심볼릭 링크로 활성화합니다. 기존 파일이 있으면 고유한 이름으로 먼저 백업합니다.
sudo install -d -m 0755 /var/www/<SITE_NAME>
sudoedit /var/www/<SITE_NAME>/index.html운영 애플리케이션을 프록시할 계획이어도 최초 HTTP 검증용 정적 페이지를 준비합니다.sudo cp --archive --no-clobber /etc/nginx/sites-available/<DOMAIN> /etc/nginx/sites-available/<DOMAIN>.<BACKUP_SUFFIX>기존 파일이 있을 때만 실행하고 고유한 백업 이름을 사용합니다.sudoedit /etc/nginx/sites-available/<DOMAIN>sudo ln -s /etc/nginx/sites-available/<DOMAIN> /etc/nginx/sites-enabled/<DOMAIN>같은 링크가 없는 신규 사이트에서만 실행합니다. 기존 링크를 강제로 덮지 않습니다.sudo test -L /etc/nginx/sites-enabled/default && sudo test -f /etc/nginx/sites-available/default && sudo cp --archive --no-clobber /etc/nginx/sites-available/default /etc/nginx/sites-available/default.<BACKUP_SUFFIX> && sudo unlink /etc/nginx/sites-enabled/default기존 서비스가 전혀 없는 신규 NGINX이며 배포판 기본 welcome 사이트가 그대로인 경우에만 실행합니다. 기존 트래픽·사용자 설정·기본 catch-all이 있으면 건너뜁니다.sudo nginx -tserver {
listen 80;
listen [::]:80;
server_name <DOMAIN>;
root /var/www/<SITE_NAME>;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}<DOMAIN>과 <SITE_NAME>을 실제 값으로 모두 바꿉니다. www 도메인도 사용할 때만 DNS를 준비한 뒤 server_name과 Certbot -d 옵션에 함께 추가합니다.<!doctype html>
<html lang="ko">
<head><meta charset="utf-8"><title>ready</title></head>
<body><h1>NGINX ready</h1></body>
</html>인증서 발급과 외부 도달성 검증 뒤 실제 정적 파일 또는 reverse proxy 설정으로 교체합니다.- 기존 사이트 파일이 있다면 별도 이름으로 백업했습니다.
- server_name이 실제 인증서를 받을 도메인과 정확히 일치합니다.
- 기본 사이트는 완전 신규 호스트에서만 백업 후 비활성화했습니다.
- nginx -t가 성공했습니다.
duplicate server name 경고가 있으면 같은 도메인을 선언한 다른 파일을 찾아 정리합니다. 문법 오류 상태에서는 reload하지 않습니다.
HTTP 접속을 먼저 확인하고 방화벽을 열어 Certbot이 NGINX 설정을 안전하게 수정하게 합니다.
NGINX 시작과 인증서 발급
NGINX를 시작해 로컬 HTTP 응답을 확인한 뒤 외부 80·443 경로를 열고 Certbot NGINX 플러그인으로 인증서를 발급합니다.
sudo systemctl enable nginx.service
sudo systemctl start nginx.servicesudo nginx -t
sudo systemctl reload nginx.servicecurl -I -H 'Host: <DOMAIN>' http://127.0.0.1/sudo ufw --dry-run allow 'Nginx Full'sudo ufw allow 'Nginx Full'UFW가 활성 상태이고 클라우드 보안그룹·조직 정책에서 공개 웹 포트를 승인한 경우에만 실행합니다.sudo /snap/bin/certbot --nginx -d <DOMAIN>실제 도메인으로 바꾸고 이메일·이용약관을 직접 확인합니다. www도 사용할 때만 DNS 준비 후 -d www.<DOMAIN>을 추가합니다.- 로컬 Host 헤더 요청이 의도한 server block에서 응답합니다.
- 외부 80·443 포트가 이 서버로 전달됩니다.
- Certbot이 인증서 발급과 NGINX reload를 오류 없이 마쳤습니다.
Certbot의 challenge 실패를 반복하면 발급 제한에 걸릴 수 있습니다. DNS·AAAA·NAT·방화벽·server_name을 바로잡은 뒤 재시도합니다.
실제 외부 HTTPS 응답, 인증서 이름, 자동 갱신 dry-run과 부팅 자동 활성화 상태를 확인합니다.
HTTPS와 자동 갱신 검증
브라우저 표시만 보지 않고 HTTPS 응답, Certbot이 관리하는 인증서, 갱신 dry-run, 서비스 부팅 활성화를 각각 확인합니다.
nslookup <DOMAIN>
curl -I https://<DOMAIN>/서버 내부가 아니라 별도 PC 또는 모바일망에서 실행해 공인 DNS, 외부 443 경로, 인증서 체인을 함께 검증합니다.sudo /snap/bin/certbot certificatessudo /snap/bin/certbot renew --dry-runsystemctl list-timers --all | grep -E 'snap.certbot|certbot'systemctl is-enabled nginx.service
systemctl is-active nginx.service
sudo nginx -t- https://<DOMAIN>이 인증서 경고 없이 응답합니다.
- certbot certificates의 Domains와 Expiry Date가 의도와 맞습니다.
- certbot renew --dry-run이 성공했습니다.
- NGINX가 enabled·active이고 설정 검사를 통과합니다.
HTTPS는 되지만 dry-run이 실패하면 현재 인증서가 정상이어도 다음 갱신 때 장애가 납니다. 오류를 남기지 말고 즉시 원인을 해결합니다.
노출 포트, TLS 범위, 파일 권한, 로그와 인증서 만료 모니터링을 점검합니다.
웹·TLS 보안 최종 점검
필요한 도메인과 포트만 열고 인증서·개인키 권한, NGINX 실행 계정, 갱신 실패 감시를 확인합니다. HSTS는 복구 가능성을 검토한 뒤 별도로 적용합니다.
sudo ss -lntp | grep -E ':(80|443)\b'sudo ufw status numberedsudo namei -l /etc/letsencrypt/live/<DOMAIN>/fullchain.pem
sudo namei -l /etc/letsencrypt/live/<DOMAIN>/privkey.pemps -eo user,group,comm | grep nginx
sudo nginx -tsudo journalctl -u nginx.service -p warning -n 50 --no-pager
sudo journalctl -u snap.certbot.renew.service -n 50 --no-pager- 80·443 외 불필요한 관리 포트를 인터넷에 노출하지 않습니다.
- Let’s Encrypt 개인키를 애플리케이션 사용자나 저장소에 복사하지 않습니다.
- 지원하는 모든 도메인이 인증서 SAN에 포함되고 불필요한 이름은 제외했습니다.
- 인증서 갱신 실패를 만료 전에 발견할 모니터링 또는 정기 점검이 있습니다.
- HSTS는 모든 하위 도메인의 HTTPS 준비와 롤백 영향을 검토한 뒤 적용합니다.
- reverse proxy 사용 시 실제 업스트림만 localhost·내부망에 노출합니다.
개인키는 root 권한 경로에 유지하고 NGINX가 직접 필요한 방식으로만 사용합니다. 권한을 넓혀 오류를 우회하지 않습니다.
문제가 생기면 인증서를 지우기 전에 server block 백업을 복원하고 NGINX 설정부터 정상화합니다.
사이트 설정·인증서 변경 롤백
기존 server block이 있던 환경은 확인된 백업을 복원하고, 신규 환경은 이번 레시피가 만든 링크와 파일만 비활성화합니다. 사용 중인 인증서나 /etc/letsencrypt 전체는 삭제하지 않습니다.
sudo ls -l /etc/nginx/sites-available/<DOMAIN> /etc/nginx/sites-enabled/<DOMAIN>
sudo find /etc/nginx/sites-available -maxdepth 1 -type f -name '<DOMAIN>.*' -print
sudo nginx -T
sudo /snap/bin/certbot certificates사전 점검에서 도메인 파일과 링크가 있었는지, 이번 작업에서 만든 고유 백업·인증서 이름을 변경 기록과 대조합니다.sudo test -f /etc/nginx/sites-available/<DOMAIN>.<BACKUP_SUFFIX> && sudo cp --archive /etc/nginx/sites-available/<DOMAIN>.<BACKUP_SUFFIX> /etc/nginx/sites-available/<DOMAIN>사전 점검에서 기존 파일이 있었고 실제 백업의 내용·시각을 확인한 경우에만 실행합니다. test가 실패하면 복원하지 않습니다.sudo test -L /etc/nginx/sites-enabled/<DOMAIN> && sudo unlink /etc/nginx/sites-enabled/<DOMAIN>사전 점검에서 링크가 없었고 이번 레시피가 만든 심볼릭 링크임이 확인된 경우에만 A 대신 실행합니다.sudo test -f /etc/nginx/sites-available/<DOMAIN> && sudo test ! -e /etc/nginx/sites-available/<DOMAIN>.disabled && sudo mv /etc/nginx/sites-available/<DOMAIN> /etc/nginx/sites-available/<DOMAIN>.disabled사전 점검에서 파일이 없었고 이번 레시피가 만든 파일임이 작업 기록으로 확인된 경우에만 실행합니다. 삭제하지 않고 disabled 파일로 보존합니다.sudo test -f /etc/nginx/sites-available/default.<BACKUP_SUFFIX> && sudo cp --archive /etc/nginx/sites-available/default.<BACKUP_SUFFIX> /etc/nginx/sites-available/default && sudo test ! -e /etc/nginx/sites-enabled/default && sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default작업 전 기본 사이트가 활성 상태였고 이번 레시피가 신규 호스트에서 비활성화한 기록이 있을 때만 실행합니다. 기존 운영 사이트에는 사용하지 않습니다.sudo nginx -t
sudo systemctl reload nginx.servicesudo grep -R --fixed-strings '/etc/letsencrypt/live/<CERTIFICATE_NAME>/' /etc/nginx출력이 있으면 인증서를 삭제하지 않습니다. 출력이 없어도 NGINX 외 서비스·로드밸런서·백업의 사용 여부를 추가 확인합니다.sudo /snap/bin/certbot delete --cert-name <CERTIFICATE_NAME>이번 레시피에서 새로 발급한 인증서이고, 모든 서비스의 사용처가 없으며, 도메인 폐기 또는 재발급이 승인된 경우에만 실행합니다. 기존 인증서나 사용 중 인증서에는 실행하지 않습니다.curl -I -H 'Host: <DOMAIN>' http://127.0.0.1/
systemctl status nginx.service --no-pager- 대상 도메인과 심볼릭 링크를 정확히 확인했습니다.
- 기존 파일 복원(A)과 신규 파일 비활성화(B) 중 사전 점검 기록에 맞는 한 경로만 실행했습니다.
- 복원 또는 비활성화 후 nginx -t가 성공한 뒤에만 reload했습니다.
- 인증서는 이번에 발급했고 모든 사용처가 없다는 사실을 확인하기 전 삭제하지 않았습니다.
Certbot이 수정한 설정이 문제라면 백업 server block을 먼저 복원합니다. NGINX 패키지와 /etc/letsencrypt 전체를 삭제하는 명령은 제공하지 않습니다.
롤백 뒤 HTTP·HTTPS 경로와 인증서 사용자 목록을 다시 확인하고 변경 기록을 남깁니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- 인증서 발급 전 DNS A·AAAA와 외부 80·443 도달성을 모두 확인합니다.
- NGINX 설정을 변경할 때마다 nginx -t 성공 후 reload합니다.
- Let’s Encrypt 개인키 권한을 넓히거나 저장소·백업 로그에 복사하지 않습니다.
- Certbot renew --dry-run과 갱신 타이머를 설치 직후 검증합니다.
- UFW와 클라우드 방화벽에는 80·443 및 필요한 관리 포트만 허용합니다.
- HSTS includeSubDomains·preload는 모든 하위 도메인과 장기 롤백 영향을 검토한 뒤 적용합니다.
COMMON ERRORS
자주 막히는 지점
Certbot 도메인 검증 실패
- 증상
- unauthorized, timeout 또는 connection refused로 인증서 발급이 실패합니다.
- 가능한 원인
- DNS A·AAAA 불일치, NAT·보안그룹·UFW의 80 차단, 잘못된 server_name일 수 있습니다.
- 확인 순서
- getent ahosts, 외부 HTTP 접속, 80 포트 리슨, 방화벽, server_name 순서로 고친 뒤 반복 발급을 줄입니다.
nginx -t가 실패함
- 증상
- unknown directive, duplicate, file not found 또는 certificate 오류가 표시됩니다.
- 가능한 원인
- 편집 문법, 중복 server block, 존재하지 않는 파일·인증서 경로가 원인일 수 있습니다.
- 확인 순서
- 오류에 표시된 파일과 줄을 수정하거나 백업으로 복원하고, 검사 성공 전 reload·restart하지 않습니다.
HTTPS는 되지만 자동 갱신 dry-run 실패
- 증상
- 현재 인증서는 정상인데 certbot renew --dry-run이 실패합니다.
- 가능한 원인
- 갱신 authenticator 설정, DNS·포트 경로, NGINX 플러그인 또는 snap 서비스 문제일 수 있습니다.
- 확인 순서
- certbot 인증서 정보와 갱신 journal을 확인하고 만료 전에 동일 challenge 경로를 복구합니다.
reverse proxy에서 502·504가 발생함
- 증상
- TLS 연결은 되지만 NGINX가 Bad Gateway 또는 Gateway Timeout을 반환합니다.
- 가능한 원인
- 인증서 문제가 아니라 업스트림 주소·포트·서비스 상태·timeout 설정 문제일 수 있습니다.
- 확인 순서
- NGINX 오류 로그와 업스트림 로컬 연결을 확인하고 502·504 장애 대응 가이드로 분기합니다.
PRIMARY REFERENCES
공식 문서
- Ubuntu Server · How to configure nginx
- Ubuntu Server · Obtain TLS certificates
- Certbot · Nginx on Linux installation instructions
- NGINX · Command-line parameters
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.