Hugo 블로그를 목적별로 3개 운영하고 있다.

  1. 개발 블로그 — 개발 삽질 기록, 기술 문서 (이 블로그)
  2. [앱명] 홈페이지 — 앱 소개 + 업데이트 블로그, 다국어(ko/en)
  3. 개인 블로그 — 비개발 글

각각 역할이 달라서 분리했지만, 관리는 한 곳에서 하고 싶었다.


디렉토리 구조

~/domain/
├── seunghan-xyz/           # 개발 블로그
│   ├── content/
│   │   ├── posts/          # 기술 포스트
│   │   ├── projects/       # 프로젝트 소개
│   │   └── about/
│   ├── themes/
│   │   └── PaperMod/       # git submodule
│   ├── hugo.toml
│   └── public/             # 빌드 결과물
│
├── blogs/
│   └── blog_richdada/
│       ├── [앱명]-blog/    # 앱 홈페이지 겸 블로그
│       │   ├── content/
│       │   │   ├── posts/
│       │   │   ├── features/
│       │   │   ├── legal/
│       │   │   └── mcp/
│       │   ├── i18n/       # ko.yaml, en.yaml
│       │   ├── hugo.toml
│       │   └── netlify.toml
│       │
│       └── personal-blog/  # 개인 블로그
│           ├── content/
│           │   └── posts/
│           └── hugo.toml
│
└── dcode/
    └── landing/            # 정적 랜딩 페이지들

테마 선택

개발 블로그: PaperMod

# hugo.toml
theme = 'PaperMod'

미니멀하고 빠르다. 코드 하이라이팅이 깔끔하고, 다크모드를 기본 지원한다. 검색, 아카이브, 목차 기능이 내장되어 있어서 추가 설정이 거의 필요 없다.

[markup.highlight]
style = "github-dark"
noClasses = false

앱 블로그: Hugo Stack v3

# hugo.toml
[module]
  [[module.imports]]
    path = "github.com/CaiJimmy/hugo-theme-stack/v3"

카드형 레이아웃. 앱 소개 페이지처럼 시각적 요소가 많을 때 어울린다. Hugo Modules로 설치해서 업데이트가 쉽다:

hugo mod get -u github.com/CaiJimmy/hugo-theme-stack/v3

다국어 설정 (앱 블로그)

앱 스토어 심사에서 앱 홈페이지 URL을 요구할 때 영문 페이지도 필요하다.

# hugo.toml
DefaultContentLanguage = "ko"

[languages]
  [languages.ko]
    languageName = "Korean"
    weight = 1
  [languages.en]
    languageName = "English"
    weight = 2

콘텐츠 파일 구조:

content/
├── posts/
│   ├── ko/
│   │   └── feature-update.md
│   └── en/
│       └── feature-update.md
├── features/
│   └── _index.ko.md
│   └── _index.en.md

번역이 없는 페이지는 기본 언어(ko)로 폴백된다. 완전한 번역보다 핵심 페이지만 영문화하는 게 현실적이다.


Netlify 배포

각 블로그마다 netlify.toml이 있고, Netlify 사이트도 별도다.

# netlify.toml
[build]
  publish = "public"
  command = "hugo --minify"

[build.environment]
  HUGO_VERSION = "0.141.0"

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-Content-Type-Options = "nosniff"

자동 배포: GitHub 저장소와 Netlify를 연결하면 main 브랜치 push시 자동 빌드.

수동 배포 (개발 블로그):

cd ~/domain/seunghan-xyz
hugo && netlify deploy --prod \
  --dir ~/domain/seunghan-xyz/public \
  --site [SITE_ID]

--dir절대경로 필수. 상대경로 쓰면 현재 작업 디렉토리 기준으로 배포되어 엉뚱한 파일이 올라간다.


로컬 개발

# 개발 블로그
cd ~/domain/seunghan-xyz
hugo server -D          # draft 포함 미리보기
hugo server --port 1314 # 포트 충돌 방지

# 앱 블로그
cd ~/domain/blogs/blog_richdada/[앱명]-blog
hugo server -D --port 1315

# 개인 블로그
cd ~/domain/blogs/blog_richdada/personal-blog
hugo server -D --port 1316

세 서버를 동시에 띄울 수 있다. 포트만 다르게.


포스트 작성 패턴

Front Matter 템플릿

---
title: "제목"
date: 2025-10-08
draft: false
tags: ["태그1", "태그2"]
description: "SEO용 한 줄 설명"
---

draft: true로 작성해두고 완성되면 false로 바꾼다. 초안이 실수로 배포되는 걸 막을 수 있다.

파일명 규칙

posts/flutter-testflight-makefile-automation.md
posts/rails-dart-api-integration.md
posts/hugo-blog-multi-site-management.md

모두 소문자, 하이픈 구분. URL이 그대로 파일명이 된다.


테마 업데이트

PaperMod (git submodule)

cd ~/domain/seunghan-xyz
git submodule update --remote --merge
git add themes/PaperMod
git commit -m "chore: update PaperMod theme"

Stack v3 (Hugo Modules)

cd ~/domain/blogs/blog_richdada/[앱명]-blog
hugo mod get -u
hugo mod tidy

SEO 설정

# hugo.toml
enableRobotsTXT = true

[outputs]
home = ["HTML", "RSS", "JSON"]

[params]
  description = "..."
  keywords = ["개발", "Flutter", "iOS", "Rails"]

JSON 출력은 Fuse.js 검색에 필요하다. PaperMod에서 검색 기능을 켜면 자동으로 사용된다.


정리

용도테마배포 방식특이사항
개발 블로그PaperModNetlify CLI (수동)이 블로그
앱 홈페이지Stack v3Netlify (자동, GitHub 연동)ko/en 다국어
개인 블로그Stack v3Netlify (자동, GitHub 연동)

세 블로그가 서로 독립적으로 빌드/배포된다. 공통 설정을 공유하고 싶은 욕심이 있었지만, 각각 Hugo 버전도 다르고 요구사항도 달라서 그냥 독립적으로 두는 게 낫다는 결론이다.