워드프레스·호스팅

워드프레스 백업, 파일과 DB 둘 다 챙기는 실전 순서

워드프레스 백업, 파일과 DB 둘 다 챙기는 실전 순서

플러그인 하나 업데이트하고 새로고침했더니 화면이 하얗게 비어 있는 경험, 워드프레스를 직접 운영하면 한 번쯤은 겪습니다. 그때 가장 먼저 떠오르는 게 “백업 있었나?”입니다. 그런데 막상 백업 폴더를 열어보면 .tar.gz 파일 하나만 덩그러니 있고, 그걸 풀어서 올려도 글은 하나도 안 보입니다. 파일만 받았기 때문입니다.

워드프레스는 사이트 하나가 두 군데에 나뉘어 저장됩니다. 이 구조를 모르면 백업을 열심히 해도 복구가 안 됩니다. 여기서는 SSH가 되는 환경에서 tar와 mysqldump로 두 덩어리를 직접 받는 순서, 그걸 cron으로 자동화하는 방법, 그리고 그 백업이 진짜 살아있는지 확인하는 리허설까지 순서대로 다룹니다.

한눈에 · 경로·DB 정보 확인 → tar로 파일 백업 → mysqldump로 DB 백업 → backup.sh 묶기 → crontab 등록 → 복구 리허설로 검증

워드프레스 백업은 왜 항상 두 덩어리인가

워드프레스를 처음 설치하면 웹 서버에 PHP 파일들이 깔리고, 동시에 MySQL(또는 MariaDB) 데이터베이스에 테이블 열 몇 개가 만들어집니다. 이 두 개가 짝을 이뤄야 사이트가 뜹니다. 한쪽만 있으면 사이트가 아니라 반쪽짜리 잔해입니다.

파일 쪽에 들어있는 것과 DB 쪽에 들어있는 것

어느 쪽에 무엇이 있는지 한 번 정리해 두면 헷갈리지 않습니다.

구분들어있는 것없으면 생기는 일
파일 (웹 루트)워드프레스 코어, 테마, 플러그인 코드, wp-content/uploads의 이미지, wp-config.php, .htaccess사이트 자체가 안 뜨거나 이미지가 전부 깨짐
DB (MySQL)글 본문, 페이지, 댓글, 카테고리, 사용자, 사이트 설정, 플러그인 옵션값껍데기만 남고 글이 0개

파일만 백업하면 글이 없는 껍데기가 살아나고, DB만 백업하면 글은 있는데 이미지가 전부 깨진 사이트가 살아납니다. 그래서 둘 다여야 합니다.

백업 한 사이클
백업 한 사이클

백업이 있어도 복구가 안 되는 흔한 이유

실제로 백업을 찾게 되는 상황은 대체로 이런 것들입니다. 플러그인 업데이트 후 백지 화면, 테마 functions.php 수정 중 Parse error로 사이트 다운, 호스팅 계정 결제 누락으로 정지, 취약한 플러그인을 통한 파일 변조. 앞의 두 개는 파일만 되돌려도 살지만, 해킹으로 DB의 옵션값까지 손댄 경우는 DB도 있어야 합니다.

호스팅사가 “일일 백업 제공”이라고 적어둔 경우도 그대로 믿기는 어렵습니다. 보관 주기가 3일인지 7일인지, 복구가 계정 전체 단위인지 특정 파일 단위인지, 요청 시 유료인지가 업체마다 다릅니다. 해킹을 3주 뒤에 발견했다면 3일 보관 백업은 이미 감염된 상태만 들고 있습니다. 내 손에 있는 백업이 하나는 있어야 합니다.

시작 전에 확인할 것: 접속 정보와 백업할 경로 파악

두 덩어리를 받아야 한다는 걸 알았으니, 그 두 덩어리가 내 서버 어디에 있는지부터 찾습니다. 여기가 어긋나면 뒤 명령이 다 헛돕니다.

SSH로 접속한 뒤 웹 루트를 찾습니다. wp-config.php가 있는 디렉터리가 웹 루트입니다.

pwd
ls -al
ls -al public_html 2>/dev/null || ls -al www 2>/dev/null || ls -al htdocs

호스팅마다 이름이 다릅니다. cPanel 계열은 public_html, 일부 국내 호스팅은 www, 직접 세팅한 서버는 /var/www/html인 경우가 많습니다. 확실하게 찾으려면 find를 씁니다.

