GitHub Actions가 안 보일 때…Wrangler로 정적 블로그를 직접 올린 날
PR만 만들고 Actions가 돌지 않던 날, npm run build와 wrangler deploy로 Workers 자산을 올린 기록. 지금은 main 푸시→Actions가 기본이지만, CI가 침묵할 때 비상 레일을 언제 쓰는지 같이 정리합니다.

증상은 ‘코드는 있는데 사이트에 글이 없다’였다. 브랜치에 글을 올리고 PR까지 만들었는데, 대시보드의 GitHub Actions 목록에는 이번 푸시가 잡히지 않았다. seominhyuk.com 카테고리 페이지도 예전 목록이었다. 배포 파이프라인을 Actions에만 맡긴 채 기다리면, 파이프라인 자체가 침묵할 때 콘텐츠 발행이 통째로 멈춘다.
이 글을 처음 쓸 당시에는 로컬 Wrangler가 사실상 유일한 발행 경로였다. 그 뒤 레포에 .github/workflows/deploy.yml이 붙었고, main 푸시가 npm run build + wrangler deploy를 돌린다. 그래도 Actions가 안 보이거나 실패하는 날의 비상 레일은 그대로 유효하다. 아래는 그날의 재현과, 지금 운영에서 Wrangler 수동 배포를 언제 꺼내는지다.
사실: 로컬 빌드는 되고, 원격 트리거만 없었다
레포에는 이미 package.json에 "deploy": "npm run build && wrangler deploy"가 있었다. wrangler.jsonc는 assets.directory를 ./dist로 두고, html_handling은 drop-trailing-slash, not_found_handling은 404-page였다. 즉 Cloudflare Workers 정적 자산 배포 경로가 문서·스크립트 수준에서는 준비돼 있었다.
로컬에서 npm run build를 돌리니 Astro가 콘텐츠를 동기화하고 dist/에 HTML을 쌓았다. 새 글 경로도 생성됐다. 그다음 wrangler deploy는 “17 new or modified static assets”를 올리고 warpsense-blog 버전 ID를 반환했다. workers.dev URL에서는 새 HTML이 즉시 보였다. **빌드·업로드는 정상이고, 빠진 고리는 ‘누가 언제 deploy를 돌리느냐’**였다.
한 가지 더. 깨끗한 클론처럼 node_modules가 없으면 astro: command not found로 빌드가 바로 죽는다. Actions가 안 도는 날에는 로컬에서 npm install(또는 npm ci)부터 다시 확인하는 편이 빠르다. 비밀값·토큰은 커밋하지 않고, Wrangler가 이미 로그인된 CLI 세션을 쓰게 했다.
이유: ‘푸시=배포’는 계약이 아니라 가정이다
많은 팀이 GitHub에 푸시하면 Pages/Workers가 따라온다고 가정한다. 그 가정이 성립하려면 워크플로 파일, 브랜치 필터, 시크릿, 계정 권한이 모두 살아 있어야 한다. 이번처럼 PR만 열고 Actions가 목록에 안 뜨면, 원인은 콘텐츠가 아니라 트리거 계층이다. 콘텐츠 컬렉션에 md를 추가해도, 배포 명령이 한 번도 실행되지 않으면 프로덕션 HTML은 바뀌지 않는다.
직접 Wrangler를 꽂는 선택은 우아한 CI 대체물이 아니다. 비상 레일이다. 다만 정적 블로그처럼 dist 산출물이 명확한 프로젝트에서는 비상 레일이 곧 발행 SLA가 된다. “PR 머지 대기”와 “독자에게 글이 보이는 시각”을 분리해 두지 않으면, 자동화 장애가 곧 편집 장애가 된다.
에이전트·cron이 cursor/bc-* 같은 feature 브랜치에만 커밋하고 멈추는 날도 같은 계열이다. deploy.yml이 on.push.branches: [main]이면, 내용이 같아 보여도 ref가 main이 아니면 job은 0건이다. 그때도 “글 파일을 더 고친다”보다 git checkout main && git pull 후 main에 올리는지, 아니면 로컬 npm run deploy로 비상 배포할지를 먼저 고른다.
조치: 그날 실제로 돌린 순서
npm install로 로컬 도구 체인 복구npm run build로dist/와 신규 slug HTML 확인wrangler deploy(또는npm run deploy)로 Workers 자산 업로드- workers.dev와 커스텀 도메인에서 해당
/posts/<slug>를 열어 HTML이 바뀌었는지 확인
지금은 정상 경로가 다르다. 글을 main에 푸시하면 Actions가 빌드·배포한다. 수동 Wrangler는 Actions 목록에 SHA가 없거나, job이 빨간불이고 재시도가 막혔을 때만 꺼낸다. Cloud Agent VM에 CLOUDFLARE_API_TOKEN이 없어도, main 푸시만 성공하면 CI 시크릿으로 배포가 이어진다는 점이 기본 경로를 바꾼다. 반대로 VM에서만 wrangler deploy를 반복하는 습관은 감사 추적과 계정 권한을 흐린다.
연속으로 여러 번 main에 푸시하면 deploy.yml의 concurrency + cancel-in-progress 때문에 중간 job이 취소될 수 있다. 비상 수동 배포와 CI가 겹치면 “누가 마지막 버전인지”가 더 헷갈린다. 같은 날에는 한 경로만 고르는 편이 안전하다.
검증: 배포 완료의 정의
내가 쓰는 완료 정의는 세 줄이다.
- Actions에 해당 SHA가 보이거나, 의도적으로 수동
wrangler deploy로그에 버전 ID가 있다. - 같은 커밋에서 로컬
npm run build가 성공한다. curl -sI -L https://seominhyuk.com/posts/<slug>가 200이고, 필요하면 AdsBot UA로도 한 번 더 본다.
workers.dev만 새것이고 apex가 옛것이면 CDN·캐시·도메인 라우팅을 의심한다. HTML이 200이어도 본문이 이전이면 브라우저 강력 새로고침과 cf-cache-status를 같이 본다. curl 200 전에는 “발행했다”고 쓰지 않는다.
평가: 어디에 쓰고, 어디에 안 쓰는가
쓰는 곳: Actions·연동 배포가 침묵할 때, 미리보기 URL로 내용만 먼저 확인해야 할 때, wrangler.jsonc의 assets 설정이 이미 검증된 프로젝트. 안 쓰는 곳: 비밀·환경변수가 배포마다 바뀌는 앱, 프로덕션 승인 게이트가 필요한 규제 영역, 로컬 머신에만 Wrangler 로그인된 개인 계정으로 팀 프로덕션을 반복 배포하는 경우.
한계도 분명하다. 직접 배포는 감사 로그·브랜치 보호·리뷰 기록을 Actions만큼 남기지 않을 수 있다. 그래서 비상 배포 뒤에는 왜 Actions가 안 돌았는지를 별도 이슈로 남겨야 한다. 그렇지 않으면 다음에도 같은 침묵이 반복된다. 시니어 IT 실무자 시각으로 보면, 자동화는 기본값이고 수동 Wrangler는 명시적 예외여야 한다.
다음에 볼 것: 워크플로가 main 푸시에서만 도는지, PR 브랜치 이름 필터에 막히는지, Cloudflare Git 연동이 Workers 이름(warpsense-blog)과 일치하는지, 저장소 시크릿 CLOUDFLARE_API_TOKEN이 Actions에만 있는지. 콘텐츠 글쓰기와 배포 배선은 한 팀의 일이지만, 실패 모드는 다르다. 글이 안 보이면 먼저 파이프라인을 의심하는 습관이 필요하다.
실무에서 남긴 최소 체크는 세 줄이다. (1) Actions에 해당 SHA가 보이는가. (2) 로컬 npm run build가 같은 커밋에서 성공하는가. (3) wrangler deploy 또는 CI 배포 후 workers.dev와 커스텀 도메인 캐시가 같은 HTML인가. 세 줄이 어긋나면 콘텐츠를 더 고치기 전에 배포 경로를 먼저 고친다. 정적 블로그는 글의 품질만큼이나 보이는 시각이 제품이다.
습관: 자동화 복구를 배포와 같은 할 일로
비상 Wrangler로 글을 살린 뒤에는 반드시 Actions 침묵 원인을 닫는다. 워크플로 파일 누락, 브랜치 필터, 시크릿 만료, feature 브랜치에만 푸시한 습관—원인이 무엇이든 다음 발행이 다시 수동에 기대지 않게 만드는 것이 목표다. 블로그 자동화(n8n·에이전트)도 결국 main 푸시와 배포 검증에 기대므로, “콘텐츠 파이프라인”과 “배포 파이프라인”을 한 체크리스트에 묶어 두는 편이 싸다.
출처
- 내부 실측:
npm run build→ Astro static build 성공,wrangler deploy로 assets 업로드 및warpsense-blog버전 배포 (2026-07-31~08-01, 비밀값 제외) - 레포 설정:
package.jsonscripts.deploy,wrangler.jsoncassets.directory=./dist,.github/workflows/deploy.ymlmain push 트리거 - Cloudflare Workers static assets / Wrangler 배포 문서 — 열람: 2026-08-01
- 관련 회고: main 푸시에 Wrangler가 붙은 날, cursor/* 브랜치와 main 푸시