GitHub에 저장한 Hugo 소스를 Cloudflare Pages에서 빌드하고 pages.dev 주소로 배포했다. 기존 GitHub Pages는 유지한 상태에서 새 배포를 먼저 검증했다.
이 글은 GitHub 저장소 연결, 첫 배포, 이후 push에 따른 자동 배포까지 다룬다. 신규 사이트에도 같은 순서를 적용할 수 있다. 기존 운영 도메인과 DNS는 여기서 변경하지 않는다.
1. 배포 환경과 사전 확인#
| 항목 | 사용한 값 |
|---|---|
| 소스 저장소 | jinosoft/jinosoft-blog |
| 운영 브랜치 | main |
| 정적 사이트 생성기 | Hugo 0.165.0 Extended |
| 테마 | Blowfish, Git 서브모듈 |
| 빌드 출력 디렉터리 | public |
| 기본 배포 주소 | https://jinosoft-blog.pages.dev/ |
로컬에서 다음 명령으로 빌드가 가능한 저장소를 준비한다.
hugo version
hugo --minify이번 저장소의 themes/blowfish는 .gitmodules에 등록된 공개 서브모듈이다. Cloudflare의 복제 로그에서도 해당 서브모듈을 체크아웃한 것을 확인했다. 외부 테마 파일을 로컬에만 두고 Git에 등록하지 않았다면 배포 환경에서 읽을 수 없으므로 먼저 확인한다.
2. Workers 생성 화면에서 Pages로 이동#
Cloudflare에 로그인하고 Workers & Pages → Create application으로 이동한다.
이번 화면에서는 GitHub 연결 버튼이 먼저 보였지만, 하단의 Continue to Pages를 선택해야 Pages 생성 절차로 이동했다.
Deploy command에 npx wrangler deploy, Preview command에 npx wrangler preview가 표시된다면 Workers 빌드 설정 화면이다. Workers로도 정적 사이트를 배포할 수 있지만, 이 글은 Cloudflare Pages의 Git 연동을 사용한다. 명령만 바꾸지 말고 Pages 생성 화면으로 이동한다. Workers 빌드 설정
Pages 화면에서 Import an existing Git repository → Get started를 선택한다. 메뉴 이름이나 진입 경로는 UI 변경에 따라 달라질 수 있다. Pages Git 연동 안내
이 과정에서 만드는 것은 **Pages 프로젝트(project)**다. 프로젝트에 저장소·빌드 명령·도메인을 설정하고, 빌드를 실행할 때마다 배포(deployment) 기록이 생성된다. 글을 올릴 때마다 새 프로젝트를 만드는 구조는 아니다.
3. GitHub 저장소 접근 권한 설정#
GitHub 연결 과정에서 Cloudflare의 GitHub App 설치·권한 요청이 표시되면 Only select repositories를 선택하고 배포할 저장소만 지정한다.
이번에는 jinosoft/jinosoft-blog만 선택한 뒤 Install & Authorize를 진행했다. GitHub App 설치 권한과 로컬 git push에 사용하는 PAT는 별개다. 이 작업을 위해 기존 PAT를 Cloudflare 입력란에 붙여 넣지 않는다.
Cloudflare로 돌아와 저장소를 선택하고 Begin setup을 클릭한다.
저장소가 표시되지 않으면 Cloudflare Pages용 GitHub App에 해당 저장소 접근 권한을 부여했는지 확인한다. Public·Private 저장소 모두 연동할 수 있지만, Private 저장소는 앱의 접근 권한이 있어야 한다.
4. Hugo 빌드 설정#
프로젝트 이름과 운영 브랜치, 빌드 설정을 지정한다.
| 항목 | 설정값 |
|---|---|
| Project name | jinosoft-blog |
| Production branch | main |
| Framework preset | Hugo |
| Build command | hugo --minify |
| Build output directory | public |
| Root directory | 저장소 루트, 기본값 유지 |
초기 캡처에는 프리셋의 기본 명령인 hugo가 표시되어 있다. 이후 Settings → Build configuration에서 hugo --minify로 변경했다. --minify는 생성 결과를 최소화하는 옵션이며, 다음 절의 버전 불일치 오류를 해결하는 옵션은 아니다.
public은 저장소의 소스 디렉터리가 아니라 Hugo 빌드 결과가 생성되는 경로다. 빌드 후 Cloudflare가 이 디렉터리를 정적 사이트로 배포한다.
이 블로그는 최종 운영 주소를 유지할 예정이므로 baseURL을 변경하지 않았다.
baseURL = "https://blog.jinosoft.com/"새 사이트라면 자신의 최종 공개 주소에 맞춰 설정한다. pages.dev를 최종 주소로 사용할지, 커스텀 도메인을 연결할지에 따라 결정한다. 이 블로그처럼 커스텀 도메인을 유지할 경우 빌드 명령에 --baseURL $CF_PAGES_URL을 무조건 추가하면 표준 URL이 임시 주소로 바뀔 수 있다.
5. Hugo 버전 지정과 Locale 오류 해결#
첫 배포는 빌드 단계에서 실패했다. 로그에는 다음 버전과 오류가 표시됐다.
hugo v0.147.7 ... +extended
WARN Module "blowfish" is not compatible with this Hugo version
can't evaluate field Locale in type *langs.Language로컬과 기존 GitHub Actions는 Hugo 0.165.0 Extended를 사용했지만, 이번 Cloudflare 첫 빌드는 0.147.7 Extended로 실행됐다. 테마가 요구하는 Hugo 버전을 충족하지 못한 것이 원인이었다. 이 오류를 해결하려고 테마의 Locale 코드를 삭제할 필요는 없다.
프로젝트의 Settings → Variables and secrets에서 Production 환경에 다음 변수를 추가한다.
| 변수 | 값 | 목적 |
|---|---|---|
HUGO_VERSION | 0.165.0 | 사용할 Hugo 버전 지정 |
HUGO_ENVIRONMENT | production | Hugo 실행 환경 명시 |
버전 오류 해결에 직접 필요한 값은 HUGO_VERSION이다. HUGO_ENVIRONMENT는 테마·템플릿이 참조하는 환경 구분이며 Hugo 버전을 바꾸지 않는다.
저장한 뒤 Deployments에서 실패한 배포의 Retry deployment를 실행한다. 환경변수는 이미 완료된 배포에 소급 적용되지 않으므로 새 빌드가 필요하다. 빌드 로그에서 실제 실행 버전과 +extended 표시를 확인한다. Preview 브랜치에도 같은 구성이 필요하다면 Preview 환경의 변수도 별도로 설정한다. Hugo 버전 지정 공식 안내
실패 로그 해석과 버전 확인 절차는 can’t evaluate field Locale 오류 해결에 별도로 정리했다.
6. 배포 성공과 pages.dev 접속 확인#
변수 지정 후 재시도한 배포는 저장소 복제·빌드·업로드가 모두 성공했다.
로그의 다음 안내는 이번 정적 사이트 배포에서 실패 원인이 아니었다.
No Wrangler configuration file found. Continuing.
No functions dir at /functions found. Skipping.이번 구성은 Pages Functions나 Wrangler 설정 없이 Hugo의 정적 결과물만 배포했다.
배포 주소를 브라우저에서 열어 홈 화면과 기존 글이 표시되는지 확인한다.
최종 도메인이 아직 기존 호스팅을 가리킨다면 절대 URL 링크를 클릭할 때 기존 사이트로 이동할 수 있다. 새 호스팅의 검증은 주소창의 호스트도 확인하면서 pages.dev의 글 경로를 직접 열어 진행한다.
https://jinosoft-blog.pages.dev/
https://jinosoft-blog.pages.dev/posts/docker-volume-data-persistence/홈 화면만으로 끝내지 말고 글 본문, 이미지·CSS, 검색 기능도 확인한다. 이번 단계에서는 새 호스팅 배포를 확인했으며, 기존 도메인의 DNS나 저장소 공개 범위는 아직 변경하지 않았다.
7. 이후 글 수정은 push하면 자동 배포#
GitHub와 연동한 Pages 프로젝트는 운영 브랜치에 새 커밋이 push되면 자동으로 빌드·배포한다. 운영 브랜치를 main으로 지정하고 자동 배포를 활성화한 이 구성에서는 매번 Cloudflare에서 배포 버튼을 누를 필요가 없다. Cloudflare Git 연동 동작
글을 작성한 뒤 반영되는 순서는 다음과 같다.
- 로컬에서 글·이미지를 수정하고 변경 파일을 commit한다.
git push origin main으로 GitHub의main브랜치에 올린다.- Cloudflare가 변경을 감지해 저장소와 테마 서브모듈을 복제한다.
- 설정된
hugo --minify를 실행하고public의 결과물을 배포한다. - 배포가 성공하면 프로젝트의 운영 주소에 변경 내용이 반영된다.
로컬 파일 저장이나 commit만으로는 배포되지 않는다. GitHub로 push해야 하며, push 성공과 Cloudflare 배포 성공도 별개다. Pages의 Deployments에서 해당 커밋·브랜치와 빌드 결과를 확인한다. Hugo 빌드가 실패하면 수정 내용은 게시되지 않는다.
public을 로컬에서 생성해 업로드하거나 Git에 추가할 필요는 없다. 이 구성은 Cloudflare가 Hugo를 실행하므로 별도 GitHub Actions 배포 워크플로도 필요하지 않다. 커스텀 도메인을 연결한 뒤에는 같은 자동 배포 결과가 그 주소에도 반영된다.
main과 다른 브랜치는 어떻게 처리될까#
main은 Production 배포 대상이다. 다른 브랜치는 Preview 배포가 활성화되어 있으면 별도의 미리보기 URL로 배포되며, 운영 사이트를 바로 교체하지 않는다. 이후 변경 내용을 main에 merge하면 운영 브랜치가 갱신되어 Production 배포가 실행된다.
push해도 배포 기록이 생기지 않으면 프로젝트 설정의 Branch control에서 운영 브랜치와 Enable automatic production branch deployments를 확인한다. Preview 배포 대상도 이곳에서 지정한다. GitHub App의 저장소 접근 권한이나 빌드 건너뛰기 설정 역시 확인할 항목이다. 브랜치별 자동 배포 설정
Retry deployment는 실패 원인을 수정한 뒤 같은 커밋을 다시 빌드할 때 사용한다. 평소 글을 수정할 때는 새 커밋을 push하면 된다.
마무리#
GitHub 저장소와 Blowfish 서브모듈을 Cloudflare에서 복제하고, Hugo 버전을 맞춰 pages.dev 배포를 완료했다. 이후에는 GitHub에 소스를 올리고 Cloudflare의 배포 결과를 확인하는 방식으로 운영한다.
서비스 선택 기준은 GitHub Pages와 Cloudflare Pages 비교, 기존 도메인과 Private 저장소 전환은 GitHub Pages에서 Cloudflare Pages로 이전하기에서 확인할 수 있다.