find ~ -maxdepth 3 -name wp-config.php

find 옵션이 익숙하지 않다면 find로 파일 찾아 한 번에 처리하기, -exec와 xargs 실전 정리를 같이 보면 뒤에서 나오는 오래된 백업 삭제도 이해가 빠릅니다.

wp-config.php에서 DB 정보 꺼내기

DB 백업에는 DB 이름, 사용자, 비밀번호, 호스트 네 개가 필요합니다. 전부 wp-config.php 안에 평문으로 적혀 있습니다.

grep -E "DB_NAME|DB_USER|DB_PASSWORD|DB_HOST" wp-config.php

출력은 이런 형태입니다.

define( 'DB_NAME', 'wp_myblog' );
define( 'DB_USER', 'wp_myblog' );
define( 'DB_PASSWORD', 'aX7!kd92mQ' );
define( 'DB_HOST', 'localhost' );

DB_HOST가 localhost가 아니라 mysql.호스팅사.com 같은 별도 주소인 경우도 있습니다. 그러면 뒤에서 mysqldump에 -h 옵션을 붙여야 합니다. 이 네 줄은 메모장에 옮겨두세요.

백업 파일을 어디에 둘 것인가

여기서 사고가 자주 납니다. 백업 폴더를 public_html/backup 같은 웹 루트 안에 만들면, 브라우저에서 https://내도메인/backup/wp-db-20260910.sql로 접근이 됩니다. DB 덤프 안에는 관리자 이메일, 해시된 비밀번호, 플러그인 API 키가 전부 들어있습니다. 백업 디렉터리는 반드시 웹 루트 밖에 둡니다.

mkdir -p ~/backup
chmod 700 ~/backup
df -h

df -h는 남은 디스크 용량을 봅니다. 백업 도중 디스크가 꽉 차면 tar나 sql 파일이 중간에 잘린 상태로 만들어지는데, 파일은 존재하니까 성공한 것처럼 보입니다. 나중에 복구할 때야 알게 됩니다. 용량이 빠듯하면 디스크 용량 부족, df와 du로 범인 찾아내는 순서를 먼저 보고 자리를 만드세요.

참고로 SSH 접속이 아예 막힌 공유호스팅이라면 이 글의 명령어 방식은 쓸 수 없습니다. 그 경우 대안은 뒤쪽 비교 섹션에서 다룹니다.

1단계: 파일 백업 — tar로 워드프레스 디렉터리 묶기

경로와 DB 정보를 확인했으면, 상대적으로 단순한 파일부터 받습니다. 리눅스에서 디렉터리 통째로 묶는 건 tar입니다.

tar czvf ~/backup/wp-files-$(date +%Y%m%d).tar.gz -C /home/user public_html

czvf는 만들고(c) gzip 압축하고(z) 진행 상황 보여주고(v) 파일명 지정(f)입니다. $(date +%Y%m%d)는 20260910 같은 오늘 날짜로 치환돼서 파일명이 겹치지 않습니다.

-C 옵션을 쓰는 이유

-C /home/user public_html은 “/home/user로 이동한 다음 public_html을 묶어라”는 뜻입니다. 이걸 안 쓰고 tar czvf backup.tar.gz /home/user/public_html로 하면 압축 파일 안에 home/user/public_html/... 경로가 통째로 박힙니다. 나중에 다른 서버나 다른 계정명으로 풀 때 경로가 어긋나서 손이 많이 갑니다. -C를 쓰면 안에 public_html/부터 들어갑니다.

tar 옵션 순서가 계속 헷갈리면 tar 압축과 해제 옵션 정리, czvf xzvf 순서까지 헷갈리지 않게를 옆에 띄워두면 편합니다.

제외할 것과 무한히 커지는 함정

캐시 파일과 로그는 복구에 필요 없습니다. 용량만 잡아먹으니 빼는 게 낫습니다.

tar czf ~/backup/wp-files-$(date +%Y%m%d).tar.gz \
  --exclude='wp-content/cache' \
  --exclude='wp-content/backup*' \
  --exclude='*.log' \
  -C /home/user public_html

여기서 주의할 게 하나 있습니다. 백업 폴더를 웹 루트 안에 만들어 두고 웹 루트를 압축하면, tar가 지금 만들고 있는 압축 파일을 자기 안에 다시 넣으려고 합니다. 파일이 계속 커지면서 디스크를 다 먹습니다. 앞에서 ~/backup을 웹 루트 밖에 만든 이유입니다.

