Obsidian Vault에서 GitHub Pages까지 — 기술 블로그 자동 발행 파이프라인

(수정: 2026년 3월 27일) · 6분 읽기
목차

Obsidian Vault의 기술 노트를 AI 어시스턴트가 블로그 글로 변환하고, GitHub Actions + Cloudflare로 자동 배포하는 파이프라인 — Telegram에서 “블로그 발행해줘”라고 말하면 끝난다.

Obsidian Vault에서 GitHub Pages까지의 자동 발행 파이프라인 아이소메트릭 일러스트

Obsidian Vault에 수백 개의 기술 노트가 쌓여 있다면, 블로그 발행의 병목은 콘텐츠가 아니라 발행 과정의 마찰이다. vault 노트는 백링크와 내부 경로가 섞인 개인 메모이고, 블로그는 외부 독자가 읽는 글이다. 이 간극을 매번 수작업으로 메우다 보면 발행 자체를 미루게 된다.

기존에는 노트를 복사해서 백링크를 수동으로 제거하고, frontmatter를 작성하고, git push하고, 빌드를 확인하는 과정을 거쳤다. 한 편 발행하는 데 30분 이상 걸렸고, 이 마찰이 쌓이면 vault에만 노트가 묻히게 된다. 물론 발행 빈도의 진짜 병목이 인프라가 아니라 글 다듬기나 구조화 같은 인지적 부담인 경우도 있다. 하지만 “발행 버튼을 누르기까지”의 물리적 마찰을 줄이는 것만으로도 심리적 저항이 눈에 띄게 낮아졌다.

이 글은 그 마찰을 Telegram 대화 한 번으로 줄인 과정을 다룬다. Obsidian에서 GitHub Pages까지 이어지는 자동 발행 파이프라인을 어떤 판단으로 구성했고, 예상치 못한 곳에서 어떤 삽질을 했는지를 기록했다.

전체 아키텍처 — Obsidian에서 GitHub Pages까지

flowchart TD
    subgraph 콘텐츠 소스
        V[Obsidian Vault<br/>iCloud 동기화]
    end

    subgraph 로컬 맥북
        NC[AI Assistant<br/>Telegram Bot]
        NC --- VTB[변환 엔진<br/>Markdown 정제 + push]
    end

    subgraph GitHub
        GH[portfolio repo]
        GA[GitHub Actions<br/>Astro 빌드]
        GP[GitHub Pages<br/>gh-pages 브랜치]
    end

    subgraph Cloudflare
        CF[커스텀 도메인<br/>CNAME Proxied]
    end

    V -->|노트 읽기| VTB
    VTB -->|SSH deploy key| GH
    GH -->|push 트리거| GA
    GA -->|빌드 결과| GP
    CF -->|CDN 프록시| GP

핵심은 Obsidian → 변환 → GitHub → 빌드 → 배포가 하나의 파이프라인으로 연결된다는 점이다. 사람이 개입하는 부분은 “어떤 노트를 발행할지” 선택하는 것뿐이다.

K3s에서 GitHub Pages로 — 불필요한 복잡성 제거

처음에는 로컬 K3s 클러스터에서 nginx + git-sync + Cloudflare Tunnel로 서빙하려 했다. 맥북에서 이미 K3s를 운영하고 있었으니 자연스러운 선택이었다.

하지만 정적 블로그에 K3s는 과했다. git-sync 사이드카가 GitHub의 빌드 결과를 주기적으로 당겨오고, Cloudflare Tunnel로 외부에 노출하는 구성 자체는 동작했지만, 정적 파일 서빙에 Kubernetes 오버헤드를 감수할 이유가 없었다.

항목K3s 자체 호스팅GitHub Pages
가용성맥북 on 시만24/7
인프라 복잡도nginx + git-sync + NodePort + tunnel ingress없음
CDNCloudflare Tunnel 경유Cloudflare Proxied + GitHub CDN
유지보수pod/sidecar 모니터링관리 불필요

GitHub Pages로 전환하면서 K3s pod 관리와 tunnel ingress 설정이 모두 사라졌고, 24시간 가용성은 덤이었다. 맥북이 항시 가동 중이긴 하지만, 인프라 단순화가 가져오는 운영 부담 감소가 결정적이었다. “이미 가진 인프라를 활용하자”는 판단이 YAGNI 원칙을 넘어서는 순간이었다 — 쓸 수 있다고 써야 하는 건 아니다.

