자기 PC가 알아서 — 백업·캐시·이미지 압축

작성자

카테고리:

This post is written in Korean. Most browsers (Chrome, Edge) can translate it automatically — look for a translate icon in the address bar, or right-click the page and choose “Translate to English.”

셀프호스팅 구축기 4편. 운영은 자동화로 푼다.

← 이전 편: 3편 — AI도 읽으라고 (robots.txt·llms.txt)
→ 다음 편: 5편 — 별고래 분석실 (Umami)


TL;DR

  • 백업: 매일 03:00 mariadb-dump → gzip → Obsidian Vault. 30일 회전. 미니PC 죽어도 글 안전
  • DB 캐시: Redis Object Cache로 반복 쿼리 메모리 캐싱. 페이지 응답 30% 빨라짐
  • 페이지 캐시: WP Super Cache로 정적 HTML 생성. 두 번째 방문자부터 PHP 안 거침
  • 이미지: EWWW로 자동 WebP 변환. 평균 30~70% 용량 ↓
  • 셋업 한 번, 잊는다

1. 셀프호스팅의 진짜 일은 운영

처음 셋업은 30분이지만, 그 후가 진짜다. 매일 누가 백업하고, 누가 캐시 비우고, 누가 이미지 압축하나? 사람이 하면 까먹는다. 자동화한다.

세 가지 자동화가 도는 시점과 흐름 백업은 매일 03:00 cron으로 돈다. mariadb-dump로 DB를 뽑아 gzip으로 압축하고 Obsidian Vault에 저장하면 노트북과 폰으로 동기화된다. 30일 지난 백업은 자동 삭제된다. 캐시는 방문 요청마다 동작한다. WP Super Cache가 완성 HTML을, Redis Object Cache가 반복 DB 쿼리를 받아내고, 둘 다 없을 때만 MariaDB까지 간다. 이미지는 업로드할 때 EWWW가 WebP 변환과 무손실 압축을 하고, 옛 이미지는 Bulk Optimize 메뉴로 일괄 변환한다. 언제 무엇이 도나 백업 매일 03:00 · cron mariadb-dump gzip Obsidian Vault 노트북·폰 동기화 30일 지난 백업은 자동 삭제 (회전) 캐시 방문 요청마다 WP Super Cache Redis Object Cache MariaDB 완성 HTML 캐시 반복 DB 쿼리 캐시 둘 다 없을 때만 이미지 업로드할 때 이미지 업로드 EWWW WebP 변환 + 무손실 압축 옛 이미지는 Bulk Optimize 메뉴로 일괄 변환
그림 1. 세 가지 자동화가 각각 언제 돌고 무엇을 하는지. 백업은 시간(03:00), 캐시는 방문 요청, 이미지 압축은 업로드가 계기다.

2. 백업 — wp-backup.sh

/home/worker/scripts/wp-backup.sh:

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/home/user/문서/Obsidian Vault/KnowledgeVault/Meta/backups/wordpress"
DATE=$(date +%Y-%m-%d)
LOG_DIR="/home/worker/logs"
WEEK=$(date +%Y-W%V)
LOG_FILE="$LOG_DIR/kimcorp-${WEEK}.log"

mkdir -p "$BACKUP_DIR" "$LOG_DIR"

START=$(date +%s)
TARGET="$BACKUP_DIR/wp-${DATE}.sql.gz"

# mariadb-dump → gzip
if sudo docker exec wordpress-db-1 
   mariadb-dump --single-transaction -u root -p"${DB_ROOT_PW}" wp 
   | gzip > "$TARGET"; then
    SIZE=$(du -h "$TARGET" | cut -f1)
    ELAPSED=$(( $(date +%s) - START ))
    echo "$(date '+%Y-%m-%d %H:%M') | [wp-backup] | OK | ${SIZE} | ${ELAPSED}s" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M') | [wp-backup] | FAIL-L2 | dump error" >> "$LOG_FILE"
    exit 1
fi

# 30일 이상 회전
find "$BACKUP_DIR" -name "wp-*.sql.gz" -mtime +30 -delete

권한: chmod +x. crontab:

0 3 * * * /home/worker/scripts/wp-backup.sh

매일 새벽 03:00 자동 실행. 첫 백업 검증:

ls -la "$BACKUP_DIR"
# wp-2026-05-27.sql.gz  20K

20KB는 콘텐츠 없는 초기 DB. 글 100편 + 이미지 메타 = 보통 500KB~5MB.

왜 Obsidian Vault에 저장?

Obsidian Vault는 이미 주인장 노트 시스템 = 자동으로 다른 PC·폰에 동기화됨 (OneDrive·Syncthing 사용 시). 별도 백업 매체 셋업 불필요. 미니PC 죽어도 주인장 노트북·폰에 백업 사본 살아있음.


3. Redis Object Cache — DB 쿼리 캐싱

WordPress는 페이지 한 번 표시할 때 평균 50~200개 DB 쿼리를 던진다. 그중 80%가 반복(메뉴·옵션·설정).

Redis Object Cache가 이 반복 쿼리를 메모리에 캐싱:

wp config set WP_REDIS_HOST redis --allow-root
wp config set WP_REDIS_PORT 6379 --allow-root
wp config set WP_REDIS_PREFIX byeolgorae: --allow-root
wp config set WP_CACHE true --raw --allow-root
wp plugin install redis-cache --activate --allow-root
wp redis enable --allow-root