빠뜨리기 쉬운 파일: .htaccess와 숨김 파일

.htaccess는 워드프레스 고유주소(퍼머링크) 규칙이 들어있는 파일입니다. 이게 없으면 복구 후 글 링크가 전부 404가 됩니다. 다행히 tar로 디렉터리를 지정하면 점으로 시작하는 숨김 파일도 같이 들어갑니다. 문제는 FTP 클라이언트로 수동 백업할 때인데, 기본 설정에서 숨김 파일을 안 보여주는 프로그램이 많습니다.

압축 파일이 정상인지 확인하는 방법

명령이 에러 없이 끝났다고 끝난 게 아닙니다. 두 가지를 봅니다.

ls -lh ~/backup/
tar tzf ~/backup/wp-files-20260910.tar.gz | head

ls -lh로 파일 크기가 상식적인지 봅니다. 사이트가 수백 MB인데 결과물이 2KB면 뭔가 잘못됐습니다. tar tzf는 압축을 풀지 않고 목록만 보여줍니다(t = list). | head로 앞 10줄만 확인하면 public_html/, public_html/wp-config.php 같은 줄이 나와야 정상입니다. 여기서 gzip: stdin: unexpected end of file이 나오면 압축이 중간에 끊긴 겁니다. 대개 디스크 용량 부족입니다.

wp-content/uploads가 커서 압축이 몇십 분씩 걸리는 사이트라면 전략을 바꿉니다. uploads는 한 번 올리면 잘 안 바뀌니까, 코어+테마+플러그인은 매일 받고 uploads는 주 1회만 따로 받는 식으로 나눕니다.

2단계: DB 백업 — mysqldump로 안전하게 덤프 뜨기

파일이 끝났으면 이제 진짜 중요한 쪽입니다. 테마와 플러그인은 다시 내려받으면 되지만, 3년 동안 쓴 글은 DB에만 있습니다.

mysqldump는 데이터베이스를 SQL 텍스트 파일로 뽑아내는 명령입니다. 결과 파일 안에는 CREATE TABLE과 INSERT 구문이 줄줄이 들어있어서, 나중에 그걸 그대로 실행하면 DB가 복원됩니다.

mysqldump -u wp_myblog -p wp_myblog > ~/backup/wp-db-$(date +%Y%m%d).sql

-u 다음이 사용자, -p는 비밀번호를 물어보라는 뜻(붙여 쓰지 않습니다), 그 다음이 DB 이름입니다. 엔터를 치면 Enter password:가 나옵니다.

실무에서 붙이는 옵션

기본 명령만으로도 되긴 하지만, 실제로는 옵션 세 개를 더 붙이는 게 안전합니다.

mysqldump --single-transaction --default-character-set=utf8mb4 --add-drop-table \
  -u wp_myblog -p wp_myblog > ~/backup/wp-db-$(date +%Y%m%d).sql
옵션하는 일안 붙이면
--single-transaction덤프 시작 시점 스냅샷으로 일관되게 뽑음(InnoDB)덤프 중 들어온 댓글 때문에 테이블 간 데이터가 어긋날 수 있음
--default-character-set=utf8mb4문자셋을 utf8mb4로 고정한글이 ???로 깨지는 대표 원인
--add-drop-table각 테이블 앞에 DROP TABLE IF EXISTS 삽입기존 테이블이 있는 DB에 넣을 때 중복 에러

utf8과 utf8mb4 차이도 짚어둘 만합니다. MySQL의 utf8은 한 글자를 최대 3바이트까지만 저장하는 반쪽짜리라서, 4바이트가 필요한 이모지를 넣으면 잘립니다. utf8mb4가 진짜 UTF-8입니다. 요즘 워드프레스는 기본이 utf8mb4이니 덤프 옵션도 여기에 맞춥니다.

한글이 ???로 깨졌다면 십중팔구 charset 옵션을 빼먹은 겁니다.

바로 압축해서 받기

sql 파일은 텍스트라서 압축이 잘 먹습니다. 200MB 덤프가 20MB로 줄어드는 일도 흔합니다. 파이프로 gzip에 넘기면 중간 파일을 안 만들고 바로 압축됩니다.

mysqldump --single-transaction --default-character-set=utf8mb4 \
  -u wp_myblog -p wp_myblog | gzip > ~/backup/wp-db-$(date +%Y%m%d).sql.gz