참고로 GitHub Pages 무료 티어에는 스토리지 1GB, 대역폭 100GB/월의 소프트 제한이 있다. 개인 기술 블로그 규모에서는 충분하지만, 이미지가 많은 블로그를 운영한다면 확인해둘 필요가 있다.

콘텐츠 자동 변환 — vault 노트를 블로그 글로

블로그 발행의 핵심은 vault 노트를 블로그 Markdown으로 변환하는 과정이다. Obsidian 노트는 그대로 블로그에 올릴 수 없다.

[[백링크]] 문법은 Astro가 인식하지 못하고, ## Related## References 섹션은 vault 내부 네비게이션용이다. 더 중요한 것은 내부 서버 주소, API 키 패턴, 사내 인프라 정보가 포함될 수 있다는 점이다. 개인 메모를 공개 블로그에 그대로 올리면 보안 사고로 이어진다.

자동 변환은 네 단계로 이루어진다:

  1. 백링크 제거[[노트명]]노트명으로, [[원본|표시]]표시로 변환
  2. 섹션 정리## Related, ## References 등 vault 전용 섹션 삭제
  3. frontmatter 생성 — title, description, pubDate, tags를 노트 내용에서 자동 구성
  4. 개인정보 마스킹 — 내부 URL, 비밀 키, 특정 경로 등을 일반화하거나 제거

개인정보 마스킹은 정규표현식 기반 패턴 매칭과 AI의 문맥 판단을 조합한다. IP 주소, API 키 패턴 같은 명확한 형식은 정규표현식으로 잡고, “이 URL이 내부용인지 공개 가능한지”처럼 맥락이 필요한 판단은 AI에게 맡긴다. 다만 AI 변환에는 환각이나 의미 왜곡의 가능성이 있다. 이 때문에 현재는 PR 생성 후 diff를 직접 확인하고 merge하는 방식으로 세이프가드를 두고 있다. 완전 자동 발행은 의도치 않은 정보 노출 위험이 있어 권장하지 않는다.

실제 발행 워크플로우는 다음과 같다:

  1. vault에서 최근 수정된 노트 중 미발행 목록을 조회한다
  2. Telegram으로 목록을 전송하고, 사용자가 번호로 선택한다
  3. 선택된 노트를 블로그 Markdown으로 변환한다
  4. PR을 생성하고 diff를 확인한다
  5. merge하면 GitHub Actions가 자동으로 Astro를 빌드하고 gh-pages에 배포한다
  6. Cloudflare CDN을 통해 블로그에 반영된다

글 관리도 단순하다. frontmatter에 draft: true를 설정하면 비공개, git rm으로 삭제, draft: false로 복원한다.

Astro + GitHub Pages 빌드/배포 구성

변환된 Markdown을 빌드하는 프레임워크로 Astro를 선택했다. 블로그라는 용도에 Astro가 적합했던 이유는 명확하다.

Content Collections가 Markdown 파일을 구조화된 데이터로 관리해준다. frontmatter에 title, description, pubDate, tags를 정의하면 Astro가 자동으로 인덱싱하고, 타입 안전한 쿼리를 제공한다. 별도의 CMS 없이 Markdown + frontmatter만으로 블로그를 운영할 수 있다는 점이 vault 기반 워크플로우와 잘 맞았다. Tailwind CSS v4로 스타일링하고, 정적 생성 특화 빌드로 JS 번들이 최소화된다. 이후 Lighthouse 100점 최적화를 진행할 때도 Astro의 정적 생성 특성이 큰 도움이 되었다.

Cloudflare DNS에서 CNAME을 Proxied 모드로 설정해 CDN 캐싱과 DDoS 보호를 함께 적용했다.

TypeNameTargetProxy
CNAMEblog*.github.ioProxied

GitHub Pages 쪽에서는 gh-pages 브랜치를 소스로 지정하고, HTTPS를 강제 적용했다. public/CNAME 파일로 커스텀 도메인을 유지하며, peaceiris/actions-gh-pages 액션이 빌드 결과를 자동 배포한다. push가 발생하면 GitHub Actions가 npm run build로 Astro를 빌드하고, 결과물을 gh-pages 브랜치에 배포한다. 전체 빌드-배포 사이클은 1분 이내로 완료된다.

컨테이너에서 git push하기 — uid 501과 SSH 프록시

한 가지 예상치 못한 장벽이 있었다. AI 어시스턴트가 Docker 컨테이너 안에서 실행되는데, 이 컨테이너의 uid가 macOS 호스트의 uid(501)로 매핑되어 있었다. 문제는 컨테이너의 /etc/passwd에 uid 501이 없다는 것이다.

