왜 Hugo인가?
WordPress는 강력하지만 무겁다. PHP, MariaDB, 각종 플러그인이 맞물려 동작하는 구조는 단순한 블로그를 운영하기엔 오버스펙이다. 특히 코드 스니펫과 기술 글 위주의 블로그라면 더욱 그렇다.
Hugo로 갈아탄 이유는 크게 세 가지다.
- 속도: DB 조회와 PHP 실행이 없다. nginx가 정적 HTML 파일만 서빙한다
- 단순함: MariaDB, PHP 없이 서버 구성이 훨씬 가벼워진다
- SEO: 빠른 로딩 속도는 Core Web Vitals 점수에 직접 영향을 준다
WordPress vs Hugo 요청 흐름 비교
WordPress 요청 흐름은 다음과 같다.
브라우저 → nginx → PHP → MariaDB → PHP → nginx → 브라우저
Hugo 요청 흐름은 이렇게 단순해진다.
브라우저 → nginx → HTML 파일
코드 블로그에 Hugo가 잘 맞는 이유
Hugo는 Chroma라는 문법 하이라이터를 빌트인으로 지원한다. 별도 플러그인 없이 200개 이상의 언어를 지원하고, 빌드 시 정적 HTML로 변환되기 때문에 Prism.js 같은 JS 라이브러리도 필요 없다.
# hugo.toml
[markup.highlight]
style = "monokai"
마크다운 코드블록을 그대로 쓰면 자동으로 하이라이팅이 적용된다.
마이그레이션 8단계
1단계. Hugo 설치
sudo apt update
sudo snap install hugo
# 버전 확인
hugo version
새 사이트를 생성한다.
cd ~
hugo new site myblog
cd myblog
생성된 디렉토리 구조는 다음과 같다.
myblog/
├── content/ # 글이 들어갈 곳
├── static/ # 이미지 등 정적 파일
├── themes/ # 테마
├── layouts/ # 커스터마이징
└── hugo.toml # 설정 파일
2단계. 테마 설치
기술 블로그에 가장 많이 쓰이는 PaperMod 테마를 기준으로 설명한다.
cd ~/myblog
git init
git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod
hugo.toml 기본 설정이다.
defaultContentLanguage = "ko"
title = "내 블로그"
theme = "PaperMod"
[languages.ko]
languageName = "한국어"
locale = "ko-KR"
title = "내 블로그"
[params]
ShowReadingTime = true
ShowCodeCopyButtons = true # 코드 복사 버튼 자동 추가
ShowToc = true # 목차 자동 생성
mainSections = ["posts"]
[markup.highlight]
style = "monokai"
[markup.goldmark.renderer]
unsafe = true # 변환된 md 파일의 HTML 태그 렌더링
3단계. WordPress 글 마이그레이션
wordpress-to-hugo-exporter plugin을 이용해서 WordPress 글을 내보낸다.
# 플러그인 다운로드
cd /var/www/wordpress/wp-content/plugins/
sudo git clone https://github.com/SchumacherFM/wordpress-to-hugo-exporter
# WP 관리자에서 플러그인 활성화 후
# Tools → Export to Hugo → 다운로드
변환된 파일을 Hugo content 폴더로 복사한다.
cp -r build/ ~/myblog/content/
4단계. 이미지 마이그레이션
WordPress는 이미지를 업로드하면 크기별로 여러 파일을 생성한다.
photo.jpg # 원본
photo-150x150.jpg # 썸네일
photo-300x200.jpg # 미디엄
photo-1024x683.jpg # 라지
Hugo에서는 원본 파일만 있으면 되므로 리사이징된 파일을 정리한다.
# -숫자x숫자. 패턴 파일 삭제
find ./uploads -regex '.*-[0-9]+x[0-9]+\..*' -delete
원본 이미지를 Hugo static 폴더로 복사한다.
cp -r ./uploads/* ~/myblog/static/images/
마크다운에서 이미지 경로는 static/ 폴더를 기준으로 절대경로로 작성한다.

5단계. 로컬 미리보기
cd ~/myblog
hugo server
같은 네트워크의 다른 PC에서 확인하려면 다음과 같이 실행한다.
hugo server --bind 0.0.0.0 --baseURL http://서버IP/
이때 ufw에서 포트를 허용해야 한다.
sudo ufw allow 1313
# 테스트 후 닫기
sudo ufw delete allow 1313
브라우저에서 http://서버IP:1313 으로 접속해 확인한다.
6단계. 빌드 및 배포
# 정적 파일 빌드
hugo build
# 서버에 rsync로 동기화
rsync -avz --delete ~/myblog/public/ /var/www/blog/
# 소유자 변경 (nginx가 www-data로 실행되므로)
sudo chown -R www-data:www-data /var/www/blog/
매번 입력하기 번거로우므로 alias로 등록해 둔다.
# ~/.bashrc에 추가
alias blogdeploy='cd ~/myblog && hugo build && \
rsync -avz --delete public/ /var/www/blog/ && \
sudo chown -R www-data:www-data /var/www/blog/'
이후 배포는 한 줄로 끝난다.
blogdeploy
7단계. nginx 설정 변경
WordPress용 설정을 Hugo용으로 교체한다.
server {
listen 80;
server_name yourblog.com;
root /var/www/blog;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# 정적 파일 캐시
location ~* \.(jpg|jpeg|png|gif|css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
}
sudo nginx -t
sudo systemctl reload nginx
HTTPS는 기존 certbot 설정을 그대로 사용한다.
8단계. 구글 서치 콘솔 업데이트
Hugo는 빌드 시 sitemap.xml을 자동으로 생성한다. 구글 서치 콘솔에 등록한다.
구글 서치 콘솔 → Sitemaps → 새 sitemap 추가
https://yourblog.com/sitemap.xml
MariaDB 정리
마이그레이션이 완료되면 WordPress와 MariaDB를 정리할 수 있다.
# DB 백업
mysqldump -u root -p wordpress > wordpress_backup.sql
# DB 삭제
mysql -u root -p -e "DROP DATABASE wordpress;"
# MariaDB 중지
sudo systemctl stop mariadb
sudo systemctl disable mariadb
MariaDB와 PHP가 빠지면 서버 메모리와 CPU 사용량이 눈에 띄게 줄어든다.
이후 글쓰기 워크플로우
# 새 글 작성
hugo new content/posts/new-post.md
vim content/posts/new-post.md
# 로컬 미리보기
hugo server
# 배포
blogdeploy
Front Matter 기본 구조는 다음과 같다.
---
title: "글 제목"
date: 2025-01-01
tags: ["태그1", "태그2"]
categories: ["dev"]
description: "글 요약"
slug: "post-url-slug"
---
어디서든 ssh로 접속해 작업할 수 있으므로 Hugo가 설치된 환경에 묶일 필요가 없다.