디스크가 빠듯한 계정에서는 이 방식이 낫습니다. 원본 sql을 만들 공간조차 없는 경우가 있습니다.

명령줄에 비밀번호를 안 쓰는 방법(.my.cnf)

-p'aX7!kd92mQ'처럼 비밀번호를 명령줄에 붙여 쓰면 두 군데에 흔적이 남습니다. ~/.bash_history 파일, 그리고 실행 중에는 ps aux 출력입니다. 같은 서버에 다른 사용자가 있으면 그 사람이 ps로 볼 수 있습니다.

자동화할 때는 비밀번호를 물어볼 사람이 없으니 이 문제가 반드시 걸립니다. 해법은 ~/.my.cnf 파일입니다.

cat > ~/.my.cnf <<'EOF'
[client]
user=wp_myblog
password=aX7!kd92mQ
default-character-set=utf8mb4
EOF
chmod 600 ~/.my.cnf

chmod 600은 본인만 읽고 쓸 수 있게 하는 권한입니다. 이걸 빼먹으면 World-writable config file '/home/user/.my.cnf' is ignored 경고와 함께 무시됩니다. 권한 숫자가 헷갈리면 chmod 755와 644의 실제 차이, 왜 폴더는 755여야 하나를 참고하세요.

이제 -u, -p 없이 됩니다.

mysqldump --single-transaction wp_myblog | gzip > ~/backup/wp-db-$(date +%Y%m%d).sql.gz

덤프가 정상인지 검사하는 두 가지 확인

mysqldump는 중간에 끊겨도 파일을 남깁니다. 그래서 크기만 보고 안심하면 안 됩니다. 정상적으로 끝난 덤프는 파일 마지막에 완료 주석이 붙습니다.

tail -5 ~/backup/wp-db-20260910.sql
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2026-09-10 04:00:12

Dump completed 줄이 있으면 끝까지 나온 겁니다. 없으면 중간에 끊긴 겁니다. gzip으로 압축한 경우는 압축을 풀지 않고 이렇게 봅니다.

zcat ~/backup/wp-db-20260910.sql.gz | tail -5
gzip -t ~/backup/wp-db-20260910.sql.gz && echo "압축 정상"

gzip -t는 압축 파일 무결성 검사입니다. 아무 출력 없이 끝나면 정상입니다.

DB 덤프와 검증
DB 덤프와 검증

여기서 자주 나는 에러

mysqldump: Got error: 1045: Access denied for user 'wp_myblog'@'localhost' (using password: YES) when trying to connect

사용자명이나 비밀번호가 틀렸습니다. wp-config.php에서 다시 복사하세요. 비밀번호에 !, $, # 같은 특수문자가 있으면 셸이 먼저 해석해 버리므로 홑따옴표로 감싸거나 .my.cnf를 쓰는 게 확실합니다.

-bash: mysqldump: command not found

명령이 PATH에 없습니다. find / -name mysqldump -type f 2>/dev/null로 위치를 찾아 절대 경로로 실행하세요. /usr/bin/mysqldump나 /usr/local/mysql/bin/mysqldump에 있는 경우가 많습니다. 아예 설치가 안 된 계정이면 호스팅사에 문의해야 합니다.

mysqldump: Got error: 1044: Access denied for user 'wp_myblog' to database 'wp_myblog' when using LOCK TABLES

LOCK TABLES 권한이 없는 계정입니다. 공유호스팅에서 흔합니다. --single-transaction을 붙이면 락을 안 걸어서 대개 해결됩니다. 그래도 안 되면 --skip-lock-tables를 추가합니다.

3단계: 두 덩어리를 하나로 묶고 cron으로 자동화하기

여기까지 손으로 해봤다면 이제 자동화 차례입니다. 사람이 매일 SSH 접속해서 명령 두 개를 치는 건 길게 못 갑니다. 스크립트 하나로 만들어 두면 그때부터는 잊고 살 수 있습니다.

backup.sh 전체 예시

#!/bin/bash
# 워드프레스 파일 + DB 백업

