지난 글에서는 제게 맞는 Quartz 블로그 아키텍처를 찾기 위해 여러 방식을 비교해 봤습니다.

지난 글 요약

  1. 호스팅: Cloudflare Pages (Private 리포지토리 무료 지원, 빠른 CDN)

  2. 리포지토리: 1-Repo (Private) (관리가 단순하고 콘텐츠 비공개)

  3. 배포 트리거: Synology Cron (시놀로지 작업 스케줄러로 10분마다 git push)

  4. 최종 아키텍처: Synology (Cron) + Private 1-Repo (GitHub) + Cloudflare Pages

이번 글에서는 이 아키텍처를 실제로 구축하는 전체 과정을 단계별로 기록해 보려고 합니다.

1. 🐙 GitHub 리포지토리 준비

먼저 GitHub에서 2개의 리포지토리를 생성해야 합니다.

“분명 1-Repo(1개 리포지토리)로 관리한다고 했는데 왜 2개를 생성하나요?” 하실 수 있어요.

Quartz 자체에는 댓글 기능이 없습니다. 그래서 오픈소스 댓글 시스템인 Giscus를 추가하려고 하는데, 이 Giscus가 댓글 데이터를 저장할 별도의 (공개) 리포지토리를 필요로 하기 때문입니다.

  1. my-quartz-blog (Private):

    • 핵심 리포지토리입니다. Quartz 소스코드와 제 Obsidian 콘텐츠(.md 파일)가 모두 이곳에 저장됩니다.

    • Private(비공개) 으로 설정해서 제 글이 외부에 노출되지 않도록 합니다.

  2. my-giscus-comments (Public):

    1. 댓글 기능인 Giscus를 연동하기 위한 리포지토리입니다.

      • GiscusGitHub Discussions 기능을 사용하기 때문에, 리포지토리는 반드시 Public(공개) 으로 설정해야 하고, Discussions 기능을 활성화해야 합니다.
    2. Giscus 앱을 해당 리포지토리에 접근 권한을 부여 하기 위해 Github에서 다음 경로로 접근하여 활성화해주세요.

      • Repository > Settings > Integrations > GitHub Apps > giscus > Configure

      • Repository access 영역에서 Only select repository를 선택

        • 방금 생성한 public repo my-giscus-comments를 선택해주세요.

2. 💻 PC에서 Quartz 프로젝트 초기화 및 Push

