본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 27. 00:17

AI를 사용하여 WordPress 사이트를 Cloudflare Pages로 마이그레이션한 방법 (그리고 무엇이 망가졌는가)

요약

WordPress 사이트를 AI와 Astro를 활용하여 Cloudflare Pages 기반의 정적 사이트로 마이그레이션하는 과정을 다룹니다. Claude를 사용하여 콘텐츠 인벤토리를 작성하고 컴포넌트를 생성함으로써 복잡한 PHP 스택을 가벼운 에지 네트워크 환경으로 전환하는 방법을 설명합니다.

핵심 포인트

  • Claude를 활용해 WordPress XML 데이터를 분석하고 콘텐츠 인벤토리 자동 생성
  • Astro와 Cloudflare Pages를 결합한 고성능 정적 사이트 스택 구축
  • 서버 관리 비용 절감 및 글로벌 에지 네트워크를 통한 성능 최적화
  • 정적 사이트 전환 시 동적 로직은 Cloudflare Workers로 보완 가능

WordPress는 모든 것을 수행합니다. 그것이 문제이자 해결책이기도 합니다.

저는 플러그인(plugins), 테마(themes), WooCommerce, Gutenberg 등 WordPress 생태계에서 수년을 보냈습니다. 이는 복잡한 사례를 매우 잘 처리하는 성숙하고 강력한 플랫폼입니다. WordPress가 나쁘다는 말을 하려는 것이 아닙니다.

하지만 AI와 함께하면서, WordPress가 과잉(overkill)이 되는 사이트 카테고리가 생겨났습니다. 랜딩 페이지(landing pages), 제품 사이트(product sites), 기업 페이지(company pages), 포트폴리오(portfolios) 같은 것들입니다. 본질적으로 연락처 양식(contact form)이 포함된 정적 콘텐츠(static content)인 페이지들 말이죠. 에지(edge)에서 제공되는 순수 HTML만으로도 충분할 페이지를 위해, 전체 PHP 스택을 실행하고, 플러그인 업데이트를 관리하며, 서버 호스팅 비용을 지불하고 있는 상황입니다.

그러한 경우들을 위해, 저는 모든 것을 마이그레이션(migration)하기 시작했습니다. 목적지는 Cloudflare Pages입니다. 과정은 대체로 AI의 도움을 받았습니다.

그 과정은 다음과 같았습니다.

왜 Cloudflare Pages인가

이 프로젝트에서 Vercel, Netlify, GitHub Pages를 제치고 선택한 몇 가지 이유가 있습니다:

  • 콜드 스타트(cold starts)가 없는 글로벌 에지 네트워크(Global edge network)
  • 진정으로 관대한 무료 티어(Free tier) — 무제한 요청, 무제한 대역폭
  • 마이그레이션 후에도 유지되는 동적 로직을 위한 Cloudflare Workers
  • 나중에 필요할 경우를 대비한 경량 데이터베이스 용도의 D1
  • 모든 것이 하나의 생태계(ecosystem) 안에 있음

만약 여러분이 이미 DNS를 위해 Cloudflare를 사용하고 있다면(대부분의 사람들이 그렇듯), 마이그레이션 경로는 생각보다 짧습니다.

마이그레이션 후의 스택

  • 정적 사이트 생성기 (Static site generator): Astro — 순수 HTML 출력, 상호작용이 필요한 컴포넌트를 위한 부분적 하이드레이션(partial hydration), 뛰어난 빌드 성능
  • 호스팅 (Hosting): Cloudflare Pages
  • 양식 (Forms): FormRoute — 이에 대해서는 나중에 더 자세히 다루겠습니다
  • 사용된 AI: 콘텐츠 변환 및 컴포넌트 생성을 위한 Claude

1단계 — WordPress 콘텐츠 내보내기 및 인벤토리 작성

첫 번째 단계: 실제로 무엇을 가지고 있는지 이해하는 것입니다.

# WordPress에서 모든 것을 내보내기
# 관리자(Admin) → 도구(Tools) → 내보내기(Export) → 모든 콘텐츠(All content)
# XML 파일 다운로드

XML 내보내기를 통해 포스트(posts), 페이지(pages), 카테고리(categories), 태그(tags), 작성자(authors) 및 미디어 참조(media references)를 얻을 수 있습니다. 실제 미디어 파일은 제공되지 않으며, 이는 별도로 제공됩니다.

저는 XML 내보내기 파일을 Claude에 입력하고 다음과 같이 요청했습니다:

  1. 제목, 슬러그 (slug), 날짜, 카테고리를 포함한 모든 포스트와 페이지 목록 작성
  2. 활발하게 트래픽이 발생하는 콘텐츠와 오래된(stale) 콘텐츠 구분
  3. 수동 작업이 필요한 임베디드 쇼트코드 (shortcode)가 포함된 포스트 표시

결과물은 약 30초 만에 깔끔한 인벤토리(inventory) 형태로 나왔습니다. 규모가 큰 사이트라면 이것만으로도 몇 시간을 절약할 수 있습니다.