# ── 설정 ──────────────────────────
WP_PARENT="/home/user"          # 웹 루트의 상위 디렉터리
WP_DIR="public_html"            # 웹 루트 디렉터리명
DB_NAME="wp_myblog"
BACKUP_DIR="/home/user/backup"  # 웹 루트 밖
KEEP_DAYS=14                    # 보관 일수
MYSQLDUMP="/usr/bin/mysqldump"  # which mysqldump 결과를 넣을 것
DATE=$(date +%Y%m%d-%H%M)
# ─────────────────────────────────

mkdir -p "$BACKUP_DIR"
echo "=== $(date '+%F %T') 백업 시작 ==="

# 1) 파일
tar czf "$BACKUP_DIR/wp-files-$DATE.tar.gz" \
  --exclude="wp-content/cache" \
  --exclude="*.log" \
  -C "$WP_PARENT" "$WP_DIR"
if [ $? -eq 0 ]; then
  echo "파일 백업 OK: $(du -h "$BACKUP_DIR/wp-files-$DATE.tar.gz" | cut -f1)"
else
  echo "파일 백업 실패"
fi

# 2) DB (비밀번호는 ~/.my.cnf 에서 읽음)
$MYSQLDUMP --single-transaction --default-character-set=utf8mb4 \
  --add-drop-table "$DB_NAME" | gzip > "$BACKUP_DIR/wp-db-$DATE.sql.gz"
if [ ${PIPESTATUS[0]} -eq 0 ]; then
  echo "DB 백업 OK: $(du -h "$BACKUP_DIR/wp-db-$DATE.sql.gz" | cut -f1)"
else
  echo "DB 백업 실패"
fi

# 3) 오래된 백업 정리
find "$BACKUP_DIR" -name '*.gz' -mtime +$KEEP_DAYS -delete
echo "=== $(date '+%F %T') 백업 종료 ==="

${PIPESTATUS[0]}는 파이프로 연결된 명령 중 첫 번째(mysqldump)의 종료 코드입니다. 그냥 $?를 쓰면 마지막 명령인 gzip의 결과만 보게 되는데, gzip은 빈 입력을 받아도 성공으로 끝납니다. 그래서 실패를 놓칩니다.

오래된 백업 정리는 이 한 줄이 핵심입니다.

find ~/backup -name '*.gz' -mtime +14 -delete

-mtime +14는 수정 시각이 14일보다 오래된 파일입니다. 보관 일수는 계정 용량에 맞춰 조정하세요. 처음 돌릴 때는 -delete 대신 -print로 바꿔서 뭐가 지워질지 눈으로 확인하는 습관을 권합니다.

실행 권한을 주고 손으로 먼저 돌려봅니다.

chmod +x ~/backup.sh
~/backup.sh

cron이 조용히 실패하는 이유

손으로 잘 돌아가면 crontab에 올립니다.

crontab -e
0 4 * * * /home/user/backup.sh >> /home/user/backup.log 2>&1

매일 새벽 4시에 실행하고, 출력과 에러를 모두 로그 파일에 이어붙입니다. 2>&1이 에러(표준 에러)까지 같은 파일로 보내는 부분입니다. 이걸 빼면 정작 필요한 에러 메시지가 사라집니다.

cron에서 가장 흔한 실패는 PATH 문제입니다. 로그인 셸과 달리 cron은 PATH가 /usr/bin:/bin 정도로 짧습니다. 손으로는 되던 mysqldump가 cron에서는 command not found로 죽습니다. 그래서 스크립트 안에 절대 경로를 박아둡니다.

which mysqldump
# /usr/bin/mysqldump

이 결과를 스크립트의 MYSQLDUMP 변수에 넣으세요. tar, find, gzip도 같은 방식으로 확인해서 문제가 되면 절대 경로로 바꿉니다. cron 등록 후에도 안 돌아가면 crontab 작성법 정리, 등록해도 안 돌아가는 이유까지에 걸리는 지점들이 정리돼 있습니다.

등록 다음 날 아침에 로그를 꼭 확인하세요.

tail -20 ~/backup.log
ls -lh ~/backup/

조용히 실패하는 백업이 백업 없는 것보다 위험합니다. 있다고 믿고 있다가 사고 났을 때 없는 걸 알게 되니까요.

백업을 서버 밖으로 내보내기

같은 서버 안에만 두면 서버가 통째로 날아갈 때 백업도 같이 날아갑니다. 계정 정지, 디스크 장애, 랜섬웨어 다 그렇습니다. 최소 1부는 다른 곳에 있어야 합니다.