이제 제 PC에서 Quartz 공식 코드를 가져와서, 방금 만든 my-quartz-blog (Private) 리포지토리로 Push해줘야 합니다.

  1. PC의 작업 폴더(예: C:\Projects)로 이동합니다.

  2. Quartz 공식 리포지토리git clone 받습니다.

    git clone https://github.com/jackyzha0/quartz.git
  3. 다운로드한 폴더(my-quartz-blog)로 이동한 뒤, 기존 Git 기록을 삭제합니다. (공식 리포지토리의 연결을 끊고 제 리포지토리에 새로 연결하기 위함입니다.)

    cd my-quartz-blog
    rmdir .git  # Windows
    # rm -rf .git      # macOS / Linux
  4. 이 폴더를 새로운 Git 리포지토리로 초기화합니다.

    git init
  5. Git 사용자 이름과 이메일을 설정합니다. (GitHub 계정과 동일하게)

    git config user.name "Your-GitHub-Username"
    git config user.email "your-github-email@example.com"
  6. 방금 만든 제 Private 리포지토리(my-quartz-blog)를 원격(origin)으로 연결합니다.

    • [Your_GitHub_ID] 부분은 실제 GitHub ID로 변경해주세요.

    git remote add origin git@github.com:[Your_GitHub_ID]/my-quartz-blog.git
  7. 모든 파일을 스테이징하고 첫 커밋을이 data-repo, data-repo-id 등이 포함된 설정값을 알려줍니다.

    <script src="[https://giscus.app/client.js] https://giscus.app/client.js)"
        data-repo="[ENTER REPO HERE]"
        data-repo-id="[ENTER REPO ID HERE]"
        data-category="[ENTER CATEGORY NAME HERE]"
        data-category-id="[ENTER CATEGORY ID HERE]"
        data-mapping="pathname"
        data-strict="0"
        data-reactions-enabled="1"
        data-emit-metadata="0"
        data-input-position="bottom"
        data-theme="preferred_color_scheme"
        data-lang="ko"
        crossorigin="anonymous"
        async>
    </script>
  8. PC에서 VS Code 같은 IDE(편집기)로 my-quartz-blog를 엽니다.

  9. quartz.layout.ts을 찾아 엽니다.

  10. Component.Footer()가 있는 afterBody 배열에, Giscus 컴포넌트 설정을 추가합니다. 7번에서 알려준 값들을 아래 options에 맞게 넣어주세요.

    // quartz.layout.ts
     
    export const defaultContentPageLayout: PageLayout = {
      beforeBody: [
        Component.Breadcrumbs(),
        Component.ArticleTitle(),
        Component.ContentMeta(),
        Component.TagList(),
      ],
      left: [
        Component.PageTitle(),
        Component.MobileOnly(Component.Spacer()),
        Component.Search(),
        Component.Darkmode(),
        Component.DesktopOnly(Component.Explorer()),
      ],
      right: [
        Component.Graph(),
        Component.DesktopOnly(Component.TableOfContents()),
        Component.Backlinks(),
      ],
      // afterBody에 Giscus 컴포넌트 추가
      afterBody: [
        Component.Spacer(),
        Component.Comments({
          provider: 'giscus',
          options: {
            // 2단계에서 Giscus 사이트에서 받은 값들
            repo: '[Your_GitHub_ID]/my-giscus-comments', // data-repo
            repoId: 'R_kgDOXXXXXX', // data-repo-id
            category: 'Announcements', // data-category
            categoryId: 'DIC_kwDOXXXXXX', // data-category-id
          }
        }),
        Component.Footer(), // Footer는 Giscus 뒤로
      ],
    }
  11. 수정이 완료되면 변경 사항을 다시 GitHub에 Push 합니다.

    git add .
    git commit -m "Add Giscus comments feature"
    git push origin main

4. ☁️ Cloudflare Pages 배포

이제 Giscus까지 적용한 나만의 Quartz를 세상에 보여줄 차례입니다.

  1. Cloudflare Pages 대시보드로 이동하여 Workers 및 Pages로 접근합니다.

    • 메뉴 > 컴퓨팅 및 AI > Workers 및 Pages
  2. GitHub 계정을 연결하고, my-quartz-blog (Private) 리포지토리를 선택합니다.

    • 이때 Cloudflare가 Private 리포지토리에 접근할 수 있도록 권한을 승인해 줘야 합니다.
  3. 빌드 설정을 구성합니다.

    • Project name: 원하는 주소 (예: my-blog)

    • Production branch: main

    • Framework preset: None

    • Build command: npx quartz build

    • Build output directory: public

    • (중요) Environment variables: NODE_VERSION = 22

  4. ‘저장 및 배포’ 버튼을 클릭합니다.

몇 분 정도 기다리면 CloudflareGitHub에서 코드를 가져와 빌드하고, my-blog.pages.dev라는 주소로 블로그를 멋지게 배포해 줍니다. 1-Repo 방식이라 Submodule 설정 같은 복잡한 과정 없이 정말 간단하게 끝났습니다.

5. 🗄️ Synology NAS 자동 동기화 설정 (Cron)

가장 핵심적인 단계입니다. 제가 Obsidian에서 글을 쓰면, 시놀로지 NAS가 10분마다 이 변경 여부를 감지해 GitHub 리포지토리로 자동 git push 하도록 설정할 겁니다.

