Obsidian × Enveloppe → Quartz 4 → Cloudflare Pages

한 개 Vault로 개인/공개 분리 + 핫키 한 번 배포 (최종 가이드)

목표

  • 하나의 Obsidian Vault에서 private/(비공개)와 public-posts/(공개) 동시 운용
  • Enveloppe 플러그인으로 공개 글만 GitHub 레포의 **/content**로 업로드
  • Cloudflare Pages가 push를 받아 quartz build 실행 → 자동 배포
  • Obsidian 안에서 핫키 한 번으로 끝

0) 준비물

  • macOS + 터미널(zsh), Git
  • Node.js 20+ (로컬 미리보기/개발용)
  • GitHub 레포 1개 (예: Seungyeup/tech-blog)
  • Cloudflare 계정(무료) + Pages 프로젝트
    • Build command: npx quartz build
    • Build output directory: public
  • 레포 루트에 Quartz v4 초기화 완료(폴더/파일 존재 확인)
    • content/, quartz.config.ts, package.json

1) Vault 설계 (iCloud Drive 공유 권장)

기기간 동기화를 위해 iCloud Drive 하위에 Vault 생성:

~/Library/Mobile Documents/com~apple~CloudDocs/ObsidianVault/
├─ private/         # 비공개(절대 퍼블리시 X)
├─ public-posts/    # 블로그 공개 대상(이 폴더만 퍼블리시)
└─ templates/       # 템플릿(선택)

블로그 템플릿 예시templates/blog_post.md

---
title: "<제목>"
date: {{date:YYYY-MM-DD}}
tags: [tech]
draft: false
share: true   # ← Enveloppe 퍼블리시 플래그
---
 
# {{title}}
 
<본문>

규칙: 블로그로 공개할 글만 public-posts/에 두고, **각 글 frontmatter에 share: true**를 둔다.
초안은 draft: true 또는 public-posts/draft/ 하위에 두어 배포 제외.


2) Quartz 4 설치 & 초기화 (요약)

최초 1회만 수행

# 작업 폴더 예: ~/dev
cd ~/dev
 
# 1) Quartz 템플릿 클론
git clone https://github.com/jackyzha0/quartz.git tech-blog
cd tech-blog
 
# 2) 의존성 설치
npm i
 
# 3) 초기화 마법사(사이트 타이틀 등)
npx quartz create
 
# 4) 로컬 미리보기
npm run dev   # http://localhost:8080

GitHub 원격 연결 & 첫 푸시

git remote remove origin 2>/dev/null || true
git remote add origin https://github.com/<YOUR_ID>/<YOUR_REPO>.git
git add .
git commit -m "feat: init Quartz 4 blog"
git push -u origin main

Quartz 기본 동작: content/(입력) → public/(출력)


3) Cloudflare Pages 연결(무료)

Pages 프로젝트 생성 → Connect to Gittech-blog 레포 선택 → Build 설정:

  • Build command: npx quartz build
  • Build output directory: public
  • Branch: main

저장하면 자동 배포가 시작되며, https://<project>.pages.dev 주소가 발급된다.
(원하면 커스텀 도메인 연결)


4) Enveloppe 플러그인 설치/설정

4-1) 설치

  • Obsidian → Settings → Community plugins → Browse → “Enveloppe” 검색 → 설치/활성화
    (만약 검색이 안 뜨면 BRAT로 Enveloppe/obsidian-enveloppe 추가 설치)

4-2) GitHub 토큰

  • GitHub → Settings → Developer settings → Personal access tokens (classic)
  • repo 권한으로 PAT 생성 → Enveloppe 설정에 붙여넣기

4-3) 핵심 설정값

  • GitHub

    • Username: <YOUR_ID>
    • Repository: tech-blog
    • Branch: main
    • Token: (위에서 만든 PAT)
  • Upload(대상 경로 지정)

    • Folder reception settings:
      • 권장: Obsidian Path
      • 대안: Fixed folder
    • Default folder: content
    • (권장) Obsidian Path + Regex 치환
      • Regex (Folder path 치환): ^public-posts/ → “(빈 값)
      • 효과: public-posts/kafka/intro.mdcontent/kafka/intro.md 로 업로드
    • (대안) Fixed folder
      • 항상 content/ 바로 아래로 평평하게 업로드
  • Publish 조건

    • 해당 노트 frontmatter에 share: true 일 때만 업로드
  • Attachments & Embeds(선택)

    • 상대 경로 유지 권장
    • 필요 시 이미지 전용 업로드 경로/정규식 지정 가능
  • 동작

    • 기본은 업로드 시 PR 생성 후 자동 병합
    • 충돌 시 자동 병합이 멈출 수 있으므로 PR에서 수동 처리

