Haru Utils

WEB & TLS

NGINX와 Certbot HTTPS 설정

Ubuntu 24.04에 NGINX를 설치하고 도메인 서버 블록을 검증한 뒤 Certbot으로 TLS 인증서를 발급해 자동 갱신과 외부 HTTPS 접속까지 확인합니다.
NGINX 설치Certbot 설치Let's Encrypt HTTPSNginx server blockTLS 인증서 자동 갱신
지원 환경Ubuntu Server 24.04 LTS · amd64
예상 시간35
난이도중급
검토일2026-08-28

BEFORE YOU START

시작 전에 준비하세요

01

서버 공인 주소를 가리키는 관리 가능한 도메인 A 레코드와 사용 중이면 올바른 AAAA 레코드

02

인터넷에서 서버의 TCP 80·443에 도달하도록 설정할 방화벽·보안그룹 권한

03

sudo 권한과 NGINX 설정 변경·reload가 가능한 점검 시간

04

기존 웹 서버·인증서가 있다면 설정 파일, 인증서 이름, 서비스 영향 백업

권장 대상 Ubuntu 웹 서버에 도메인을 연결하고 NGINX와 Let’s Encrypt 인증서를 안전하게 처음 구성하려는 개발자·운영자

FOLLOW THE RECIPE

8단계 구성·점검 레시피

1
확인시스템을 변경하지 않는 점검 단계

OS·도메인·네트워크 전제 확인

이 가이드는 Ubuntu 패키지의 NGINX와 Certbot snap을 기준으로 합니다. 도메인이 실제 서버를 가리키고 외부 검증이 가능한 환경인지 먼저 확인합니다.

Ubuntu 릴리스와 아키텍처
cat /etc/os-release
dpkg --print-architecture
서버 주소
ip -brief address
ip route
도메인 해석 결과
getent ahosts <DOMAIN>
A와 AAAA가 있다면 모두 이 서버에서 요청을 받을 수 있어야 합니다.
시간 동기화
timedatectl status
  • Ubuntu 24.04 LTS임을 확인했습니다.
  • 도메인의 모든 A·AAAA 주소가 의도한 서버 또는 프록시를 가리킵니다.
  • 서버 시간이 동기화돼 있습니다.
결과 읽기

잘못된 AAAA 레코드도 인증서 검증 실패 원인이 됩니다. DNS 전파와 외부 경로가 확실하지 않으면 인증서 발급을 시도하지 않습니다.

다음 판단

기존 80·443 사용 프로세스, NGINX 설정, Certbot 설치와 인증서를 조사합니다.

2
확인시스템을 변경하지 않는 점검 단계

기존 웹 서버·포트·인증서 사전 점검

포트 충돌과 기존 설정 덮어쓰기를 막기 위해 리슨 프로세스, 설치 패키지, NGINX 전체 설정, 기존 인증서를 확인합니다.

80·443 리슨 프로세스
sudo ss -lntp | grep -E ':(80|443)\b'
출력이 없으면 아직 해당 포트를 사용하지 않는 상태입니다.
웹 서버·Certbot 설치 방식과 실제 경로
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 이관 계획 없이 두 방식을 혼용하지 않습니다. 미설치 환경의 출력 없음은 정상입니다.
기존 NGINX 설정 검사
sudo nginx -t
sudo nginx -T
NGINX가 이미 설치된 경우에만 실행하며 출력에 인증서 경로가 포함될 수 있으므로 안전하게 보관합니다.
기존 snap Certbot 인증서
sudo /snap/bin/certbot certificates
readlink 결과가 /snap/bin/certbot이고 snap 설치가 확인된 경우에만 실행합니다. apt 설치본이면 이 레시피를 중단하고 기존 방식으로 별도 조사합니다.
방화벽 상태
sudo ufw status verbose
  • 80·443 포트의 기존 소유 프로세스와 중단 영향을 확인했습니다.
  • apt Certbot과 snap Certbot을 혼용하지 않도록 현재 설치 방식을 확인했습니다.
  • 기존 NGINX server_name과 인증서 이름이 새 도메인과 충돌하지 않습니다.
결과 읽기

Apache·기존 NGINX·프록시가 포트를 사용 중이면 강제 종료하지 않습니다. 현재 트래픽과 전환 계획을 먼저 확정합니다.

다음 판단

Ubuntu 저장소의 NGINX와 공식 권장 Certbot snap을 설치합니다.

3
변경패키지·설정·서비스 상태가 달라지는 단계

NGINX와 Certbot 설치

NGINX는 Ubuntu APT 패키지로, Certbot은 Certbot 공식 안내가 권장하는 classic snap으로 설치합니다. 기존 apt Certbot이 있으면 먼저 사용 현황과 인증서를 확인합니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
패키지 후보 확인
sudo apt update
apt-cache policy nginx snapd
NGINX와 snapd 설치
sudo apt install nginx snapd
snapd 활성 상태
systemctl is-active snapd.service
systemctl is-enabled snapd.socket
승인된 apt Certbot 이관
sudo apt remove certbot python3-certbot-nginx
apt 설치본이 발견됐고 기존 인증서·갱신 설정 백업과 snap 이관이 명시적으로 승인된 경우에만 snap 설치 전에 실행합니다. 미설치라면 건너뜁니다.
Certbot snap 설치
sudo snap install --classic certbot
snap 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과 테스트 콘텐츠를 별도 파일로 구성합니다.