사용된 프롬프트 (Prompt):

여기 WordPress XML 내보내기 파일이 있습니다. 다음을 제공해 주세요:
1. 모든 포스트의 테이블: 제목, 슬러그 (slug), 발행 날짜, 카테고리, 단어 수
2. 콘텐츠 전체에서 사용된 모든 쇼트코드 (shortcode) 목록
...

2단계 — 콘텐츠를 마크다운 (Markdown)으로 변환

WordPress는 콘텐츠를 쇼트코드가 섞인 HTML 형태로 저장합니다. 반면 Astro는 프론트매터 (frontmatter)가 포함된 마크다운 (Markdown)을 원합니다. Claude는 이 변환 작업의 대부분을 자동으로 처리했습니다.

콘텐츠 변환을 위한 프롬프트:

이 WordPress 포스트 HTML을 Astro 프론트매터 (frontmatter)가 포함된 마크다운 (Markdown)으로 변환하세요.
모든 헤딩 (heading), 링크, 이미지, 포맷팅을 유지하세요.
프론트매터 (frontmatter)에는 다음을 포함하여 출력하세요: title, description, pubDate, slug, tags.
...

포스트의 80%는 결과물이 깔끔하여 바로 사용할 수 있었습니다. 나머지 20%에는 다음과 같은 항목이 있었습니다:

  • 연락처 양식 쇼트코드 ([contact-form-7]) — 교체 필요
  • 갤러리 쇼트코드 ([gallery ids="..."]) — 수동 재구축 필요
  • 플러그인 전용 쇼트코드 — 플러그인마다 다름

쇼트코드 문제는 대부분의 WordPress 마이그레이션이 막히는 지점입니다. 양식 교체에 관한 자세한 내용은 아래에서 다룹니다.

3단계 — Cloudflare Pages에 Astro 설정

npm create astro@latest my-site
cd my-site
npx astro add cloudflare

Cloudflare 어댑터 (adapter)가 Pages를 위한 빌드 출력 형식을 처리합니다. 그 후, GitHub 리포지토리 (repo)를 Cloudflare Pages에 연결하면 푸시(push)할 때마다 배포됩니다.

기본 astro.config.mjs:

import { defineConfig } from 'astro/config'
import cloudflare from '@astrojs/cloudflare'

...

순수 정적 사이트 (static site)의 경우, output: 'static' 설정을 사용하면 됩니다. 서버 사이드 렌더링 (SSR)도 없고, 콜드 스타트 (cold start)도 없으며, 엣지 (edge)에서 순수 HTML만 제공됩니다.

4단계 — 콘텐츠 및 에셋 (assets) 마이그레이션

저는 Claude에게 다음과 같은 기능을 수행하는 마이그레이션 스크립트를 생성해 달라고 요청했습니다:

  1. WordPress XML 내보내기(export) 파일 읽기
  2. 적절한 프론트매터 (frontmatter)를 포함한 각 포스트별 개별 .md 파일 생성
  3. 미디어 파일을 깔끔한 슬러그 (slug) 기반 컨벤션으로 이름 변경
  4. 콘텐츠 내의 내부 이미지 참조 업데이트
// Claude가 생성한 마이그레이션 스크립트 (단순화 버전)
import { parseStringPromise } from 'xml2js'
import { writeFileSync, mkdirSync } from 'fs'
...

미디어의 경우, 파일들을 Cloudflare Pages의 public 폴더에 유지하고 Markdown 파일 내의 참조를 업데이트했습니다. 미디어가 많은 대규모 사이트라면 R2를 검토해 볼 가치가 있지만, 대부분의 기업 페이지나 랜딩 페이지의 경우 Pages에서 에셋 (assets)을 직접 서빙하는 것만으로도 충분합니다. Claude는 URL 재작성 (rewriting)을 위한 찾기 및 바꾸기 (find-and-replace) 스크립트를 생성해 주었습니다.

단계 5 — 폼 (forms) 문제

이 지점은 모든 WordPress-to-static 마이그레이션이 동일한 벽에 부딪히는 구간입니다.

Contact Form 7, Gravity Forms, WPForms — 이들은 모두 서버에서 실행되는 PHP에 의존합니다. 정적 (static) 사이트로 이동하면 이들은 완전히 작동을 멈춥니다. 제출을 처리할 서버가 없기 때문입니다.

제가 검토한 옵션들은 다음과 같습니다:

Cloudflare Worker 작성 — 가능하지만, 본질적으로 연락처 폼에 불과한 것에 대해 이제 백엔드 (backend)를 유지 관리해야 합니다. 이메일 전송, 유효성 검사 (validation), 스팸 방지 등을 연결해야 합니다. 제가 원했던 것보다 더 많은 가동 부품 (moving parts)이 필요합니다.

폼 백엔드 서비스 사용 — 폼에 엔드포인트 (endpoint) 하나만 넣으면 서비스가 모든 것을 처리합니다. 서버도 필요 없고 유지 관리도 필요 없습니다.

