블로그를 운영하다 보면 글 쓰는 것보다 올리는 과정이 더 귀찮을 때가 많다. 그래서 평소 메모하는 공간인 옵시디언에서 글을 쓰면 자동으로 블로그에 게시되는 파이프라인을 만들었다.

거창한 시스템은 아니고, 옵시디언에서 깃허브로 글을 보내면 클라우드플레어가 이를 받아 배포해주는 구조다. 무료 플랜의 소소한 제약들을 해결하면서, 최대한 신경 안 쓰고 글만 쓸 수 있는 환경을 만드는 데 집중했다.

주요 기술 스택

  • Quartz: Obsidian의 위키링크와 콜아웃을 완벽하게 지원하는 정적 사이트 generator.
  • Obsidian-Git: 로컬의 변경사항을 GitHub 저장소로 푸시하는 obsidian 플러그인.
  • Cloudflare Pages: GitHub와 연동되어 웹사이트를 호스팅하는 플랫폼.
  • GitHub Actions: 배포 주기와 빌드 환경을 제어하는 자동화 도구.

필수 설정 가이드

필수로 설정해야하는 부분들만 작성했다.

A. Quartz 설치 및 저장소 구성

  1. Quartz 공식 문서의 Get Started를 참고하여 설치한다.
  2. 설치 후 생성되는 content 폴더가 Obsidian 볼트가 된다.

B. Obsidian 및 Git 설정

  1. Obsidian을 동기화할 Github repository를 하나 만든다. (문서 전체가 올라가므로 Private 권장)
  2. 로컬의 Quartz 전체 프로젝트를 방금 만든 Repo에 푸시한다.
  3. Obsidian의 커스텀 플러그인 중 Git 플러그인을 설치한다.
    • 필수 설정: Custom base path에 .. 입력
      content 폴더가 Quartz 내부 디렉토리이므로, 상위 디렉토리의 .git을 인식할 수 있도록 세팅

C. Cloudflare Pages 연동

  1. Cloudflare 관리자 페이지에서 B에서생성한 GitHub Repo를 연결한다.
  2. 필수 빌드 설정
    • 빌드 구성 > 빌드 명령: git fetch --unshallow && npx quartz build
    • 빌드 구성 > 빌드 출력: public
    • 분기제어 > 자동배포: push될 때마다 배포 하려면 사용으로 설정

배포 플랫폼 비교

여러 호스팅 서비스를 검토했으나 내 환경에는 Cloudflare Pages가 가장 적합했다.

  • GitHub Pages: 설정은 간편하지만 무료 플랜에서는 Public 저장소만 배포 가능하다. 개인적인 메모가 포함된 Obsidian 볼트를 공개 저장소에 올리는 것은 보안상 부적합했다.
  • Vercel: 배포 횟수나 속도 면에서 훌륭하지만, 무료 플랜(Hobby)은 상업적 이용을 비교적 엄격히 제한한다. 향후 블로그 수익화(광고 등) 가능성을 고려해 제외했다.
  • Cloudflare Pages: Private 저장소 배포가 무료이며 트래픽에 관대하다. 월 배포 횟수 제한(500회)이 있으나, 실시간성이 중요하지 않은 블로그 특성상 GitHub Actions로 제어하면 충분히 극복 가능하다.

최적화 가이드

블로그를 더 효율적으로 관리하고 무료 플랜의 제약을 피하기 위한 설정들이다.

1. Explicit Publish (선택적 공개)

모든 메모가 블로그에 올라가는 것을 방지하기 위해 사용한다.

  • 설정 방법: quartz.config.ts 에서 filters: [Plugin.ExplicitPublish()],로 변경
  • 사용 방법: 파일 상단(Frontmatter)에 publish: true라고 적힌 문서만 실제 웹사이트에 빌드됨

작성 중인 초안이나 개인적인 메모를 걸러낼 때 필수적이다.

2. GitHub Actions를 통한 스케줄링 배포

Cloudflare의 월 500회 배포 쿼터는 개인 블로그에 충분하다. 그러나 위에서push가 자동으로 실시되도록 설정했기 때문에, 매 push마다 빌드가 돌아가는 것은 비효율적이며, 배포되는 문서의 완성도 측면에서도 좋지 않다.