5-1. 필수 패키지 설치

  • 시놀로지 패키지 센터에서 Git Server 를 설치합니다.

    • NAS에서 Git 명령어를 사용하기 위해 필요합니다.

5-2. NAS용 SSH 배포 키 생성

NAS가 GitHub Private 리포지토리에 암호 없이 git push를 하려면 SSH 키 인증이 필요합니다.

  1. NAS에 SSH 접속

    • 제어판 > 터미널 및 SNMP > SSH 서비스 활성화 체크

    • 터미널에서 NAS 관리자 계정으로 SSH 접속

    ssh [NAS_Admin_ID]@[NAS_IP]
  2. user계정으로 접근 후 root로 전환 및 키 생성

    # root로 전환하기 위한 관리자 암호 입력
    sudo -i
    # SSH 키 생성
    ssh-keygen -t rsa -b 4096 -C "quartz-deploy"
    # Enter 3번 눌러 암호 없이 기본 경로 `/root/.ssh/id_rsa`에 생성
  3. 공개 키 확인 및 복사

    cat /root/.ssh/id_rsa.pub
    • ssh-rsa AAAA...로 시작하는 긴 키 문자열 전체를 복사합니다.

5-3. GitHub에 배포 키 등록

  • GitHub의 my-quartz-blog (Private) 리포지토리로 이동합니다.

  • Settings > Deploy Keys > Add deploy key 클릭

    • Title: Synology NAS (구분하기 쉬운 이름)

    • Key: (5-2-3에서 복사한 ssh-rsa... 공개 키 붙여넣기)

    • ✅ Allow write access (쓰기 권한 허용): 반드시 체크해야 합니다. (git push에 필요)

5-4. NAS에 리포지토리 클론

이제 NAS의 SSH 터미널(root 상태)에서, Obsidian 볼트를 저장할 위치로 이동해 Private 리포지토리를 클론합니다.

  • (중요!) git clone 시 반드시 SSH 주소를 사용해야 배포 키가 작동합니다.

  • 경로는 home/{user_ID}와 동일한 /volume1/homes/[Your_User_ID] 입니다.

# [Your_User_ID]는 실제 사용자 ID로 변경
cd /volume1/homes/[Your_User_ID] 
 
# [Your_GitHub_ID]는 GitHub ID로 변경
# "Obsidian_Quartz"라는 이름의 폴더로 클론됩니다.
git clone git@github.com:[Your_GitHub_ID]/my-quartz-blog.git Obsidian_Quartz

5-5. Obsidian 볼트 연결

  • 이제 /volume1/homes/[Your_User_ID]/Obsidian_Quartz 폴더가 생겼습니다.

  • PC나 모바일의 Obsidian 앱에서 리포지토리 폴더 안의 content 폴더 (.../Obsidian_Quartz/content)를 볼트로 열어줍니다.

    • 이 폴더는 Synology Drive 등으로 동기화되어 있어야겠죠?

5-6. 자동 동기화 스크립트 생성

NAS의 root 홈 디렉터리에 자동 실행될 셸 스크립트를 생성합니다.

  • vi /root/quartz_sync.sh (vi 편집기 열기)

  • i를 눌러 입력 모드로 변경 후, 아래 스크립트 내용을 붙여넣습니다.

    • (주의!) [Your_User_ID] 부분은 실제 사용자 ID로 꼭 변경해주세요.
#!/bin/bash
set -ex  # -e: 오류 시 즉시 중단, -x: 디버그 모드
 
cd /volume1/homes/[Your_User_ID]/Obsidian_Quartz || exit 1
echo "현재 위치: $(pwd)"
echo "Git 상태 확인 중..."
git status -s content
 
# 변경 사항이 없으면 종료
if [[ -z $(git status -s content) ]]; then
  echo "변경 사항 없음 → 종료"
  exit 0
fi
 
echo "변경 사항 발견 → 동기화 시작"
 
