Supabase DB Daily Backup
Self-hosted Supabase PostgreSQL 데이터베이스의 일일 자동 백업·복원 가이드입니다.
개요
| 항목 | 내용 |
|---|---|
| 스크립트 | /usr/local/bin/supabase-daily-backup.sh |
| 스케줄 | Cron 0 0 * * * (매일 00:00) |
| 백업 저장소 | /var/www/example.com/dbBackup/ |
| 로그 | /var/www/example.com/dbBackup/backup.log |
| 보관 기간 | 최근 3일 (RETENTION_DAYS=3) |
| 파일 형식 | example-backup-YYYYMMDD-HHMMSS.sql.gz |
| 백업 방식 | docker exec supabase-db pg_dump → gzip 압축 |
백업 프로세스
- 백업 디렉토리 존재 여부 확인 (없으면 생성)
supabase-db컨테이너에서pg_dump로 스키마+데이터 덤프.sql파일을gzip으로 압축- 3일 이상 된
example-backup-*.sql(.gz)삭제 - 결과·파일 목록·디스크 사용량을 로그에 기록
pg_dump 옵션
-U postgres
-d postgres
--no-owner
--no-acl
--clean
--if-exists
--clean --if-exists: 복원 시 기존 객체를 먼저 삭제할 수 있는 덤프 생성--no-owner --no-acl: 소유자/권한 의존을 줄여 복원 호환성 향상
파일 구조
/usr/local/bin/
└── supabase-daily-backup.sh
/var/www/example.com/dbBackup/
├── example-backup-YYYYMMDD-HHMMSS.sql.gz
├── ...
└── backup.log
현재 백업 예시 (2026-07-16 기준)
example-backup-20260713-011055.sql.gz
example-backup-20260713-090001.sql.gz
example-backup-20260714-090001.sql.gz
example-backup-20260715-090001.sql.gz
example-backup-20260716-090001.sql.gz
backup.log
스크립트 전문
경로: /usr/local/bin/supabase-daily-backup.sh
#!/bin/bash
################################################################################
# Supabase 일일 자동 백업 스크립트
# 매일 자정에 실행되며, 최근 3일간의 백업만 유지합니다.
################################################################################
# 설정
BACKUP_DIR="/var/www/example.com/dbBackup"
LOG_FILE="$BACKUP_DIR/backup.log"
RETENTION_DAYS=3
# 로그 함수
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "=========================================="
log "Supabase 백업 시작"
log "=========================================="
# 백업 디렉토리 확인
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
chmod 755 "$BACKUP_DIR"
log "백업 디렉토리 생성: $BACKUP_DIR"
fi
# 백업 파일명 (날짜 포함)
BACKUP_FILE="example-backup-$(date +%Y%m%d-%H%M%S).sql"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_FILE"
log "백업 파일: $BACKUP_FILE"
# Docker를 통한 데이터베이스 백업
log "데이터베이스 백업 중..."
docker exec supabase-db pg_dump \
-U postgres \
-d postgres \
--no-owner \
--no-acl \
--clean \
--if-exists > "$BACKUP_PATH" 2>> "$LOG_FILE"
# 백업 성공 확인
if [ $? -eq 0 ] && [ -f "$BACKUP_PATH" ]; then
FILE_SIZE=$(du -h "$BACKUP_PATH" | cut -f1)
log "✅ 백업 완료: $BACKUP_FILE (크기: $FILE_SIZE)"
# 압축 (선택사항 - 용량 절약)
log "백업 파일 압축 중..."
gzip "$BACKUP_PATH"
if [ $? -eq 0 ]; then
COMPRESSED_SIZE=$(du -h "$BACKUP_PATH.gz" | cut -f1)
log "✅ 압축 완료: $BACKUP_FILE.gz (압축 크기: $COMPRESSED_SIZE)"
else
log "⚠️ 압축 실패"
fi
else
log "❌ 백업 실패"
exit 1
fi
# 오래된 백업 삭제 (최근 3일만 유지)
log "오래된 백업 파일 정리 중... (${RETENTION_DAYS}일 이상)"
# .sql.gz 파일 삭제
DELETED_COUNT=0
while IFS= read -r old_file; do
if [ -n "$old_file" ]; then
log "삭제: $(basename "$old_file")"
rm -f "$old_file"
((DELETED_COUNT++))
fi
done < <(find "$BACKUP_DIR" -name "example-backup-*.sql.gz" -type f -mtime +$RETENTION_DAYS)
# .sql 파일 삭제 (압축 안된 파일)
while IFS= read -r old_file; do
if [ -n "$old_file" ]; then
log "삭제: $(basename "$old_file")"
rm -f "$old_file"
((DELETED_COUNT++))
fi
done < <(find "$BACKUP_DIR" -name "example-backup-*.sql" -type f -mtime +$RETENTION_DAYS)
if [ $DELETED_COUNT -gt 0 ]; then
log "✅ $DELETED_COUNT 개의 오래된 백업 삭제 완료"
else
log "✅ 삭제할 오래된 백업 없음"
fi
# 현재 백업 목록
log "=========================================="
log "현재 백업 파일 목록:"
log "=========================================="
ls -lh "$BACKUP_DIR"/example-backup-*.sql.gz 2>/dev/null | awk '{print $9, $5}' | while read line; do
log " $line"
done
# 디스크 사용량
DISK_USAGE=$(du -sh "$BACKUP_DIR" | cut -f1)
log "=========================================="
log "백업 디렉토리 총 사용량: $DISK_USAGE"
log "백업 완료"
log "=========================================="
exit 0
스크립트 복사해서 사용하기
아래 스크립트 전문을 그대로 복사한 뒤, 본인 서버 환경에 맞게 값만 바꿔 사용하면 됩니다.
1. 사전 확인
Self-hosted Supabase가 Docker로 실행 중이어야 합니다.
# DB 컨테이너 이름 확인 (기본값: supabase-db)
docker ps --format "table {{.Names}}\t{{.Status}}" | grep -i db
# Docker 명령 실행 권한 확인
docker exec supabase-db pg_dump --version
컨테이너 이름이 supabase-db가 아니면 스크립트의 docker exec 부분을 본인 환경에 맞게 수정하세요.
2. 설치 순서
# 1) 스크립트 파일 생성
sudo nano /usr/local/bin/supabase-daily-backup.sh
# → 위 "스크립트 전문" 전체를 붙여넣기
# 2) 실행 권한 부여
sudo chmod +x /usr/local/bin/supabase-daily-backup.sh
# 3) 백업 디렉토리 미리 만들기 (선택 — 스크립트가 자동 생성함)
sudo mkdir -p /var/www/example.com/dbBackup
sudo chmod 755 /var/www/example.com/dbBackup
# 4) 수동 실행으로 테스트
sudo /usr/local/bin/supabase-daily-backup.sh
# 5) 백업 파일 생성 확인
ls -lh /var/www/example.com/dbBackup/
# 6) Cron 등록 (아래 "Cron 설정" 참고)
crontab -e
Cron 등록 시에도
BACKUP_DIR경로를 본인 환경에 맞게 바꿔 주세요.
3. 반드시 바꿔야 할 항목
| # | 스크립트 위치 | 예시 값 | 본인 환경 |
|---|---|---|---|
| 1 | BACKUP_DIR |
/var/www/example.com/dbBackup |
백업을 저장할 디렉토리 |
| 2 | RETENTION_DAYS |
3 |
백업 보관 일수 (원하면 7, 14 등) |
| 3 | BACKUP_FILE 접두사 |
example-backup- |
mysite-backup- 등 구분하기 쉬운 이름 |
| 4 | docker exec 컨테이너명 |
supabase-db |
docker ps로 확인한 DB 컨테이너 이름 |
| 5 | find / ls 파일 패턴 |
example-backup-* |
3번 접두사와 동일하게 |
| 6 | Cron 로그 경로 | /var/www/example.com/dbBackup/backup.log |
1번 BACKUP_DIR과 일치 |
LOG_FILE은 $BACKUP_DIR/backup.log로 되어 있으므로 BACKUP_DIR만 바꾸면 로그 경로도 함께 맞춰집니다.
4. 커스터마이징 예시
도메인이 myservice.com이고, 백업을 7일간 보관하려면 스크립트 상단을 이렇게 바꿉니다.
# 설정 — ↓ 이 3줄(및 접두사)을 본인 환경에 맞게 수정
BACKUP_DIR="/var/www/myservice.com/dbBackup"
LOG_FILE="$BACKUP_DIR/backup.log"
RETENTION_DAYS=7
# ...
BACKUP_FILE="myservice-backup-$(date +%Y%m%d-%H%M%S).sql"
접두사를 myservice-backup-으로 바꿨다면, 아래 4곳의 파일 패턴도 같이 수정해야 합니다.
# find (삭제 대상 .sql.gz)
-name "myservice-backup-*.sql.gz"
# find (삭제 대상 .sql)
-name "myservice-backup-*.sql"
# ls (백업 목록 출력)
ls -lh "$BACKUP_DIR"/myservice-backup-*.sql.gz
5. 보통 바꾸지 않아도 되는 항목
| 항목 | 기본값 | 설명 |
|---|---|---|
pg_dump -U |
postgres |
Self-hosted Supabase 기본 DB 사용자 |
pg_dump -d |
postgres |
Self-hosted Supabase 기본 DB 이름 |
pg_dump 옵션 |
--no-owner --no-acl --clean --if-exists |
복원 호환성을 위한 권장 옵션 |
| 스크립트 설치 경로 | /usr/local/bin/supabase-daily-backup.sh |
다른 경로를 쓰면 Cron에도 동일하게 반영 |
DB 사용자·DB 이름을 커스텀했다면 pg_dump -U, -d 값도 함께 맞춰 주세요.
6. Cron 등록 시 함께 바꿀 것
스크립트만 수정하고 Cron 경로를 그대로 두면 로그가 엉뚱한 곳에 쌓일 수 있습니다.
# BACKUP_DIR을 /var/www/myservice.com/dbBackup 으로 바꿨다면:
0 0 * * * /usr/local/bin/supabase-daily-backup.sh >> /var/www/myservice.com/dbBackup/backup.log 2>&1
7. 설치 후 확인 체크리스트
-
docker ps에서 DB 컨테이너가 실행 중인가 - 수동 실행 후
✅ 백업 완료로그가 남는가 -
BACKUP_DIR에.sql.gz파일이 생성되는가 -
find/ls의 파일 접두사가BACKUP_FILE과 일치하는가 - Cron에 등록했고,
crontab -l로 확인했는가 - Cron 로그 경로가
BACKUP_DIR/backup.log와 같은가
Cron 설정
등록된 작업
0 0 * * * /usr/local/bin/supabase-daily-backup.sh >> /var/www/example.com/dbBackup/backup.log 2>&1
확인 / 편집
# 등록 확인
crontab -l
# 편집
crontab -e
스케줄 변경 예시
# 매일 새벽 3시
0 3 * * * /usr/local/bin/supabase-daily-backup.sh >> /var/www/example.com/dbBackup/backup.log 2>&1
# 매일 오전 9시
0 9 * * * /usr/local/bin/supabase-daily-backup.sh >> /var/www/example.com/dbBackup/backup.log 2>&1
수동 실행
/usr/local/bin/supabase-daily-backup.sh
성공 시 로그에 다음과 같은 메시지가 기록됩니다.
✅ 백업 완료: example-backup-YYYYMMDD-HHMMSS.sql
✅ 압축 완료: example-backup-YYYYMMDD-HHMMSS.sql.gz
백업 완료
모니터링
# 최근 로그
tail -50 /var/www/example.com/dbBackup/backup.log
# 실시간 로그
tail -f /var/www/example.com/dbBackup/backup.log
# 백업 파일 목록
ls -lh /var/www/example.com/dbBackup/
# 최신 백업 1개
ls -t /var/www/example.com/dbBackup/example-backup-*.sql.gz | head -1
# 디렉토리 사용량
du -sh /var/www/example.com/dbBackup/
정상 여부 체크리스트
- 오늘(또는 전날) 날짜의
.sql.gz파일이 있는가 -
backup.log에❌ 백업 실패가 없는가 -
supabase-db컨테이너가 실행 중인가 (docker ps | grep supabase-db)
복원 (Restore)
일일 백업(example-backup-*.sql.gz)을 Self-hosted Supabase DB(supabase-db)에 복원하는 방법입니다.
주의
- 복원은 현재 DB의 스키마/데이터를 덮어씁니다 (
--clean --if-exists덤프).- 운영 중이면 앱/API 트래픽을 잠시 중단한 뒤 진행하세요.
- 복원 직전에 현재 상태 안전 백업을 먼저 남기는 것을 권장합니다.
복원 개요
| 항목 | 내용 |
|---|---|
| 대상 컨테이너 | supabase-db |
| 대상 DB | postgres / 사용자 postgres |
| 입력 파일 | /var/www/example.com/dbBackup/example-backup-*.sql.gz |
| 복원 명령 | gunzip -c ... | docker exec -i supabase-db psql ... |
| 예상 소요 | DB 크기에 따라 수 초 ~ 수 분 |
사전 준비
# 1) DB 컨테이너 상태 확인
docker ps --filter name=supabase-db
# 2) 사용 가능한 백업 목록 확인
ls -lht /var/www/example.com/dbBackup/example-backup-*.sql.gz
# 3) (권장) 복원 전 현재 DB 안전 백업
/usr/local/bin/supabase-daily-backup.sh
1) 최신 백업으로 복원
LATEST=$(ls -t /var/www/example.com/dbBackup/example-backup-*.sql.gz | head -1)
echo "복원 대상: $LATEST"
gunzip -c "$LATEST" | docker exec -i supabase-db psql -U postgres -d postgres
성공 시 DROP / CREATE / COPY / ALTER 등이 연속 출력됩니다.
끝부분에서 major error 없이 프롬프트가 돌아오면 기본 복원은 완료된 것입니다.
2) 특정 시점 백업으로 복원
# 예: 2026-07-16 09:00 백업
BACKUP_FILE="/var/www/example.com/dbBackup/example-backup-20260716-090001.sql.gz"
gunzip -c "$BACKUP_FILE" | docker exec -i supabase-db psql -U postgres -d postgres
3) 압축 해제 후 복원 (디버깅용)
로그를 파일로 남기거나 오류를 자세히 볼 때 사용합니다.
BACKUP_GZ="/var/www/example.com/dbBackup/example-backup-20260716-090001.sql.gz"
BACKUP_SQL="/tmp/example-restore-$(date +%Y%m%d-%H%M%S).sql"
RESTORE_LOG="/tmp/example-restore-$(date +%Y%m%d-%H%M%S).log"
gunzip -c "$BACKUP_GZ" > "$BACKUP_SQL"
docker exec -i supabase-db psql -U postgres -d postgres < "$BACKUP_SQL" \
> "$RESTORE_LOG" 2>&1
echo "복원 로그: $RESTORE_LOG"
tail -50 "$RESTORE_LOG"
# 임시 SQL 삭제 (선택)
rm -f "$BACKUP_SQL"
4) 로컬 PC에서 받은 백업으로 복원
서버에 파일을 올린 뒤 동일하게 복원합니다.
# 로컬 PC → 서버 업로드
scp -P 2222 ./example-backup-YYYYMMDD-HHMMSS.sql.gz \
deploy@example.com:/tmp/
# 서버에서 복원
gunzip -c /tmp/example-backup-YYYYMMDD-HHMMSS.sql.gz | \
docker exec -i supabase-db psql -U postgres -d postgres
복원 후 확인
# 테이블 목록
docker exec supabase-db psql -U postgres -d postgres -c "\dt public.*"
# 주요 테이블 건수 예시
docker exec supabase-db psql -U postgres -d postgres -c "
SELECT
(SELECT COUNT(*) FROM profiles) AS profiles,
(SELECT COUNT(*) FROM posts) AS posts,
(SELECT COUNT(*) FROM comments) AS comments;
"
# DB 접속 후 수동 확인
docker exec -it supabase-db psql -U postgres -d postgres
# 예: \dt
# 예: SELECT COUNT(*) FROM profiles;
# 예: \q
복원 체크리스트
- 복원 전 안전 백업을 생성했는가
- 선택한
.sql.gz파일명(시점)이 맞는가 -
supabase-db가 실행 중인가 - 복원 후
\dt로 테이블이 보이는가 - 주요 테이블 row 수가 기대한 수준인가
- Studio/앱에서 로그인·조회가 정상인가
복원 시 자주 보는 메시지
| 메시지 | 의미 | 조치 |
|---|---|---|
ERROR: ... does not exist (DROP 중) |
--if-exists로 대부분 무시 가능 |
보통 무시 |
ERROR: role "..." does not exist |
덤프의 역할이 로컬에 없음 | --no-owner 덤프라 보통 영향 적음. 기능 이상 시 역할 생성 검토 |
FATAL: database "postgres" does not exist |
컨테이너/DB 이름 문제 | docker ps, compose 상태 확인 |
Cannot connect to the Docker daemon |
Docker 미기동 | systemctl status docker |
| 복원 중 연결 끊김 | 타임아웃/리소스 부족 | 압축 해제 후 파일 복원 방식 사용, 로그 확인 |
복원 실패 시 롤백
복원 직전에 만든 안전 백업으로 다시 되돌립니다.
# 방금 만든 최신 안전 백업 확인
ls -lht /var/www/example.com/dbBackup/example-backup-*.sql.gz | head -5
# 해당 파일로 재복원
gunzip -c /var/www/example.com/dbBackup/example-backup-YYYYMMDD-HHMMSS.sql.gz | \
docker exec -i supabase-db psql -U postgres -d postgres
백업 파일 다운로드 (로컬 PC)
SSH 포트: 2222 (환경에 맞게 변경)
# 전체 백업 디렉토리
scp -P 2222 -r deploy@example.com:/var/www/example.com/dbBackup ./example-dbBackup
# 최신 DB 백업만
ssh -p 2222 deploy@example.com \
"ls -t /var/www/example.com/dbBackup/example-backup-*.sql.gz | head -1" \
| xargs -I {} scp -P 2222 deploy@example.com:{} .
스크립트 설정 요약
위 「스크립트 복사해서 사용하기」 절차를 따랐다면, 이후 변경은 상단 변수만 수정하면 됩니다.
| 변수 | 기본값 | 설명 |
|---|---|---|
BACKUP_DIR |
/var/www/example.com/dbBackup |
백업 저장 경로 |
LOG_FILE |
$BACKUP_DIR/backup.log |
로그 파일 |
RETENTION_DAYS |
3 |
보관 일수 |
| 파일명 prefix | example-backup- |
생성 파일 이름 접두사 (find/ls 패턴과 동일해야 함) |
보관 기간을 7일로 바꾸는 예:
RETENTION_DAYS=7
장애 대응
1. supabase-db 미실행
cd /opt/supabase/docker
docker compose ps
docker compose up -d db
2. 백업 디렉토리 권한/경로 문제
mkdir -p /var/www/example.com/dbBackup
chmod 755 /var/www/example.com/dbBackup
3. 디스크 부족
df -h /var/www/example.com
du -sh /var/www/example.com/dbBackup/*
# 필요 시 RETENTION_DAYS 축소 또는 오래된 파일 수동 삭제
4. Cron이 실행되지 않음
systemctl status cron
crontab -l
grep CRON /var/log/syslog | tail -20
보안 유의사항
- 백업에는 DB 스키마·데이터가 포함되므로 접근 권한을 제한하세요.
- 비밀번호·API 키를 스크립트나 문서에 평문으로 추가하지 마세요.
- 로컬로 다운로드한 백업도 안전하게 보관·폐기하세요.


주파수 소통방 (0)
로딩 중...