이러한 단점을 해결하기 위해 GitHub Actions를 통해 따로 배포 설정을 해주었다.

  • 설정 방법:
    1. Cloudflare 배포설정 변경: ‘분기제어 > 자동배포’를 사용 안함으로 변경
    2. GitHub Actions 추가:
      1. 매일 새벽 5시에 하루간 push 내영이 있었으면 배포하도록 설정
      2. 아래 첨부된 yaml 코드를 .github/workflow에 원하는 이름으로 저장 후 commit

Git Action 코드 전문

name: Trigger Daily Cloudflare Build
 
on:
  schedule:
    # 매일 20시(UTC 기준)에 실행 -> 한국 시간으로는 새벽 5시
    - cron: '0 20 * * *'
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Check last push time via GitHub API
        id: check_push
        run: |
          # GitHub API를 통해 저장소의 마지막 Push 시간을 가져옴 (자동 발급되는 GITHUB_TOKEN 사용)
          LAST_PUSH=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
            https://api.github.com/repos/${{ github.repository }} | jq -r .pushed_at)
          
          # 가져온 시간을 Unix Timestamp(초 단위)로 변환
          LAST_PUSH_SEC=$(date -d "$LAST_PUSH" +%s)
          NOW_SEC=$(date +%s)
          
          # 현재 시간과 마지막 푸시 시간의 차이 계산
          DIFF_SEC=$((NOW_SEC - LAST_PUSH_SEC))
          
          # 차이가 86400초(24시간) 이하일 경우에만 배포 허용
          if [ "$DIFF_SEC" -le 86400 ]; then
            echo "Push found within 24 hours. Proceeding to deploy."
            echo "should_deploy=true" >> $GITHUB_OUTPUT
          else
            echo "No push in the last 24 hours. Skipping deploy."
            echo "should_deploy=false" >> $GITHUB_OUTPUT
          fi
 
      - name: Trigger Cloudflare Deploy Hook
        if: steps.check_push.outputs.should_deploy == 'true'
        run: curl -X POST -d {} ${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}

3. 빌드 시 대용량 파일 자동 제거

Cloudflare Pages 무료 플랜은 단일 파일 크기가 25MB를 초과하면 배포 에러가 발생한다. 이를 방지하기 위해 빌드 명령어에 삭제 로직을 추가했다.

  • 수정된 빌드 명령: git fetch --unshallow && npx quartz build && find public -type f -size +25M -print -delete

이렇게 설정하면 GitHub에는 대용량 파일이 보존되지만, 웹 배포 시에만 해당 파일을 제외한다.

UI 및 레이아웃 커스텀 방향

Quartz의 기본 테마는 문서 뷰어에 가깝다. 이를 ‘블로그’이자 ‘포트폴리오’처럼 보이게 하려고 디자인을 수정했다.

  • 첫 페이지: 이력서 형식으로, 나를 소개하는 공간으로 활용
  • Nav bar 추가: 내가 주요하게 다루고 카테고리를 상단 네비게이션 바에 띄울 수 있도록 수정
  • 기타 레이아웃 수정
    • Left sidebar 제거
    • Right sidebar
      • 제어 및 검색: 라이트/다크모드 버튼, 읽기모드 버튼, 검색 버튼
      • 파일 리스트: 동일한 폴더 내에 있는 문서링크 나열
      • 태그 리스트: 해당 문서에 있는 tag 나열
  • CSS 커스텀:
    • 색상 변경: quartz.config.ts에서 색상 변수에 사용할 색상 코드 입력.
    • Callout을 이용한, 2단 레이아웃 도입
    • Pretendard 폰트 적용

사용 방법 (워크플로우)

  1. 작성: Obsidian에서 마크다운 문서를 작성하고, 공개할 글에만 publish: true를 마킹한다.
  2. 동기화: Obsidian-Git을 통해 변경사항을 GitHub로 푸시한다. (커스텀 베이스 경로를 ..으로 설정해 Quartz 저장소와 동기화)
  3. 자동 배포: 매일 새벽 5시, GitHub Actions가 돌아가며 Cloudflare로 빌드 결과물을 전송하고 블로그를 업데이트한다.
  4. 수동 배포: 수동 배포가 필요할시에는 cloudflare에서 직접 배포한다.

마치며

이것저것 처음 쓰는 인프라와 기술들을 살펴보는 과정에서 배운 것이 많다. 이제는 배포에 신경 쓰지 않고 오직 ‘기록’ 그 자체에만 집중할 수 있는 환경이 갖추어졌다는 것이 가장 기쁘다. 내 글은 편하게 수정하고 publish 버튼 하나만 누르면 git commit부터 블로그 배포까지 내가 모르는 사이에 모든 것이 자동으로 진행된다.