Ubuntu 26.04 강좌 / HTTPS 인증서 발급·자동 갱신·만료 점검하기
HTTPS는 자신이 관리하는 실제 도메인과 도메인 검증 경로를 준비한 뒤 인증서를 발급하고 웹 서버에 적용합니다. 발급 성공, 외부에서 제공되는 인증서, 자동 갱신 작업과 만료 감지는 각각 검증해야 합니다.
도메인과 공개 HTTP 조건 확인하기
Nginx 강좌의 127.0.0.1:8080 .test 실습 사이트는 인증서 발급 대상이 아닙니다. 실제 DNS가 서버를 가리키고 Nginx의 server_name·문서 루트·80번 응답이 맞는 사이트를 먼저 준비합니다. IPv6 AAAA 레코드가 있다면 그 경로도 실제로 동작해야 합니다.
다음 조회는 실제 도메인을 입력해 실행합니다. dig가 없으면 Ubuntu의 dnsutils 패키지를 준비합니다. 다른 네트워크의 클라이언트에서도 DNS와 HTTP 응답을 확인하고 방화벽·공유기·클라우드 규칙을 함께 검토합니다.
read -r -p "Domain you control: " domain
dig +short A "$domain"
dig +short AAAA "$domain"
curl -I "http://$domain/"
실제 도메인의 HTTP 사이트를 먼저 완성하기
이 절은 사용자 소유 도메인이 공개 주소로 연결되는 별도의 Ubuntu 웹 서버를 대상으로 합니다. 고정 IP 실습에 사용하는 호스트 전용 VM은 인터넷에서 직접 접속되지 않으므로 그대로 발급을 시도하지 않습니다. 공개 서버·DNS를 준비할 수 없으면 발급 실습은 보류하거나 공식 DNS 플러그인과 자격 증명 보관을 갖춘 DNS-01 경로를 따로 선택합니다.
Nginx와 curl을 준비하고 도메인의 A 레코드를 서버의 공개 IPv4로 설정합니다. AAAA가 있으면 IPv6 경로도 작동해야 합니다. 아래 전체 코드를 ~/prepare-public-http.sh에 저장하고 bash ~/prepare-public-http.sh 실제도메인으로 실행합니다. 일반 ASCII 호스트 이름용 예제이며 국제화 도메인은 검증한 퓨니코드 이름을 사용합니다. 기존 실습 경로가 있으면 덮어쓰지 않고 중단합니다.
set -eu
if [ "$#" -ne 1 ]; then
printf 'Usage: bash prepare-public-http.sh YOUR_DOMAIN\n' >&2; exit 2
fi
domain=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')
if [[ ! "$domain" =~ ^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]([a-z0-9-]*[a-z0-9])?$ ]]; then
printf 'Use a valid ASCII hostname you control.\n' >&2; exit 2
fi
case "$domain" in
*.test|*.invalid|*.localhost|*.example|example.com|*.example.com)
printf 'Use your real domain, not an example name.\n' >&2; exit 2 ;;
esac
site=/etc/nginx/sites-available/ubuntu-course-public
enabled=/etc/nginx/sites-enabled/ubuntu-course-public
root_dir=/srv/ubuntu-course-public
for path in "$site" "$enabled" "$root_dir"; do
if sudo test -e "$path" || sudo test -L "$path"; then
printf 'Existing lab path: %s; stop and inspect.\n' "$path" >&2; exit 1
fi
done
backup_dir=$(sudo mktemp -d /root/nginx-before-public.XXXXXX)
sudo cp -a /etc/nginx "$backup_dir/"
sudo install -d -m 0755 "$root_dir"
printf 'public-http-lab\n' | sudo sh -c 'set -C; cat > "$1/index.html"' sh "$root_dir"
sudo chmod 0644 "$root_dir/index.html"
sudo sh -c 'set -C; cat > "$1"' sh "$site" <<EOF
server {
listen 80;
listen [::]:80;
server_name $domain;
root /srv/ubuntu-course-public;
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOF
sudo ln -s "$site" "$enabled"
sudo nginx -t
sudo systemctl reload nginx
printf 'HTTP site prepared; backup: %s\n' "$backup_dir"
IPv6 리스너를 사용할 수 없는 서버는 실제 정책을 확인해 해당 listen 행을 조정하고 사용 불가능한 AAAA를 제공하지 않습니다. 파일·링크 생성, 검사와 reload가 모두 성공한 뒤 다음 단계로 갑니다. 실패하면 이번 파일·링크만 백업과 대조하며 다른 사이트를 덮어쓰지 않습니다.
UFW가 이미 관리 중인 새 공개 웹 서버에서 HTTP·HTTPS를 공개할 방침이면 다음 규칙을 추가합니다. SSH 규칙은 보존하고 공급자 방화벽·보안 그룹에도 80/443 경로를 준비합니다. UFW를 새로 활성화하는 명령은 아닙니다. HTTP-01 외부 검증은 실습 클라이언트 .10만 허용한 규칙으로 완료되지 않습니다.
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw status verbose
위 별도 스크립트의 domain 변수는 부모 셸에 남지 않습니다. 현재 Bash 세션에서 실제 이름을 다시 입력하고 다른 인터넷 연결의 클라이언트에서도 HTTP 본문의 public-http-lab을 확인합니다. 이름·본문·A/AAAA 경로가 맞는지 대조한 뒤 Certbot으로 진행합니다.
read -r -p "Domain you control: " domain
dig +short A "$domain"
dig +short AAAA "$domain"
curl --fail --show-error "http://$domain/"
Certbot 설치 경로를 하나로 정하기
기존 Certbot이 있으면 설치 출처와 갱신 작업을 먼저 확인하고 APT·Snap·pip 설치를 섞지 않습니다. 이 예시는 새 전용 서버에서 공식 Snap 경로를 선택합니다. classic 권한이 필요한 패키지라는 점을 읽고 설치하며 명령은 전체 경로로 실행해 다른 설치본과 혼동하지 않습니다.
sudo snap install --classic certbot
/snap/bin/certbot --version
Certbot 공식 Nginx·Snap 안내에서 설치·발급·갱신 시험 절차를 확인할 수 있습니다.
백업과 구문 검사 후 발급하기
(
set -eu
backup=$(sudo mktemp -d /root/nginx-before-tls.XXXXXX)
sudo cp -a /etc/nginx "$backup/"
sudo nginx -t
sudo /snap/bin/certbot --nginx -d "$domain"
)
같은 Bash 세션의 domain 변수에 실제 도메인이 들어 있는지 재확인하고 구문 검사 성공 후에만 Certbot을 실행합니다. 이메일·약관·리디렉션 선택은 안내를 읽고 결정합니다. 자동 설정은 Nginx 파일을 수정하므로 무엇이 바뀌었는지 백업과 비교합니다.
HTTP-01은 외부 검증자가 접근하는 경로가 필요합니다. 접근 불가 환경은 공식 DNS 플러그인 등 지원되는 방식을 별도로 선택하고 DNS API 자격 증명은 최소 권한으로 보관합니다. 발급 실패를 반복 요청으로 해결하려 하지 말고 DNS·포트·검증 로그를 먼저 조사합니다.
외부 HTTPS와 실제 인증서 확인하기
curl --fail --show-error "https://$domain/"
openssl s_client -connect "$domain:443" -servername "$domain" -verify_return_error -verify_hostname "$domain" </dev/null
이름·인증서 체인 검증과 예상 웹 응답을 확인합니다. 검증을 끄는 curl -k로 성공 표시를 만들지 않습니다. 로컬 발급 파일이 최신이어도 프록시·로드밸런서·다른 IPv6 서버가 오래된 인증서를 제공할 수 있으므로 사용자가 접속하는 실제 경로를 시험해야 합니다.
갱신 시험과 만료 감지
sudo /snap/bin/certbot certificates
sudo /snap/bin/certbot renew --dry-run
systemctl list-timers --all | grep certbot
dry-run은 현재 검증·갱신 경로의 시험이며 미래 작업이 반드시 성공한다는 보장은 아닙니다. 실제 timer·실행 로그·실패 알림과 외부 인증서 만료 감지를 함께 준비합니다. 인증서 유효 기간을 고정된 일수로 가정하지 말고 현재 notAfter를 확인합니다.
복원할 때는 이번 Certbot 변경과 Nginx 설정만 검토하고 다른 도메인의 인증서·갱신 구성을 삭제하지 않습니다. 인증서 갱신 뒤 실제 제공 경로의 새 인증서와 서비스 응답을 확인해야 HTTPS 운영 점검이 완료됩니다.




