이 글은 Hugo + PaperMod 블로그 세팅 시리즈의 두 번째 글이다.
- Hugo + PaperMod로 기술 블로그 만들기
- NCP 서버에 Hugo 블로그 배포하기 ← 현재 글
- 커스텀 도메인 연결과 Let’s Encrypt SSL 설정
배포 구조
[로컬 macOS] [NCP Rocky Linux]
content/*.md
↓ hugo --minify
public/ ──── rsync ────→ /var/www/blog/ ←── Nginx 서빙
Hugo가 생성한 정적 파일을 rsync로 서버에 전송하고, Nginx가 서빙하는 단순한 구조다. DB도 Node.js도 필요 없다.
1. SSH 키 인증 설정
매번 비밀번호를 입력하는 건 번거롭고, 스크립트 자동화도 불가능하다. SSH 키 인증을 먼저 세팅한다.
키 생성
ssh-keygen -t ed25519 -C "blog-deploy"
ed25519: RSA보다 짧고 안전한 알고리즘- passphrase: 비워도 되고, 입력하면 macOS Keychain이 기억해준다
서버에 공개키 등록
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@서버IP
이때 마지막으로 서버 비밀번호를 입력한다. 이후로는 비밀번호 없이 접속 가능.
SSH config 설정 (선택)
~/.ssh/config에 아래를 추가하면 ssh ncp-blog만으로 접속할 수 있다:
Host ncp-blog
HostName 서버IP
User root
IdentityFile ~/.ssh/id_ed25519
2. Nginx 설정 파일
Hugo 정적 파일을 서빙하기 위한 Nginx 설정이다.
server {
listen 80;
server_name 서버IP;
root /var/www/blog;
index index.html;
# gzip 압축
gzip on;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
# 정적 파일 캐싱 (30일)
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# Hugo 정적 사이트 서빙
location / {
try_files $uri $uri/ =404;
}
# 404 페이지
error_page 404 /404.html;
location = /404.html {
internal;
}
# 보안 헤더
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
핵심 설정:
try_files $uri $uri/ =404: 파일 → 디렉토리(index.html) → 404 순서로 탐색gzip: 텍스트 기반 파일을 압축해서 전송 (대역폭 절약)expires 30d: CSS/JS/이미지를 30일 캐싱 (재방문 시 빠른 로딩)
3. 서버 세팅
SSH로 서버에 접속해서 실행한다.
# Nginx 설치
dnf install -y nginx
# 블로그 디렉토리 생성
mkdir -p /var/www/blog
# Nginx 설정 파일 복사 (로컬에서)
scp deploy/nginx/blog.conf ncp-blog:/etc/nginx/conf.d/blog.conf
# 설정 검사 + 시작
ssh ncp-blog "nginx -t && systemctl enable nginx && systemctl start nginx"
systemctl enable은 서버가 재부팅되어도 Nginx가 자동 시작되게 한다.
4. 배포 스크립트
매번 명령어를 치는 건 번거로우니 스크립트로 만든다.
deploy.sh:
#!/bin/bash
set -e
SERVER_USER="root"
SERVER_HOST="서버IP"
SERVER_PORT="22"
REMOTE_DIR="/var/www/blog"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"
build() {
echo "=== Hugo 빌드 시작 ==="
hugo --minify
echo "=== 빌드 완료 ==="
}
deploy() {
echo "=== 서버 배포 시작 ==="
rsync -avz --delete \
-e "ssh -p ${SERVER_PORT}" \
public/ \
"${SERVER_USER}@${SERVER_HOST}:${REMOTE_DIR}/"
echo "=== 배포 완료 ==="
}
case "${1:-all}" in
build) build ;;
deploy) deploy ;;
all) build && deploy ;;
*) echo "사용법: $0 {build|deploy|all}" ; exit 1 ;;
esac
사용법:
chmod +x deploy.sh
./deploy.sh build # 빌드만
./deploy.sh deploy # 배포만
./deploy.sh # 빌드 + 배포
rsync의 --delete 옵션은 서버에서 로컬에 없는 파일을 삭제한다. 글을 지웠을 때 서버에도 반영되게 하려면 필요하다.
5. NCP ACG (방화벽) 설정
서버에서 curl localhost는 되는데 외부에서 접속이 안 된다면, NCP ACG 설정을 확인해야 한다.
NCP 콘솔 → Server → ACG → 인바운드 규칙:
| 프로토콜 | 포트 | 허용 소스 |
|---|---|---|
| TCP | 80 | 0.0.0.0/0 |
| TCP | 443 | 0.0.0.0/0 |
NCP는 OS 레벨 방화벽(firewalld)과 별개로 ACG라는 네트워크 방화벽을 사용한다. 둘 다 확인해야 한다.
배포 확인
curl -s -o /dev/null -w "HTTP %{http_code}, %{time_total}s" http://서버IP/
# HTTP 200, 0.021s
다음 글
IP 주소로 접속하는 블로그는 아무래도 불편하다. 다음 글에서는 커스텀 도메인을 연결하고 HTTPS를 설정한다.