메뉴 닫기

Certbot Hook으로 Let’s Encrypt 갱신 시 80번 포트 임시 허용하기

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에서 해당 규칙을 다시 삭제합니다.

실제 테스트에서도 아래와 같이 정상적으로 동작했습니다.

Certbot Hook Let's Encrypt 자동 갱신 테스트

5. 자동 갱신 테스트

설정이 정상적으로 저장됐는지 확인합니다.

grep -E '^(pre_hook|post_hook)' \
/etc/letsencrypt/renewal/example.com.conf

이후 실제 갱신 전에 dry-run으로 테스트합니다.

certbot renew \
    --cert-name example.com \
    --dry-run

Certbot Hook Let's Encrypt 자동 갱신 테스트

정상적으로 완료되면 갱신할 때도 80번 포트가 잠시 허용됐다가 다시 기존 방화벽 정책으로 돌아옵니다.

마지막으로 자동 갱신 timer를 활성화합니다.

systemctl enable --now certbot-renew.timer

마무리

방화벽에서 해외망을 차단하거나 특정 IP만 허용해서 운영하고 있다면 Let’s Encrypt 인증서 갱신 때문에 80번 포트를 항상 열어둘 필요는 없습니다.

Certbot의 pre-hook, post-hook을 이용하면 인증할 때만 80번 포트를 잠시 허용하고, 인증이 끝난 뒤 기존 방화벽 정책으로 다시 돌릴 수 있습니다.

다만 서버 앞단에 별도의 방화벽이나 ELCAP을 사용하고 있다면 해당 장비의 정책도 같이 확인해야 합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다