6.1 스타터 웹사이트 세팅
이번 실습에서는 콘텐츠 사업부가 사용할 웹사이트를 내 GitHub 계정으로 가져오고, 로컬 개발 서버와 Vercel 운영 서버에 글을 차례로 발행합니다. 웹사이트를 처음부터 만드는 대신 이미 준비된 스타터를 사용해 이후의 콘텐츠 제작과 자동 발행 실습에 집중합니다.
완료 기준
- 내 GitHub 계정에
magma-content-site저장소가 있습니다. - 개발 서버의 블로그에서 로컬 테스트 글이 보입니다.
- Vercel 운영 주소에서 GitHub에 저장된 테스트 글이 보입니다.
- 개발 발행 응답은
mode: "local", 운영 발행 응답은mode: "github"입니다.
준비물
- GitHub 계정
- GitHub 계정으로 가입한 Vercel 계정
- Node.js 20 이상
- 로컬 PC 또는 Hermes가 설치된 원격 Linux 서버
터미널에서 버전을 확인합니다.
node -v
npm -v
git --version
Node.js가 v20보다 낮으면 최신 LTS를 설치한 뒤 계속합니다.
1. 스타터 저장소를 내 계정으로 가져오기
브라우저에서 MAGMA 스타터 저장소를 엽니다.
- 오른쪽 위의 Fork를 누릅니다.
- Owner가 내 GitHub 계정인지 확인합니다.
- Create fork를 누릅니다.
완료되면 주소가 https://github.com/내계정/magma-content-site 형태로 바뀝니다. 원본과 연결되지 않은 독립 저장소가 필요하다면 Use this template → Create a new repository를 사용해도 됩니다.
2. 저장소를 내려받고 개발 서버 열기
Hermes에게 요청하기
내계정을 실제 GitHub 계정명으로 바꿔 Hermes 세션에 입력합니다.
내 저장소 https://github.com/내계정/magma-content-site.git을 작업 폴더에 clone해 줘.
프로젝트 폴더에 package.json과 package-lock.json이 있는지 확인하고 npm ci로 패키지를 설치해.
설치가 끝나면 npm run dev -- --hostname 0.0.0.0으로 개발 서버를 실행하고 접속 주소를 알려 줘.
같은 이름의 폴더가 이미 있다면 삭제하거나 덮어쓰지 말고 먼저 상태를 알려 줘.
직접 실행하기
git clone https://github.com/내계정/magma-content-site.git
cd magma-content-site
npm ci
npm run dev -- --hostname 0.0.0.0
브라우저에서 http://localhost:3000을 엽니다. MAGMA 홈 화면이 나타나면 정상입니다.
npm ci가 lockfile 오류로 중단될 때
정상 저장소에는 package-lock.json이 들어 있습니다. 다음 오류가 나오면 npm install로 바로 우회하지 말고 현재 위치와 clone 결과부터 확인합니다.
The npm ci command can only install with an existing package-lock.json
pwd
ls -la
ls package.json package-lock.json
git remote -v
package.json과 package-lock.json이 없다면 저장소가 아닌 폴더에 들어온 것입니다. 불완전한 폴더는 백업 이름으로 옮긴 뒤 다시 clone합니다.
cd ..
mv magma-content-site "magma-content-site.stale-$(date +%Y%m%d-%H%M%S)"
git clone https://github.com/내계정/magma-content-site.git
cd magma-content-site
npm ci
3. 원격 서버에서 개발하는 경우
로컬 PC에서 실행하는 수강생은 이 절을 건너뜁니다. VPS의 localhost와 내 PC의 localhost는 서로 다른 주소입니다.
Hostinger 원클릭 Hermes
Hostinger Docker Manager에는 두 종류의 터미널이 있습니다.
- 화면 오른쪽 위 터미널: VPS 호스트입니다. Tailscale 설치와 Serve를 여기에서 실행합니다.
- Hermes Agent 프로젝트 행의 터미널: Hermes 컨테이너입니다. 저장소, npm, 개발 서버 작업을 여기에서 실행합니다.


Tailscale을 Hermes 컨테이너에 다시 설치하지 않습니다. Docker Manager의 프로젝트 Compose 화면에서 시각적 편집기를 열고 Hermes 컨테이너의 포트에 다음 값을 추가합니다.
127.0.0.1:3000:3000
컨테이너 영역의 저장을 누른 뒤 화면 위쪽의 배포를 누릅니다.