# 스크립트 끝에 추가 (SSH 키 인증이 설정된 원격 서버로)
rsync -az --delete "$BACKUP_DIR/" backupuser@203.0.113.10:/srv/wp-backup/

# 로컬 PC로 직접 내려받는 경우 (내 PC에서 실행)
scp user@내서버:/home/user/backup/wp-db-20260910.sql.gz ./

rsync는 바뀐 부분만 전송하니 매일 돌려도 부담이 적습니다. 자동화하려면 원격 서버에 SSH 키 인증을 걸어야 합니다. 비밀번호를 스크립트에 적는 건 피하세요.

복구 리허설: 백업이 진짜 살아있는지 확인하는 절차

백업을 걸어놨다는 것과 복구가 된다는 것은 완전히 다른 얘기입니다. 검증하지 않은 백업은 백업이라고 부르기 어렵습니다. 한 번은 되돌려 봐야 합니다.

중요한 전제가 있습니다. 리허설은 운영 사이트가 아니라 로컬 환경이나 별도 서브도메인, 임시 DB에서 합니다. 운영 DB에 덤프를 밀어넣었다가 잘못되면 사고를 직접 만드는 셈입니다.

파일 되돌리기

먼저 임시 디렉터리에 풀어봅니다.

mkdir -p ~/restore-test
tar xzvf ~/backup/wp-files-20260910.tar.gz -C ~/restore-test
ls -al ~/restore-test/public_html | head -20

xzvf는 풀고(x) gzip 해제(z) 목록 표시(v) 파일 지정(f)입니다. wp-config.php, wp-content, .htaccess가 보이면 됩니다.

DB 되돌리기

복구용 빈 DB를 하나 만들고 그쪽에 넣습니다.

mysql -u root -p -e "CREATE DATABASE wp_restore DEFAULT CHARACTER SET utf8mb4;"
mysql -u root -p wp_restore < ~/backup/wp-db-20260910.sql

# gzip 파일이라면
zcat ~/backup/wp-db-20260910.sql.gz | mysql -u root -p wp_restore

들어갔는지 봅니다.

mysql -u root -p wp_restore -e "SELECT COUNT(*) FROM wp_posts WHERE post_status='publish';"
mysql -u root -p wp_restore -e "SELECT post_title FROM wp_posts ORDER BY post_date DESC LIMIT 3;"

발행 글 수가 실제와 비슷하고 최근 글 제목이 한글로 제대로 나오면 덤프는 살아있습니다. 여기서 제목이 ???로 나오면 charset 문제입니다. 덤프 옵션이나 복구 시 문자셋을 확인하세요.

도메인이 바뀔 때 손봐야 하는 값

복구한 사이트를 다른 주소로 띄우면 접속하자마자 원래 도메인으로 튕깁니다. 워드프레스가 wp_options 테이블의 siteurl과 home 값을 보고 리다이렉트하기 때문입니다.

SELECT option_name, option_value FROM wp_options
 WHERE option_name IN ('siteurl','home');

UPDATE wp_options SET option_value='https://test.example.com'
 WHERE option_name IN ('siteurl','home');

테이블 접두어가 wp_가 아닌 사이트도 있습니다. wp-config.php의 $table_prefix 값을 확인하세요. 본문 안의 이미지 URL은 여기서 안 바뀌니, 리허설 목적이면 그냥 두고 표시 여부만 봐도 충분합니다.

복구 후 점검 항목

확인할 것안 되면 볼 곳
최신 글이 목록에 뜨는지DB 복구 자체, wp_posts 행 수
이미지가 표시되는지wp-content/uploads 존재 여부, 디렉터리 권한 755
관리자 로그인이 되는지wp_users, wp_usermeta 복구 여부
플러그인이 활성 상태인지wp_options의 active_plugins
개별 글 URL이 404 안 나는지.htaccess 존재, 고유주소 설정 재저장

이미지가 안 나올 때는 원인을 나눠야 합니다. 브라우저 개발자도구에서 이미지 URL을 직접 열어보세요. 404면 파일이 없거나 경로가 다른 것이고, 403이면 권한 문제입니다. 403이면 find ~/restore-test/public_html/wp-content/uploads -type d -exec chmod 755 {} \;로 디렉터리 권한을 맞춥니다.

플러그인 백업과 명령어 백업, 어느 쪽을 써야 하나

복구까지 해봤다면 이제 어떤 방식으로 운영할지 정할 차례입니다. 방법마다 맞는 상황이 다릅니다.

