← 글 목록

Let's Encrypt 붙이면서 놓칠 뻔한 것 두 가지

도메인을 연결하고 certbot으로 인증서를 받았다. 과정 자체는 금방 끝난다.

dnf install epel-release
dnf install certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com --redirect

"Congratulations!" 뜨고 브라우저에 자물쇠도 나왔다. 여기서 끝인 줄 알았는데 확인해 보니 두 가지가 걸렸다.

1. 자동 갱신이 안 돌고 있었다

certbot은 끝날 때 "자동 갱신 작업을 등록했다"고 알려 준다. 그런데 Rocky 9(EPEL 패키지)에서 타이머를 보니 이렇게 나왔다.

systemctl list-timers --all | grep certbot
# -   -   -   -   certbot-renew.timer   certbot-renew.service

enabled인데 다음 실행 시각이 비어 있다. 켜져는 있는데 시작이 안 된 상태다. 이대로 두면 90일 뒤에 인증서가 그냥 만료된다.

systemctl enable --now certbot-renew.timer
certbot renew --dry-run

이제 다음 실행 시각이 제대로 찍힌다. dry-run도 성공.

2. HSTS 헤더가 두 개

nginx에 HSTS 헤더를 직접 넣었다.

add_header Strict-Transport-Security "max-age=31536000" always;

그런데 curl -I로 보니 헤더가 두 줄이었다.

strict-transport-security: max-age=31536000 ; includeSubDomains
strict-transport-security: max-age=31536000

윗줄은 스프링 시큐리티가 붙인 거다. 시큐리티는 기본으로 HSTS를 켜 두는데, 요청이 https일 때만 헤더를 보낸다. 앞 글에서 프록시 헤더(X-Forwarded-Proto)를 제대로 읽게 해 놨더니 이제 앱이 https 요청이라는 걸 알아보고 헤더를 붙이기 시작한 것이다.

같은 헤더가 두 번 오면 브라우저마다 처리가 애매할 수 있어서 nginx 쪽을 지웠다. 설정을 한 군데에서만 관리하는 게 낫다.

정리

  • certbot 끝나고 systemctl list-timers로 갱신 타이머가 진짜 도는지 볼 것
  • certbot renew --dry-run 한 번 돌려 볼 것
  • HSTS는 앱이나 nginx 중 한 곳에서만 붙일 것

HSTS를 켜면 브라우저가 1년 동안 그 도메인을 https로만 연다. 나중에 인증서를 날려 먹으면 접속 자체가 안 되니까, 갱신 확인은 진짜 중요하다.