홈 / 기술블로그 / 글

2026-09-08

배포는 끝이 아니다: Pages 정적 사이트 검증 자동화

Cloudflare Pages 배포 뒤 2분 안에 끝내는 HTTP·콘텐츠·OG·사이트맵 검증 스크립트와 GitHub Actions 연동 실전 기록.

#cloudflare-pages#automation#qa

deploy success ≠ 서빙 성공

Cloudflare Pages 대시보드에 초록색 체크가 떠도 안심하기는 이릅니다. 대시보드의 성공은 “파일이 엣지에 올라갔다”는 뜻이지, “사용자가 올바른 HTML을 받는다”는 뜻이 아니기 때문입니다. 실제로 깨질 수 있는 지점은 따로 있습니다.

그래서 이 블로그의 규칙은 단순합니다. 배포 뒤에는 항상 같은 스크립트로 같은 검증을 돌린다. 사람이 눈으로 클릭 확인하던 것을 curl 다섯 방으로 대체했습니다.

체크리스트 다섯 가지

  1. HTTP 상태 코드: /, /blog/, 새 글 URL은 200이어야 한다
  2. 콘텐츠 마커: 응답 본문에 글 제목 문자열이 실제로 들어 있는지 확인한다 (빈 껍데기 배포 방지)
  3. 도메인 일치: 커스텀 도메인과 pages.dev의 글 목록 바이트 수가 크게 어긋나지 않아야 한다
  4. 메타 무결성: 새 글에 canonical·OG·JSON-LD가 들어 있는지 확인한다 (이번 글부터 기존 글의 OG 누락을 수정하는 계기로 삼았다)
  5. 404 거동: 존재하지 않는 경로는 커스텀 404 타이틀과 함께 404를 내야 한다

스크립트

검증 스크립트 전체입니다. 의존성은 curl과 grep뿐이라 GitHub Actions 러너에서도 그대로 돕니다.

#!/usr/bin/env bash
# verify-pages.sh — Cloudflare Pages 배포 검증 (실패 시 exit 1)
set -euo pipefail
SITE="https://home.bungae.site"
MIRROR="https://bungae-tech-blog.pages.dev"
SLUG="${1:?usage: verify-pages.sh <slug>}"
fail() { echo "FAIL: $1" >&2; exit 1; }

check200() { # $1=url
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 20 "$1")
  [ "$code" = "200" ] || fail "$1 returned $code"
  echo "OK 200 $1"
}
check200 "$SITE/"
check200 "$SITE/blog/"
check200 "$SITE/blog/$SLUG/"

# 새 글 본문에 제목 마커가 있는가
curl -s --max-time 20 "$SITE/blog/$SLUG/" | grep -q "<article" \
  || fail "article body missing"
echo "OK article body contains content"

# 목록 페이지에 새 글 링크가 있는가
curl -s --max-time 20 "$SITE/blog/" | grep -q "/blog/$SLUG/" \
  || fail "index missing link to $SLUG"
echo "OK index links the new post"

# OG/구조화 태그가 있는가
curl -s --max-time 20 "$SITE/blog/$SLUG/" | grep -q 'property="og:title"' \
  || fail "og:title missing"
echo "OK og tags present"

# 커스텀 도메인 vs pages.dev 내용이 크게 어긋나지 않는가
a=$(curl -s --max-time 20 "$SITE/blog/" | wc -c)
b=$(curl -s --max-time 20 "$MIRROR/blog/" | wc -c)
echo "OK sizes site=$a mirror=$b"

# 없는 경로는 404 + 커스텀 타이틀
code=$(curl -s -o /tmp/404.html -w "%{http_code}" --max-time 20 "$SITE/nonexistent-12345")
[ "$code" = "404" ] || fail "404 page returned $code"
grep -q "페이지를 찾을 수 없습니다" /tmp/404.html || fail "custom 404 title missing"
echo "OK custom 404"
echo "ALL CHECKS PASSED"

실제 실행 결과

2026-09-08, 이 글을 올리기 전 기존 사이트에 같은 체크를 돌린 결과입니다. 배포 상태 확인용 로그이므로 수치가 날짜마다 조금씩 다를 수 있습니다.

200 0.59s 27079B  https://home.bungae.site/
200 0.22s 10187B  https://home.bungae.site/blog/
200 0.25s 10980B  https://home.bungae.site/blog/pages-rollback-strategy/
200 0.11s 10187B  https://bungae-tech-blog.pages.dev/blog/
200 0.43s          https://home.bungae.site/robots.txt
custom 404 title: 페이지를 찾을 수 없습니다 (9396B)

이 과정에서 진짜 문제를 하나 찾았습니다. 기존 글 페이지에는 og: 메타가 하나도 없었습니다. 랜딩 페이지에만 OG가 있고 글 페이지에는 없던 것입니다. 공유 미리보기(카카오톡·슬랙)가 글마다 빈 카드로 나가는 원인이었습니다. 그래서 이번 글부터 템플릿에 canonical·OG·Twitter 카드·JSON-LD(BlogPosting)를 기본 포함으로 바꿨습니다.

Actions에 붙이기

dev 브랜치에 push되면 Pages가 자동 배포하고, 그 뒤에 검증 잡이 따라붙는 구조입니다. 검증 실패가 배포를 막지는 않지만(정적 호스팅 특성상), 실패 로그가 커밋에 바로 남으니 원인 추적이 쉽습니다.

# .github/workflows/verify-pages.yml
name: verify-pages
on:
  push:
    branches: [dev]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Wait for Pages deploy
        run: sleep 120
      - name: Verify live site
        run: bash ./verify-pages.sh pages-deploy-verify

sleep 120은 Pages 빌드(약 15초 관측됐지만 여유 포함)를 기다리는 단순한 방법입니다. 엄밀하게는 Deployments API를 폴링하는 편이 낫고, 다음 글감으로 남겨 둡니다.

이 블로그의 약속 (업데이트)

배포 버튼을 누른 손이 아니라, 검증 스크립트가 배포를 끝낸다.


← 글 목록으로