방식별 비교표

항목SSH 명령어(tar+mysqldump)백업 플러그인호스팅사 백업WP-CLI
대상 범위파일·DB 모두 직접 지정대개 둘 다, 설정 UI 제공계정 단위(업체별 다름)DB 중심, 파일은 별도
SSH 필요필요불필요불필요필요
대용량 사이트유리, 타임아웃 없음PHP 타임아웃/메모리로 끊기는 경우 있음업체 정책에 달림유리
자동화cron으로 자유롭게플러그인 스케줄러(WP-Cron 의존)업체가 자동 실행cron으로 자유롭게
보관 정책 통제내가 완전히 통제플러그인 설정 범위 내통제 불가내가 통제
복구 난이도명령어 알아야 함클릭으로 비교적 쉬움요청 절차 필요명령어 방식

플러그인 방식이 잘 끊기는 이유는 웹 요청 안에서 압축을 돌리기 때문입니다. PHP의 max_execution_time이나 memory_limit에 걸리면 중간에 죽습니다. 실패했는데 화면에 성공처럼 나오는 경우도 있어서, 플러그인을 쓰더라도 결과 파일 크기는 직접 확인하는 게 좋습니다.

WP-CLI가 깔린 환경이라면 DB 덤프가 한 줄로 끝납니다. wp-config.php에서 접속 정보를 알아서 읽어옵니다.

cd /home/user/public_html
wp db export ~/backup/wp-db-$(date +%Y%m%d).sql

권장 조합은 하나입니다. cron 자동 백업을 기본으로 걸어두고, 큰 작업 전에 수동으로 한 번 더 뜨고, 그중 1부는 서버 밖에 둡니다.

언제 수동 백업을 한 번 더 떠야 하나

자동 백업이 있어도 아래 상황에서는 직전에 한 번 더 받아두는 게 안전합니다. 새벽 4시 백업 이후에 쓴 글이 날아갈 수 있으니까요.

  • 워드프레스 코어 메이저 버전 업데이트 전
  • 테마 교체나 functions.php 수정 전
  • 플러그인 여러 개를 한꺼번에 업데이트할 때
  • PHP 버전을 올리기 전
  • 도메인 변경, 서버 이전 작업 전

워드프레스를 외부에서 자동으로 다루는 작업도 사고 가능성이 있는 쪽입니다. 워드프레스 REST API로 글 자동 등록하기, 인증부터 발행까지 같은 자동 발행 스크립트를 붙이기 전에도 백업을 한 번 떠두면 마음이 편합니다.

자주 묻는 질문

앞에서 다룬 내용 중 실제로 많이 걸리는 부분만 모았습니다.

워드프레스 백업은 얼마나 자주 해야 하나요?

기준은 “얼마까지 잃어도 견딜 수 있는가”입니다. 하루에 여러 건 발행하고 댓글이 활발한 사이트라면 매일, 주 1~2회 발행하는 개인 블로그라면 주 2~3회로도 충분합니다. 파일과 DB를 다른 주기로 돌리는 것도 방법입니다. 코드는 잘 안 바뀌니 주 1회, DB는 매일 이런 식입니다. 쇼핑몰처럼 주문 데이터가 계속 쌓이는 사이트는 DB만 하루 여러 번 받는 것도 과하지 않습니다.

파일 백업만 있고 DB 백업이 없으면 복구가 아예 안 되나요?

사이트는 뜨지만 글은 하나도 없습니다. 워드프레스를 새로 설치한 것과 비슷한 상태에 테마와 이미지 파일만 얹힌 셈입니다. wp-content/uploads에 이미지 파일은 남아 있으니 그걸 보고 글을 다시 쓸 수는 있지만, 본문 텍스트와 댓글은 복구할 방법이 없습니다. 반대로 DB만 있으면 글은 살아나지만 이미지가 전부 깨집니다.

mysqldump: command not found가 나오는데 어떻게 하나요?

먼저 실행 파일이 있는지 찾습니다. find / -name mysqldump -type f 2>/dev/null 또는 ls /usr/bin/mysqldump /usr/local/mysql/bin/mysqldump를 확인하세요. 있으면 그 절대 경로로 실행하면 됩니다. 아무것도 안 나오면 클라이언트 패키지가 설치돼 있지 않은 것으로, 직접 관리하는 서버라면 mysql-client(또는 mariadb-client)를 설치하고, 공유호스팅이면 호스팅사에 문의해야 합니다. 손으로는 되는데 cron에서만 이 에러가 나면 PATH 문제이므로 스크립트에 절대 경로를 박으세요.