저는 FormRoute를 선택했습니다. Contact Form 7에서의 마이그레이션은 간단했습니다:

이전 (Contact Form 7 쇼트코드 (shortcode)):

[contact-form-7 id="123" title="Contact form"]

이후 (Astro 컴포넌트 (component)):

---
// src/components/ContactForm.astro
---
...

스팸 방지는 실제 사용자에게는 보이지 않는 Cloudflare Turnstile을 통해 실행됩니다. 제출된 내용은 FormRoute 대시보드로 전송되며 이메일 알림을 트리거합니다. 무료 티어는 한 달에 1,000건의 제출을 지원합니다.

단계 6 — 리다이렉트 (Redirects)

WordPress URL은 정적 사이트(Static site)에서 원하는 형태와 항상 일치하지는 않습니다. SEO를 잃거나 기존 링크가 깨지는 것을 방지하려면 이전 URL을 새 URL로 리다이렉트(Redirect)해야 합니다.

Cloudflare Pages는 public 폴더 내의 _redirects 파일을 통해 리다이렉트를 처리합니다:

/old-post-url/ /new-post-url/ 301
/category/news/ /blog/ 301
/?p=123 /post-slug/ 301

저는 Claude에게 이전 URL 목록과 새로운 슬러그(Slug) 목록을 제공하고 리다이렉트 파일을 생성해 달라고 요청했습니다. Claude는 한 번의 작업으로 매핑(Mapping)을 처리했습니다.

?p=123 스타일의 URL을 사용하는 WordPress 사이트의 경우, 패턴은 다음과 같습니다:

/?p=:id /blog/:slug 301

각 ID를 해당 슬러그로 수동으로 또는 스크립트를 통해 매핑해야 합니다. Claude는 XML 내보내기(Export) 파일을 바탕으로 해당 스크립트를 생성할 수 있습니다.

무엇이 망가졌는가 (솔직한 목록)

댓글 (Comments) — WordPress 댓글에는 정적 사이트용 상응 기능이 없습니다. 저는 댓글을 아예 없애버렸습니다. 만약 댓글이 사이트에 중요하다면, Giscus (GitHub Discussions 기반)를 살펴보거나 그냥 삭제하십시오.

검색 (Search) — WordPress 검색은 서버 측(Server-side)에서 작동합니다. 정적 사이트는 클라이언트 측(Client-side) 검색이 필요합니다. Pagefind는 Astro와 잘 작동하며 설정하는 데 10분 정도 걸립니다.

WooCommerce — 만약 WordPress 사이트에 이커머스(Ecommerce) 기능이 있다면, 이 마이그레이션 경로는 적용되지 않습니다. WooCommerce는 서버가 필요합니다. 대안으로는 정적 사이트 + Shopify Buy Button을 사용하거나 헤드리스(Headless) 접근 방식을 사용하는 것이 있습니다.

일부 SEO 플러그인 — Yoast SEO 데이터는 WordPress 메타(Meta)에 저장됩니다. XML 내보내기에 이 데이터가 포함되어 있지만, Astro의 프론트매터(Frontmatter)로 수동 매핑해야 합니다. Claude가 매핑 스크립트를 생성할 수 있지만 약간의 정리 작업이 필요합니다.

플러그인 전용 쇼트코드 (Shortcodes) — 콘텐츠가 아닌 플러그인 요소(카운트다운 타이머, 예약 위젯, 대화형 지도 등)는 교체가 필요합니다. 이에 대한 보편적인 정답은 없으며, 해당 플러그인이 어떤 기능을 수행했느냐에 따라 달라집니다.

결과

  • 빌드 시간 (Build time): 10초 미만
  • 첫 바이트 도달 시간 (Time to first byte): 전 세계적으로 50ms 미만 (Cloudflare edge)
  • Lighthouse 점수: 전 항목 98–100
  • 호스팅 비용: $0 (Cloudflare Pages 무료 티어)
  • 유지보수: PHP 제로, 플러그인 업데이트 제로, 서버 패치 제로

AI의 도움을 받은 이번 마이그레이션은 중간 규모의 사이트(포스트 80개, 페이지 20개) 기준으로 실제 작업 시간 약 하루가 소요되었습니다. AI가 없었다면 동일한 작업에 일주일이 걸렸을 것입니다. 콘텐츠 변환 (Content conversion)과 스크립트 생성 (Script generation)이 가장 큰 시간 절약 요소였습니다.

요약 — AI가 도움을 준 부분

작업AI 미사용 시 시간AI 사용 시 시간
콘텐츠 인벤토리 (Content inventory)2–3시간10분
...

AI가 도움을 줄 수 없었던 부분: 무엇을 남기고 무엇을 삭제할지, 그리고 플러그인 특화 기능 (Plugin-specific functionality)을 어떻게 처리할지에 대한 판단. 그 부분은 여전히 사용자의 몫입니다.

리소스

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0