Certbot Hook을 이용해서 Let’s Encrypt 인증서를 발급하거나 갱신할 때만 80번 포트를 임시로 허용하도록 구성해보겠습니다.
웹서버를 운영하다 보면 해외망을 차단하거나 특정 IP만 접근할 수 있도록 방화벽 정책을 적용하는 경우가 있습니다.
Let’s Encrypt의 HTTP-01 인증 방식은 외부 인증 서버에서 웹서버의 80번 포트로 접속해서 인증 파일을 확인하기 때문에, 방화벽에서 접근을 제한하고 있다면 인증서 발급이나 갱신에 실패할 수 있습니다.
HTTP-01 인증 방식에 대한 자세한 내용은 Let’s Encrypt Challenge Types 공식 문서에서 확인할 수 있습니다.
이번에는 80번 포트를 항상 열어두지 않고 Certbot Hook이 실행될 때만 임시로 허용하고, 인증이 끝나면 다시 기존 방화벽 정책으로 복구하도록 설정해보겠습니다.
테스트 환경은 Rocky Linux 9, Apache, nftables를 사용했습니다.
1. 80번 포트 임시 허용 스크립트
vi /usr/local/sbin/certbot-open-http.sh
#!/bin/bash
set -e
TABLE="inet"
TABLE_NAME="filter"
CHAIN="input"
COMMENT="certbot-temp-http"
# 이미 규칙이 있으면 중복 추가하지 않음
if nft -a list chain "$TABLE" "$TABLE_NAME" "$CHAIN" | \
grep -q "comment \"$COMMENT\""; then
exit 0
fi
# 80번 포트 임시 허용
nft add rule "$TABLE" "$TABLE_NAME" "$CHAIN" \
tcp dport 80 \
ct state new \
accept \
comment "$COMMENT"
실행 권한을 추가합니다.
chmod 750 /usr/local/sbin/certbot-open-http.sh
TABLE, TABLE_NAME, CHAIN은 현재 사용 중인 nftables 구성에 맞게 변경하면 됩니다.
COMMENT는 나중에 Certbot에서 추가한 규칙만 찾아서 삭제하기 위해 사용합니다.
2. 임시 규칙 제거 스크립트
vi /usr/local/sbin/certbot-close-http.sh
#!/bin/bash
set -e
TABLE="inet"
TABLE_NAME="filter"
CHAIN="input"
COMMENT="certbot-temp-http"
HANDLE=$(nft -a list chain "$TABLE" "$TABLE_NAME" "$CHAIN" | \
awk -v comment="$COMMENT" '
$0 ~ "comment \"" comment "\"" {
for (i=1; i<=NF; i++) {
if ($i == "handle") {
print $(i+1)
exit
}
}
}')
# 규칙이 없으면 종료
if [ -z "$HANDLE" ]; then
exit 0
fi
# Certbot에서 추가한 규칙만 삭제
nft delete rule "$TABLE" "$TABLE_NAME" "$CHAIN" handle "$HANDLE"
chmod 750 /usr/local/sbin/certbot-close-http.sh
nftables의 rule에는 각각 handle 번호가 붙습니다.
이 스크립트에서는 certbot-temp-http라는 comment를 기준으로 handle 번호를 찾아서 해당 규칙만 삭제합니다.
3. Certbot 설치
Rocky Linux 9에서는 EPEL 저장소를 이용해서 설치했습니다.
dnf config-manager --set-enabled crb
dnf install -y epel-release
dnf install -y certbot python3-certbot-apache
설치 확인:
certbot --version
4. Hook을 사용해서 인증서 발급
Apache의 DocumentRoot가 /var/www/html인 경우 아래와 같이 실행할 수 있습니다.
certbot certonly \
--webroot \
-w /var/www/html \
-d example.com \
--pre-hook /usr/local/sbin/certbot-open-http.sh \
--post-hook /usr/local/sbin/certbot-close-http.sh
pre-hook에서는 80번 포트를 임시로 전체 허용하고, 인증이 끝나면 post-hook에서 해당 규칙을 다시 삭제합니다.
실제 테스트에서도 아래와 같이 정상적으로 동작했습니다.

5. 자동 갱신 테스트
설정이 정상적으로 저장됐는지 확인합니다.
grep -E '^(pre_hook|post_hook)' \
/etc/letsencrypt/renewal/example.com.conf
이후 실제 갱신 전에 dry-run으로 테스트합니다.
certbot renew \
--cert-name example.com \
--dry-run

정상적으로 완료되면 갱신할 때도 80번 포트가 잠시 허용됐다가 다시 기존 방화벽 정책으로 돌아옵니다.
마지막으로 자동 갱신 timer를 활성화합니다.
systemctl enable --now certbot-renew.timer
마무리
방화벽에서 해외망을 차단하거나 특정 IP만 허용해서 운영하고 있다면 Let’s Encrypt 인증서 갱신 때문에 80번 포트를 항상 열어둘 필요는 없습니다.
Certbot의 pre-hook, post-hook을 이용하면 인증할 때만 80번 포트를 잠시 허용하고, 인증이 끝난 뒤 기존 방화벽 정책으로 다시 돌릴 수 있습니다.
다만 서버 앞단에 별도의 방화벽이나 ELCAP을 사용하고 있다면 해당 장비의 정책도 같이 확인해야 합니다.