위 설정으로 Vault에서는 public-posts/ 폴더로 관리하되, 레포에서는 깔끔히 content/ 루트로 정리된다.


5) Obsidian 핫키 배포

Obsidian → Settings → Hotkeys:

  • Enveloppe: Upload all notes” (또는 “Upload unpublished notes”)에 단축키 지정
    • 예: Ctrl+Cmd+P

배포 흐름

  1. public-posts/에 글 작성(각 글에 share: true)
  2. 핫키 실행
  3. Enveloppe가 변환/업로드 → 레포에 PR 생성 및 자동 병합 → push 발생
  4. Cloudflare Pages가 npx quartz build 실행 → public/ 산출 → 자동 배포

6) “대상 경로 지정” 요약 (Enveloppe 핵심 팁)

  • 가장 단순:

    • Reception = Fixed folder, Default folder = content
    • → 모든 글이 repo/content/ 바로 아래로
  • 폴더 구조 보존(추천):

    • Reception = Obsidian Path, Default folder = content
    • Regex 치환 ^public-posts/ → “(빈 값)
    • public-posts/<subdirs>/<file>.mdcontent/<subdirs>/<file>.md
  • 글 단위 오버라이드: 각 글 frontmatter에

    path: content/blog
    • → 이 글만 repo/content/blog/로 강제 업로드
    • path는 레포 루트 기준. 빈 값//면 레포 루트로 감

7) “최근 작성 글” 섹션(Quartz)

  • Quartz 레이아웃(quartz.layout.ts)에 Recent Notes 블록을 배치(템플릿 버전에 맞춰 추가)
  • 각 글 frontmatterdate: YYYY-MM-DD를 넣으면 최신순 정렬에 반영
  • 로컬 미리보기:
    npx quartz build --serve
    # http://localhost:8080

8) 트러블슈팅 (빠른 진단)

  • Cloudflare: “Missing script: build” 에러
    • Build command를 npx quartz build, Output을 public 으로 설정
  • 업로드했는데 글이 안 보임
    • 해당 노트 share: true 여부 확인
    • 레포 /content 경로에 파일이 실제 생성됐는지 확인
    • draft: true거나 public-posts/draft/ 하위면 제외되도록 설정했는지 점검
  • PR이 자동 병합되지 않음
    • 충돌 발생 가능 → 레포에서 수동 병합
    • 필요 시 Enveloppe 설정에서 자동 병합 비활성화 후 수동 운영
  • 이미지 경로 깨짐
    • Vault에 public-posts/img/...로 두고, 본문에서는 ![](./img/xxx.png) 같은 상대 경로 사용
  • 대상 경로가 이상함
    • Upload의 Reception/Default folder/Regex 치환을 다시 확인
    • 단순하게 한 위치만 원하면 Reception을 Fixed folder + content

9) 선택 옵션(운영 고도화)

  • 폴더별 라우팅: public-posts/blog/content/blog/, public-posts/notes/content/notes/
  • 커밋 메시지 템플릿: “publish: {{fileName}} at {{date}}”
  • 초안 필터: draft: true인 글은 업로드 제외
  • Failure 알림: PR 실패/충돌 시 GitHub 알림, Cloudflare 빌드 실패 알림 활용

10) 최종 워크플로 (요약)

  1. Obsidian에서 작성
    • 비공개: private/
    • 공개: public-posts/ + 각 글에 share: true
  2. 핫키(Enveloppe Upload …) → GitHub에 /content로 업로드(자동 PR/병합)
  3. Cloudflare Pages: npx quartz buildpublic/ → 배포
  4. Quartz 홈: 최근 글 목록 자동 반영

체크리스트

  • Vault: private/, public-posts/, templates/
  • 템플릿에 share: true 기본 포함
  • Enveloppe → Upload:
    • Reception = Obsidian Path, Default folder = content
    • Regex: ^public-posts/ → “(빈 값) (권장)
    • (대안) Fixed folder = content
  • Hotkeys: “Enveloppe: Upload all notes” → Ctrl+Cmd+P
  • Cloudflare Pages: Build = npx quartz build, Output = public
  • 각 글 frontmatter: title, date, tags, draft, share

부록: 자주 쓰는 명령 모음

# 로컬 미리보기(Quartz)
npx quartz build --serve
 
# Node/NPM 버전 확인
node -v
npm -v
 
# GitHub 원격 설정 확인
git remote -v

이제 Obsidian에서 글을 쓰고 핫키만 누르면, GitHub → Cloudflare Pages까지 완전 자동으로 배포됩니다.
중복 작성 없이 싱글 소스 → 멀티 퍼블리시 파이프라인 완성! 🚀