Hermes 컨테이너 터미널에서 개발 서버를 실행합니다.
su - hermes
cd /opt/data/profiles/sam/workspace/magma-content-site
npm run dev -- --hostname 0.0.0.0
프로필 이름이 sam이 아니라면 실제 프로필 경로로 바꿉니다. 개발 서버가 켜진 상태에서 VPS 호스트 터미널을 새로 열어 확인합니다.
curl -I --max-time 10 http://127.0.0.1:3000
VPS 호스트에서 Tailscale Serve 실행하기
Hostinger 또는 일반 Ubuntu VPS의 호스트 터미널에서 실행합니다.
tailscale status
tailscale ip -4
Tailscale이 없다면 Ubuntu 호스트에 한 번만 설치하고, 표시된 로그인 URL을 브라우저에서 승인합니다.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
개발 서버가 VPS의 127.0.0.1:3000에서 응답하는지 확인한 뒤 Serve를 등록합니다.
curl -I --max-time 10 http://127.0.0.1:3000
sudo tailscale serve --bg 3000
tailscale serve status
출력된 https://호스트명.테일넷.ts.net 주소를 같은 Tailnet에 로그인한 내 PC의 브라우저에서 엽니다.
Tailscale Serve는
http://localhost:3000을 내 PC에 자동 생성하지 않습니다. 내 PC의localhost:3000으로 접속해야 한다면 별도의 SSH 포워딩ssh -N -L 3000:127.0.0.1:3000 사용자@서버를 사용합니다.
4. 발행 설정 만들기
프로젝트 폴더에서 .env.example을 .env.local로 복사합니다.
Hermes에게 요청하기
magma-content-site의 .env.example을 .env.local로 복사해 줘.
openssl rand -hex 32로 발행 인증 키를 만들고 PUBLISH_API_KEY에 저장해.
비밀 값은 화면이나 응답에 출력하지 말고, 설정 여부만 알려 줘.
GITHUB_TOKEN과 GITHUB_REPO는 내가 직접 채울 수 있도록 그대로 둬.
직접 실행하기
cp .env.example .env.local
openssl rand -hex 32
생성된 문자열을 .env.local의 PUBLISH_API_KEY에 저장합니다.
PUBLISH_API_KEY=생성한_긴_문자열
GITHUB_TOKEN=발급한_GitHub_토큰
GITHUB_REPO=내계정/magma-content-site
GitHub 토큰 발급하기
GitHub에서 Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token으로 이동합니다.
- Repository access에서 내
magma-content-site만 선택합니다. - Repository permissions의 Contents를 Read and write로 바꿉니다.
- 토큰을 생성해
GITHUB_TOKEN에 저장합니다.
토큰은 비밀번호와 같습니다. 채팅, 강의 화면, Git 커밋에 노출하지 않습니다. .env.local은 Git에 커밋하면 안 됩니다.
현재 스타터는 개발 서버에서 GITHUB_TOKEN과 GITHUB_REPO가 채워져 있어도 로컬 파일로 발행합니다. 운영 서버에서 같은 설정을 읽으면 GitHub 발행으로 자동 전환됩니다.
5. Vercel에 운영 사이트 배포하기
Vercel에 GitHub 계정으로 로그인합니다.
- Add New → Project를 누릅니다.

- 내
magma-content-site저장소를 찾아 Import를 누릅니다.

- Environment Variables에 다음 값을 등록합니다.
| 이름 | 값 |
|---|---|
PUBLISH_API_KEY | 로컬과 같은 발행 인증 키 |
GITHUB_TOKEN | Contents가 Read and write인 토큰 |
GITHUB_REPO | 내계정/magma-content-site |

- Deploy를 누릅니다.