복구한 사이트에서 한글이 ???로 깨집니다. 어디를 봐야 하나요?

거의 항상 문자셋 불일치입니다. 순서대로 확인합니다. 첫째, 덤프를 뜰 때 --default-character-set=utf8mb4를 붙였는지. 둘째, 복구할 DB를 DEFAULT CHARACTER SET utf8mb4로 만들었는지. 셋째, 복구 명령에도 mysql --default-character-set=utf8mb4 -u user -p dbname < wp-db.sql처럼 문자셋을 지정했는지. 이미 깨진 상태로 저장된 덤프는 되돌리기 어려우니, 원본이 살아있다면 옵션을 붙여 다시 뜨는 게 빠릅니다.

백업 용량이 너무 커서 계정 용량을 잡아먹습니다. 어떻게 줄이나요?

세 가지를 같이 씁니다. 먼저 보관 일수를 줄입니다. find ~/backup -name '.gz' -mtime +7 -delete처럼 7일로 낮추면 절반이 됩니다. 다음으로 wp-content/cache와 .log를 --exclude로 빼고, DB는 | gzip으로 반드시 압축합니다. 마지막으로 wp-content/uploads를 파일 백업에서 분리해 주 1회만 받고, 매일 백업에는 코어와 테마·플러그인만 넣습니다. du -sh ~/backup/*로 어느 파일이 큰지부터 확인하세요.

SSH를 못 쓰는 공유호스팅인데 명령어 백업이 가능한가요?

mysqldump나 tar를 직접 실행할 수 없으니 이 글의 방식은 그대로는 안 됩니다. 대안은 세 가지입니다. 호스팅 관리 패널에 phpMyAdmin이 있으면 거기서 DB를 sql로 내보낼 수 있고, 파일은 FTP로 내려받습니다(이때 .htaccess 같은 숨김 파일 표시를 켜야 합니다). 둘째는 백업 플러그인인데, 대용량이면 중간에 끊길 수 있으니 결과 파일 크기를 반드시 확인하세요. 셋째로, 관리 패널에 백업 메뉴를 제공하는 호스팅이면 그걸 쓰고 파일은 로컬로 한 부 내려두면 됩니다.

지금 바로 해둘 것 체크리스트

읽고 나서 안 하면 아무 의미가 없습니다. 오늘 안에 끝낼 수 있는 순서로 정리했습니다.

  1. SSH 접속 후 find ~ -maxdepth 3 -name wp-config.php로 웹 루트 경로 확인
  2. grep -E "DB_NAME|DB_USER|DB_PASSWORD|DB_HOST" wp-config.php로 DB 정보 4개 메모
  3. mkdir -p ~/backup && chmod 700 ~/backup — 웹 루트 밖에 생성
  4. df -h로 남은 용량 확인. 백업 예상 크기보다 여유가 있는지 볼 것
  5. tar czvf ~/backup/wp-files-$(date +%Y%m%d).tar.gz -C /home/user public_html 1회 실행
  6. tar tzf + ls -lh로 압축 파일 목록과 크기 확인
  7. mysqldump --single-transaction --default-character-set=utf8mb4 -u user -p db | gzip > ~/backup/wp-db-$(date +%Y%m%d).sql.gz 1회 실행
  8. zcat ... | tail -5로 Dump completed 줄 확인
  9. ~/.my.cnf 작성 후 chmod 600, 비밀번호 없이 덤프되는지 재확인
  10. which mysqldump 결과를 넣어 backup.sh 작성, 손으로 먼저 실행해서 성공 확인
  11. crontab -e에 0 4 * /home/user/backup.sh >> /home/user/backup.log 2>&1 등록
  12. 다음 날 tail -20 ~/backup.log와 ls -lh ~/backup/로 자동 실행 결과 확인
  13. 백업 파일 1부를 scp로 로컬 PC나 외부 스토리지에 내려두기
  14. 캘린더에 “복구 리허설” 일정을 한 달 안으로 하나 잡아두기

10번과 12번을 건너뛰는 사람이 제일 많습니다. 등록만 하고 확인을 안 하면, 정작 필요할 때 빈 폴더를 보게 됩니다.

댓글 남기기

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