# pull을 하기 전에 로컬 변경 사항을 먼저 add/commit 합니다.
/usr/bin/git add content/
 
# 커밋 메시지: 일시
/usr/bin/git commit -m "Auto-sync: $(date +'%Y-%m-%d %H:%M:%S')" || true
 
# 로컬 커밋 이후에 pull --rebase를 실행합니다.
# 이렇게 하면 원격 변경 사항을 먼저 받고, 그 위에 방금 만든 로컬 커밋을 올립니다.
/usr/bin/git pull --rebase origin main
 
# 마지막으로 원격 저장소에 푸시합니다.
/usr/bin/git push origin main
echo "완료"
  • ESC 키 누르고 :wq 입력 후 Enter (저장 및 종료)

  • 스크립트에 실행 권한 부여:

    • chmod +x /root/quartz_sync.sh

5-7. 시놀로지 작업 스케줄러 등록 (Cron 설정)

이것이 바로 Watcher를 대체하는 안정적인 Cron 설정입니다.

  1. NAS 제어판 > 작업 스케줄러로 이동합니다.

  2. 생성 > 예약된 작업 > 사용자 정의 스크립트 클릭

    • [일반] 탭:

      • 작업: Quartz 자동 배포 (원하는 이름)

      • 사용자: root (필수! root 권한으로 실행)

    • [스케줄] 탭:

      • 다음 날짜에 실행: 매일

      • 주기: 매 10분 (또는 원하는 간격)

    • [작업 설정] 탭:

      • 사용자 정의 스크립트: bash /root/quartz_sync.sh
    • 확인을 눌러 저장합니다.

6. ✍️ 최종 워크플로우 확인

모든 설정이 완료되었습니다. 이제 저의 블로깅 워크플로우는 완벽하게 자동화되었습니다.

  1. PC나 모바일의 Obsidian 앱에서 글을 작성하고 저장합니다.

    • 이 볼트는 Synology Drive를 통해 NAS의 .../Obsidian_Quartz/content 폴더와 실시간 동기화됩니다.
  2. NAS의 Obsidian_Quartz 폴더에 파일 변경이 감지됩니다.

  3. 최대 10분 이내에 ‘작업 스케줄러(Cron)‘가 quartz_sync.sh 스크립트를 실행합니다.

  4. 스크립트가 content 폴더의 변경 사항을 감지하고, Private GitHub 리포지토리(my-quartz-blog)로 git push를 실행합니다.

  5. Cloudflare Pages가 이 push 이벤트를 즉시 감지합니다.

  6. Cloudflare가 자동으로 npx quartz build를 실행하여 사이트를 새로 빌드하고, 배포합니다.

graph RL
    subgraph "글 작성"
        A["Obsidian (PC/모바일)<br>글 작성 및 저장"]
    end

    subgraph "Synology NAS"
        B("Synology Drive<br>실시간 동기화")
        C["NAS 로컬 리포지토리<br>.../Obsidian_Quartz/content"]
        D("작업 스케줄러 (Cron)<br>10분마다 스크립트 실행")
        E{"변경 사항 감지<br>(quartz_sync.sh)"}
    end

    subgraph "Cloudflare"
        F["Private GitHub Repo<br>my-quartz-blog"]
        G("Cloudflare Pages<br>Push 감지 및 자동 빌드")
        H[("🌎<br>최종 블로그 배포")]
    end

    %% 워크플로우 연결
    A --> B
    B --> C
    D --> E
    C -. "파일 변경" .-> E
    E -- "변경 사항 O" --> F(git push)
    E -- "변경 사항 X" --> I["종료"]
    F --> G("Push 트리거")
    G --> H

이제 Obsidian에서 글을 저장하는 것 외에는 아무것도 신경 쓸 필요가 없어졌습니다. 앞으로 성장 일기를 하나 하나 작성하려고 합니다. 많은 조언 부탁드립니다!

감사합니다