OpenSSH는 내부적으로 getpwuid()를 호출하는데, 해당 uid에 대한 사용자 정보가 없으면 즉시 실패한다. ssh-keyscan, StrictHostKeyChecking=no 같은 옵션은 이 문제와 무관하다. SSH 연결 자체가 아니라 로컬 사용자 조회에서 막히기 때문이다.

해결 방법을 선택할 때 세 가지 경로를 검토했다:

방법장점단점
/etc/passwd 직접 수정단순함, 추가 종속성 없음컨테이너 재생성 시 초기화, 이미지 수정 필요
HTTPS + 토큰 인증SSH 자체를 우회토큰 관리, deploy key 대비 권한 범위 넓음
Node.js ssh2 프록시컨테이너 이미지 수정 불필요추가 종속성, 프록시 코드 유지보수

컨테이너 이미지를 직접 관리하지 않는 상황이었기 때문에 /etc/passwd 수정은 매번 초기화되는 문제가 있었다. HTTPS + 토큰은 deploy key 대비 권한 범위가 넓어 최소 권한 원칙에 맞지 않았다. 결국 Node.js ssh2 라이브러리로 SSH 프록시를 만들어 OpenSSH를 우회하는 방식을 선택했다. GIT_SSH 환경변수로 이 프록시를 지정하면 git push가 정상 동작한다.

# SSH 프록시를 통한 git push
GIT_SSH=/tmp/git_ssh.sh git push origin main

프록시 코드를 직접 유지해야 한다는 부담은 있지만, 컨테이너 이미지에 손대지 않고 해결할 수 있었다. 비슷한 환경에서 SSH 기반 git 작업을 한다면, 자신의 상황에 맞는 경로를 선택하면 된다.

이 접근이 적합한 경우와 한계

이 파이프라인은 이미 Obsidian에 노트를 쌓고 있는 사람에게 가장 적합하다. vault가 콘텐츠 소스이므로, 별도의 CMS나 에디터 없이 기존 습관 그대로 블로그를 운영할 수 있다.

반면, 몇 가지 한계도 있다:

  • 로컬 환경 종속 — 변환 엔진이 로컬 맥북에서 실행되므로, 맥북이 꺼져 있으면 발행이 불가능하다. 클라우드 기반 CI/CD와 달리 항시 가용한 구성은 아니다.
  • Markdown 단일 포맷 — vault 노트가 Markdown이 아닌 다른 형식(Notion, Google Docs 등)이라면 변환 파이프라인을 처음부터 다시 만들어야 한다.
  • 정적 사이트의 한계 — 댓글, 좋아요, 조회수 같은 동적 기능은 별도 서비스가 필요하다. 이 부분은 GitHub Pages 블로그의 동적 기능 구현에서 다루었다.
  • 단일 사용자 전제 — 팀 블로그나 다수 기여자 환경에는 적합하지 않다. 편집 워크플로우와 권한 관리가 없다.
  • AI 변환 리스크 — 자동 변환 과정에서 의미 왜곡이나 과도한 마스킹이 발생할 수 있다. PR 리뷰 단계에서 diff를 직접 확인하는 것이 필수적이다.

남은 과제

  • giscus 댓글 — GitHub Discussions 기반 댓글 시스템은 이미 적용했다.
  • 발행 리마인더 — 매주 일요일 아침에 발행 후보 노트 목록을 자동으로 알려주는 스케줄 태스크를 검토 중이다.
  • 시리즈 기능 — 연관된 글을 시리즈로 묶는 기능도 고려하고 있다.

마무리

이 파이프라인에서 가장 과소평가했던 부분은 “발행 버튼까지의 거리”가 심리적 저항에 미치는 영향이었다. K3s에서 GitHub Pages로 전환하고, 수동 변환을 자동화하고, Telegram 한 마디로 발행할 수 있게 만든 뒤에야 vault의 노트가 블로그로 나오기 시작했다. 결국 블로그의 핵심은 글을 쓰는 것이지 인프라가 아니다. 인프라는 그 글이 나올 수 있도록 길을 닦는 것에 그쳐야 한다.


More: 이 파이프라인은 이후에도 진화했다. 멀티 모델 리뷰 파이프라인으로 발행 전 품질 검증을 자동화했고, Telegram 채널 설정을 통해 대화형 인터페이스를 고도화했다. 블로그 기능 확장과 Lighthouse 최적화도 같은 맥락의 연장선이다.

이어서 읽기