4
주의권한·연결·중단 영향을 확인할 단계

도메인 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>
기존 파일이 있을 때만 실행하고 고유한 백업 이름을 사용합니다.
server block 편집
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 -t
설정 예시 · /etc/nginx/sites-available/<DOMAIN>
인증서 발급 전 최소 HTTP server block
server {
    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 옵션에 함께 추가합니다.
설정 예시 · /var/www/<SITE_NAME>/index.html
HTTP 도달성 확인용 최소 페이지
<!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 설정을 안전하게 수정하게 합니다.

5
주의권한·연결·중단 영향을 확인할 단계

NGINX 시작과 인증서 발급

NGINX를 시작해 로컬 HTTP 응답을 확인한 뒤 외부 80·443 경로를 열고 Certbot NGINX 플러그인으로 인증서를 발급합니다.

NGINX 시작과 부팅 활성화
sudo systemctl enable nginx.service
sudo systemctl start nginx.service
설정 반영
sudo nginx -t
sudo systemctl reload nginx.service
로컬 Host 기반 HTTP 확인
curl -I -H 'Host: <DOMAIN>' http://127.0.0.1/
NGINX 방화벽 규칙 미리보기
sudo ufw --dry-run allow 'Nginx Full'
80·443 방화벽 허용
sudo ufw allow 'Nginx Full'
UFW가 활성 상태이고 클라우드 보안그룹·조직 정책에서 공개 웹 포트를 승인한 경우에만 실행합니다.
도메인 인증서 발급·NGINX 적용
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과 부팅 자동 활성화 상태를 확인합니다.

6
확인시스템을 변경하지 않는 점검 단계

HTTPS와 자동 갱신 검증

브라우저 표시만 보지 않고 HTTPS 응답, Certbot이 관리하는 인증서, 갱신 dry-run, 서비스 부팅 활성화를 각각 확인합니다.

외부 네트워크에서 DNS·HTTPS 확인
nslookup <DOMAIN>
curl -I https://<DOMAIN>/
서버 내부가 아니라 별도 PC 또는 모바일망에서 실행해 공인 DNS, 외부 443 경로, 인증서 체인을 함께 검증합니다.
관리 인증서 목록
sudo /snap/bin/certbot certificates
자동 갱신 모의 실행
sudo /snap/bin/certbot renew --dry-run
갱신 타이머 확인
systemctl list-timers --all | grep -E 'snap.certbot|certbot'
NGINX 부팅 상태와 설정
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 범위, 파일 권한, 로그와 인증서 만료 모니터링을 점검합니다.

7
주의권한·연결·중단 영향을 확인할 단계

웹·TLS 보안 최종 점검

필요한 도메인과 포트만 열고 인증서·개인키 권한, NGINX 실행 계정, 갱신 실패 감시를 확인합니다. HSTS는 복구 가능성을 검토한 뒤 별도로 적용합니다.

외부 리슨 주소
sudo ss -lntp | grep -E ':(80|443)\b'
방화벽 규칙
sudo ufw status numbered
인증서 디렉터리 권한
sudo namei -l /etc/letsencrypt/live/<DOMAIN>/fullchain.pem
sudo namei -l /etc/letsencrypt/live/<DOMAIN>/privkey.pem
NGINX 실행 사용자와 설정 검사
ps -eo user,group,comm | grep nginx
sudo nginx -t
최근 NGINX·Certbot 오류
sudo 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 설정부터 정상화합니다.

8
변경패키지·설정·서비스 상태가 달라지는 단계

사이트 설정·인증서 변경 롤백

기존 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
사전 점검에서 도메인 파일과 링크가 있었는지, 이번 작업에서 만든 고유 백업·인증서 이름을 변경 기록과 대조합니다.
A. 기존 server block의 확인된 백업 복원
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가 실패하면 복원하지 않습니다.
B. 이번에 새로 만든 사이트 링크 비활성화
sudo test -L /etc/nginx/sites-enabled/<DOMAIN> && sudo unlink /etc/nginx/sites-enabled/<DOMAIN>
사전 점검에서 링크가 없었고 이번 레시피가 만든 심볼릭 링크임이 확인된 경우에만 A 대신 실행합니다.
B. 이번에 새로 만든 server block 보존 비활성화
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.service
인증서 사용처 확인
sudo 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

공식 문서

설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.

도구 빠른 검색

최근 사용한 도구를 다시 열거나, 이름과 기능으로 검색하세요.

검색어와 도구의 입력·결과는 저장하지 않습니다.

↑↓ 이동 · Enter 열기 · Esc 닫기