검증:

wp redis status --allow-root
# Status: Connected
# Client: PhpRedis (v6.x)

체감: 페이지 응답 300ms → 200ms (30% 단축).


4. WP Super Cache — 페이지 캐시

Redis가 DB 쿼리 캐시라면, WP Super Cache는 완성된 HTML 자체를 캐싱.

방문 Redis만 Redis + Super Cache
첫 방문자 PHP 실행 + Redis 캐시 미스 → DB → 응답 PHP 실행 + 정적 HTML 생성
두 번째~ 방문자 PHP 실행 + Redis 캐시 히트 → 응답 (~200ms) PHP 안 거침. 정적 파일 직접 응답 (~50ms)
방문 요청 하나가 두 캐시를 지나는 경로 방문자 요청이 들어오면 먼저 WP Super Cache가 완성 HTML이 있는지 본다. 있으면 두 번째 방문부터는 PHP를 거치지 않고 정적 HTML 파일을 바로 응답한다(약 50ms). 없으면 첫 방문이므로 PHP가 실행되고, WordPress의 DB 쿼리는 Redis Object Cache가 먼저 받는다. 캐시 미스일 때만 MariaDB에 간다. 응답과 함께 정적 HTML이 만들어져 다음 방문자용으로 저장된다. 로그인한 사용자는 페이지 캐시를 받지 않는다. 방문자 요청 WP Super Cache 완성 HTML 있나? 있음 두 번째 방문부터 정적 HTML 파일을 바로 응답 PHP 안 거침 · 약 50ms 없음 PHP 실행 WordPress · 첫 방문 쿼리 Redis Object Cache 반복 쿼리는 메모리에서 캐시 미스 MariaDB 미스일 때만 조회 응답 + 정적 HTML 생성 다음 방문자는 위쪽 경로로 간다 HTML 저장 참고: 로그인한 사용자는 페이지 캐시를 받지 않는다 (의도된 동작). 발행 직후 확인은 시크릿 창으로.
그림 2. 요청 흐름에서 두 캐시가 끼는 자리. WP Super Cache는 완성 HTML을, Redis Object Cache는 PHP 안쪽의 반복 DB 쿼리를 받아낸다.

플러그인 설치 후 활성화는 GUI에서:
– 설정 → WP Super Cache → Easy 탭
– “Caching On (Recommended)” 라디오
– Update Status

wp-cli로는 활성 못함 (커맨드 미등록). 주인장이 직접 한 번 클릭.

⚠ 함정: 로그인된 사용자(주인장)는 페이지 캐시 안 받음 (의도된 동작). 주인장이 글 발행 후 “왜 안 보여?” 할 수 있는데 시크릿 모드로 열어보면 보임.


5. EWWW Image Optimizer — 이미지 자동 압축

업로드한 이미지를 자동으로 WebP로 변환 + 무손실 압축.

형식 같은 사진 용량
JPEG (원본) 800KB
WebP (EWWW) 250KB (-69%)
AVIF (EWWW 유료) 150KB (-81%)

설치 후 기본 설정 그대로면 OK. 새 이미지 업로드 시 자동 변환. 옛 이미지 일괄 변환은 Bulk Optimize 메뉴.

체감: 모바일 페이지 LCP(Largest Contentful Paint) 2.5초 → 1.2초.


6. 종합 — 셋업 한 번, 운영 0

작업 셋업 시간 이후
wp-backup.sh + cron 10분 매일 03:00 자동
Redis Object Cache 3분 영구 자동
WP Super Cache GUI 활성 1분 영구 자동
EWWW Image Optimizer 1분 새 이미지 업로드 시 자동

총 15분 한 번 = 운영 자동화 완료.


FAQ

Q. 백업 복원은 어떻게?

gunzip -c wp-2026-05-30.sql.gz | sudo docker exec -i wordpress-db-1 mariadb -u root -p"${DB_ROOT_PW}" wp

한 줄. 실제 복원은 분기에 한 번 정도 리허설 권장.

Q. wp-content/uploads 이미지도 백업되나?
위 스크립트는 DB만. 이미지는 tar -czf uploads-$DATE.tar.gz wp-content/uploads/ 한 줄 추가하면 됨. 또는 Obsidian Vault에 직접 첨부하는 워크플로면 별도 백업 불필요.

Q. UpdraftPlus 같은 WP 백업 플러그인 쓰면 안 되나?
가능. 단 WP 안에서 백업 = WP 죽으면 백업도 죽음. 시스템 레벨 cron이 더 안전. UpdraftPlus는 보조로 설치만 해두고 비활성.

Q. Redis 메모리 차면?
별고래 트래픽 규모(월 1만 미만)에선 100MB 이하. 메모리 차도 LRU(Least Recently Used)로 자동 정리. 걱정 X.

Q. WP Super Cache + Cloudflare CDN 중복 아닌가?
중복 아님. CDN은 정적 파일(이미지·CSS), Super Cache는 HTML. 둘 다 켜는 게 정답.


다음 편 예고

5편 — 별고래 분석실: Umami로 방문자 통계. Google Analytics 대신 자체 호스팅. 쿠키 없음 + 주인장이 데이터 소유.


한 줄 정리

셋업 15분으로 백업·DB 캐시·페이지 캐시·이미지 압축이 매일 자동. 운영 시간 0, 페이지 30% 빠름, 이미지 70% 작음, 데이터 안전.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다