GITHUB_REPO에 원본 저장소인 dandacompany/magma-content-site를 넣지 않도록 주의합니다. 배포가 끝나면 https://내프로젝트.vercel.app 주소에서 사이트를 확인합니다.
6. 개발 환경에 먼저 발행하기
.env.local을 개발 서버 실행 뒤에 만들었으므로 서버를 재시작해야 합니다.
Hermes에게 재시작 요청하기
방금 만든 .env.local을 읽도록 현재 개발 서버를 종료하고 다시 실행해 줘.
PUBLISH_API_KEY가 설정되어 있는지는 확인하되 값은 출력하지 마.
magma-content-site에서 npm run dev -- --hostname 0.0.0.0으로 다시 시작하고,
http://localhost:3000이 응답하는지 확인해 줘.
개발 테스트 글 발행 요청하기
내 개발 주소 http://localhost:3000의 POST /api/posts에 테스트 글을 발행해 줘.
Authorization 헤더에는 .env.local의 PUBLISH_API_KEY를 Bearer 방식으로 사용하고 값은 출력하지 마.
제목은 "개발 발행 테스트", 설명은 "로컬 세팅 확인용 글", 본문은 "개발 환경의 첫 글입니다."로 해.
브라우저에서 확인할 수 있도록 draft는 false로 지정해.
응답 코드, mode, 발행 주소를 알려 줘.
직접 호출할 때는 프로젝트 폴더에서 실행합니다.
set -a
source .env.local
set +a
curl -X POST http://localhost:3000/api/posts \
-H "Authorization: Bearer $PUBLISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"개발 발행 테스트","description":"로컬 세팅 확인용 글","content":"개발 환경의 첫 글입니다.","draft":false}'
정상 응답은 201과 mode: "local"입니다. 글 파일은 content/posts/에 생기며 http://localhost:3000/blog에서 바로 확인할 수 있습니다.
7. 운영 환경에 발행하기
개발 발행이 성공한 뒤 Vercel 주소에 같은 방식으로 발행합니다.
Hermes에게 요청하기
내 운영 주소 https://내프로젝트.vercel.app의 POST /api/posts에 테스트 글을 발행해 줘.
Authorization 헤더에는 .env.local의 PUBLISH_API_KEY를 Bearer 방식으로 사용하고 값은 출력하지 마.
제목은 "운영 발행 테스트", 설명은 "Vercel 세팅 확인용 글", 본문은 "운영 환경의 첫 글입니다."로 해.
브라우저에서 확인할 수 있도록 draft는 false로 지정해.
응답 코드, mode, 발행 주소, GitHub 커밋 주소를 알려 줘.
직접 호출하기
curl -X POST https://내프로젝트.vercel.app/api/posts \
-H "Authorization: Bearer $PUBLISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"운영 발행 테스트","description":"Vercel 세팅 확인용 글","content":"운영 환경의 첫 글입니다.","draft":false}'
정상 응답은 201, mode: "github", GitHub 커밋 주소를 포함합니다. GitHub 커밋 뒤 Vercel이 새 배포를 완료할 때까지 잠시 기다린 후 운영 사이트의 /blog에서 글을 엽니다.
8. 문제 해결
개발 발행이 mode: "github"로 나옵니다
오래된 스타터 코드를 사용하고 있을 가능성이 큽니다. 작업 내용을 커밋하거나 백업한 뒤 내 저장소가 최신 스타터 변경을 포함하는지 확인합니다. 최신 버전은 개발 환경을 항상 로컬 발행으로 처리합니다.
운영 발행이 401입니다
로컬과 Vercel의 PUBLISH_API_KEY가 같은지 확인합니다. 값을 화면에 출력하지 말고 길이 또는 설정 여부만 비교합니다. Vercel 환경변수를 바꿨다면 다시 배포합니다.
운영 발행이 GitHub 권한 오류로 실패합니다
Fine-grained token의 대상 저장소가 내 magma-content-site인지, Contents 권한이 Read and write인지 확인합니다. 권한을 바꾼 뒤 같은 발행 요청을 다시 실행합니다.
발행 응답은 성공인데 글 상세가 404입니다
- 요청의
draft가false인지 확인합니다. - 개발 서버를 최신 코드로 다시 시작합니다.
- 운영은 GitHub 커밋 뒤 Vercel 배포 완료를 기다립니다.
- 응답의 발행 경로를 임의로 바꾸지 말고 그대로 엽니다.
VPS에서만 접속할 수 없습니다
다음 경계를 순서대로 확인합니다.
# Hermes 컨테이너 또는 일반 서버
curl -I http://127.0.0.1:3000
# Hostinger VPS 호스트
curl -I http://127.0.0.1:3000
tailscale serve status
tailscale status
개발 서버는 0.0.0.0:3000에 바인딩하고, Hostinger 포트 연결은 127.0.0.1:3000:3000이어야 합니다. 사이트를 보는 PC도 같은 Tailnet에 연결되어 있어야 합니다.
마지막 점검
- 내 GitHub 계정에 스타터 저장소가 있다.
-
npm ci가 정상 저장소에서 완료됐다. -
.env.local을 만든 뒤 개발 서버를 재시작했다. - 개발 발행은
201,mode: "local"이다. - Vercel에는 세 환경변수가 등록되어 있다.
- GitHub 토큰의 Contents 권한은 Read and write다.
- 운영 발행은
201,mode: "github"이고 커밋 주소가 있다. - 개발과 운영의
/blog에서 각 테스트 글을 확인했다.
테스트가 끝나면 불필요한 글은 개발 환경의 content/posts/와 내 GitHub 저장소에서 정리합니다. 이제 다음 강의부터 이 발행 API를 콘텐츠 자동화의 출구로 사용합니다.
