Restic으로 VPS 데이터 외부 백업 자동화하기
Restic을 사용하여 VPS 데이터를 암호화 및 중복 제거 후 외부 저장소로 안전하게 전송하는 방법을 설명합니다. systemd 타이머를 활용한 매일 자동 백업 설정과 데이터 복구 훈련 과정을 포함하여 서버 장애나 삭제 사고에 대비하는 실무 가이드를 제공합니다.
동일한 서버에 저장된 백업이 백업이 아닌 이유
Restic은 파일의 암호화된 중복 제거 스냅샷을 다른 곳(두 번째 VPS, 가정용 머신, S3 호환 객체 스토리지 등)의 저장소로 전송하는 무료 오픈 소스 백업 도구입니다. 이 가이드에서는 Ubuntu 24.04 환경에서 Restic을 설치하고, SFTP를 통한 저장소 설정, 첫 백업 수행, systemd 타이머를 이용한 매일 자동 백업, 보존 정책 설정, 그리고 전체 과정이 정상 작동함을 확인하는 복구 훈련까지 다룹니다. 백업 대상은 반드시 다른 머신이어야 합니다. 동일한 서버에 존재하는 복사본은 서버와 운명을 같이하기 때문입니다.
백업 대상 서버 내의 backup/ 디렉터리는 실수로 파일을 삭제하는 상황으로부터만 보호해 줍니다. 디스크 장애가 발생하면 해당 디스크에 있던 백업본도 함께 사라지므로 보호받지 못합니다. root 권한을 탈취한 공격자가 백업본을 먼저 삭제할 경우에도 보호받지 못합니다. VPS 자체를 삭제하는 계정 실수로부터도 안전하지 않습니다. 세상에서 가장 비효율적인 데이터센터라는 농담은 데이터와 동일한 어레이에 저장된 backup_final_v2_REAL라는 이름의 tarball을 소재로 합니다. 우리 중 많은 이들이 실제로 그런 방식을 사용해 보았기에 이 농담이 성립합니다. '서버 외부로 보낼 것'이 원칙이며, Restic은 이를 가장 고통 없이 실천하는 방법입니다.
Restic의 4가지 핵심 개념
Repository. Restic이 데이터를 기록하는 저장소입니다. Restic 고유의 형식으로 구성된 디렉터리이며, 암호화된 블롭(blob)들로 채워져 있어 Restic만이 읽을 수 있습니다. 사용자가 직접 수정해서는 안 되며, Restic 명령어와 -r 주소를 통해서만 접근해야 합니다.
Snapshot. 백업한 파일들의 특정 시점 상태를 기록한 것입니다. 백업을 실행할 때마다 스냅샷이 생성되며, 각 스냅샷은 독립적으로 복원할 수 있고 해당 시점의 전체 데이터 복사본처럼 동작합니다.
Deduplication. Restic은 파일을 내용 기반의 청크(chunk)로 분할한 뒤, 저장소에 존재하지 않는 청크만 업로드합니다. 첫 번째 백업에서는 모든 데이터를 업로드하지만, 이후부터는 변경된 부분만 업로드합니다. 20 GB 데이터를 매일 백업할 때 50 MB만 변경되었다면 실제 추가되는 용량은 약 50 MB에 불과하므로, 수십 개의 스냅샷을 유지해도 저장 공간 효율이 매우 높습니다.
Encryption by default. Restic 저장소는 항상 AES-256으로 암호화되며, 모든 명령어 실행 시 저장소 비밀번호가 필요합니다. 백업 호스트나 스토리지 제공자는 암호화된 블롭만 확인할 수 있습니다. 이로 인해 발생하는 중요한 결과는, 비밀번호를 분실하면 데이터도 영구적으로 복구할 수 없다는 점입니다. 비밀번호는 반드시 서버 외부의 안전한 곳에 보관하십시오. 이는 아래에서 두 번 더 강조될 만큼 매우 중요한 사항입니다.
Ubuntu 24.04에 restic 설치하기
sudo apt update && sudo apt install -y restic
restic versionUbuntu 24.04에서는 restic 0.16.4 버전이 설치됩니다. 현재 업스트림 최신 릴리스는 0.19.1입니다. LTS(Long Term Support) 릴리스는 패키지 버전을 고정하므로 이러한 차이가 발생하지만, 이 가이드의 모든 작업은 0.16.4 버전으로 충분히 수행할 수 있습니다. 속도 향상을 위해 최신 릴리스가 필요하다면 restic 프로젝트의 GitHub 릴리스 페이지에서 공식 단일 바이너리 빌드를 다운로드하십시오. 이후 bunzip2로 압축을 풀고 /usr/local/bin/restic에 설치하면 됩니다. restic 설치 과정은 이것이 전부입니다.
SFTP를 통해 다른 서버에 저장소 생성하기
대상 장비가 필요합니다. 일반적으로 두 번째 소형 VPS를 사용하며, SSH 서버와 여유 디스크 공간이 있는 장비라면 무엇이든 가능합니다. Restic은 SFTP(SSH를 통한 파일 전송)를 지원하므로 백업 호스트에 별도의 소프트웨어를 설치할 필요가 없습니다. 이 가이드에서는 백업 호스트를 10.0.0.12로, 사용자를 restic로 가정합니다. 해당 사용자의 이름을 backup으로 지정하지 마십시오. Ubuntu와 Debian은 모든 설치 시 backup(uid 34, 로그인 셸 없음)이라는 예약된 시스템 계정을 생성하므로, adduser backup을 사용하면 실패하게 되며 ssh backup@...는 nologin에 위치하게 됩니다.
야간 작업은 백업 대상 서버에서 root 권한으로 실행되므로, root 계정이 백업 호스트에 키 기반으로 로그인할 수 있어야 합니다. 새벽 3시에 비밀번호를 입력할 사람이 없으므로 암호가 없는 전용 키를 생성하여 복사하십시오.
sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" -C "web1-restic"
sudo ssh-copy-id -i /root/.ssh/id_ed25519.pub restic@10.0.0.12
sudo ssh restic@10.0.0.12 true && echo key login works키 사용이 처음이라면 SSH 키 관리 기초에서 모델, 권한, 그리고 나중에 키를 취소하는 방법을 확인하십시오.
다음으로 저장소 비밀번호를 설정합니다. root만 읽을 수 있는 파일에 강력한 비밀번호를 생성하십시오.
openssl rand -base64 32 | sudo tee /root/.restic-password
sudo chmod 600 /root/.restic-password더 진행하기 전에 해당 비밀번호를 비밀번호 관리자에 복사해 두십시오. VPS가 손상되더라도 저장소와 이 비밀번호가 있으면 모든 데이터를 복구할 수 있습니다. 비밀번호가 없으면 저장소는 무용지물입니다.
저장소를 초기화합니다.
sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password initcreated restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1대안으로 S3 호환 객체 스토리지를 사용할 수 있습니다. 두 번째 장비를 운영하고 싶지 않을 때 적합한 선택입니다. 모든 S3 호환 버킷은 동일한 방식으로 작동하며, 주소와 두 개의 자격 증명 변수만 변경하면 됩니다.
export AWS_ACCESS_KEY_ID=your-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-key
sudo -E restic -r s3:https://s3.example.com/web1-backups --password-file /root/.restic-password initinit 이후의 모든 과정은 두 대상 모두 동일합니다. 이 가이드의 나머지 부분은 SFTP 주소를 기준으로 설명하므로, 본인의 환경에 맞게 수정하여 사용하십시오.
첫 번째 백업과 제외 항목 설정
전체 파일 시스템이 아닌, 재설치가 불가능한 데이터만 백업하십시오. 운영 체제는 재설치를 통해 복구할 수 있지만, 구성 파일과 데이터는 그렇지 않습니다. 일반적인 VPS의 경우 /etc, /home, 그리고 /srv나 /var/www와 같이 애플리케이션이 상태를 유지하는 경로가 이에 해당합니다. 캐시는 용량이 크고 매일 변경되며 스스로 재생성되므로 백업에서 제외하십시오.
sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password backup /etc /home /srv --exclude '/home/*/.cache'Files: 4181 new, 0 changed, 0 unmodified
Added to the repository: 731.204 MiB (312.418 MiB stored)
snapshot 5b8a3f2c saved첫 번째 실행 시에는 모든 데이터를 업로드하므로 시간이 다소 소요됩니다. 동일한 명령을 다시 실행하면 중복 제거(deduplication) 기능을 통해 새로운 청크만 업로드하므로, 변경된 몇 개의 파일과 몇 MiB의 데이터만 처리하고 몇 초 내에 완료됩니다. 현재 백업된 목록을 확인하려면 다음 명령을 사용하십시오.
sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password snapshots각 스냅샷은 ID, 시간, 포함된 경로를 보여줍니다. 이 ID를 사용하여 데이터를 복원할 수 있습니다.
systemd 타이머를 이용한 야간 실행
모든 명령마다 저장소 주소를 입력하는 것은 번거로운 일이며, 수동으로 실행하는 백업은 한 달을 넘기지 못하고 중단되기 마련입니다. 이 두 가지 문제는 하나의 스크립트와 하나의 타이머로 해결할 수 있습니다. 스크립트에서 restic이 읽어 들이는 두 환경 변수인 RESTIC_REPOSITORY과 RESTIC_PASSWORD_FILE을 설정하면, 내부의 모든 명령을 간결하게 유지할 수 있습니다.
sudo nano /usr/local/bin/restic-backup.sh#!/usr/bin/env bash
set -euo pipefail
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic backup /etc /home /srv --exclude '/home/*/.cache'
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic checksudo chmod 700 /usr/local/bin/restic-backup.shforget 및 check 줄에 대한 설명은 다음 두 섹션에서 다룹니다. 이제 스케줄을 설정합니다. 스크립트를 실행하는 oneshot 서비스와 매일 밤 03:00에 이를 호출하는 타이머를 만듭니다. 타이머는 cron보다 유리한데, 실행 기록이 저널에 남으며 Persistent=true 옵션을 사용하면 서버가 다운타임 이후 복구되는 즉시 누락된 백업을 수행하기 때문입니다.
# /etc/systemd/system/restic-backup.service
[Unit]
Description=Nightly restic backup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run the nightly restic backup
[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=15m
Persistent=true
[Install]
WantedBy=timers.target타이머를 활성화한 뒤, 서비스를 수동으로 한 번 실행하여 정상적으로 작동하는지 확인합니다.
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -fsystemctl list-timers 명령을 사용하면 다음 실행 시각을 확인할 수 있습니다. 직접 입력하는 대신 두 유닛 파일을 생성할 수도 있습니다.
캘린더 문법과 서비스에 적용할 수 있는 보안 강화 지시어를 포함하여, 이 두 파일에 적용된 전체 패턴은 VPS에서 systemd 서비스로 프로그램 실행하기에서 확인할 수 있습니다.
백업은 복구하기 전까지는 소문에 불과합니다
이 문장을 하나의 계명으로 여기십시오. 매일 밤 성공적으로 실행되는 백업 작업은 단지 작업이 수행되었다는 사실만을 증명할 뿐, 데이터가 실제로 복구될 수 있음을 보장하지는 않습니다. 두 가지 점검을 통해 이 간극을 메울 수 있습니다.
첫 번째는 restic check이며, 스크립트가 이미 매일 밤 이를 실행하고 있습니다. 이 작업은 리포지토리 구조와 인덱스를 검증하므로, 백업 호스트에서 발생한 조용한 데이터 손상을 복구 당일이 아닌 다음 날 바로 발견할 수 있습니다. 한 달에 한 번은 더 심층적인 버전을 실행하십시오. 이 작업은 실제 데이터의 10분의 1을 무작위로 다운로드하여 암호학적으로 검증합니다.
sudo -i
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic check --read-data-subset=10%매번 무작위로 하위 집합을 선택하므로, 전체 데이터를 다운로드하는 비용을 들이지 않고도 매달 리포지토리 전체를 점검할 수 있습니다.
두 번째는 복구 훈련입니다. 위에서 사용한 root 셸을 유지한 상태에서, 최신 스냅샷의 실제 디렉터리 하나를 임시 위치로 복구하고 실제 파일과 비교하십시오.
restic restore latest --target /srv/restore-drill --include /etc/ssh
diff -r /etc/ssh /srv/restore-drill/etc/sshdiff가 아무것도 출력하지 않는다면 모든 바이트가 동일하게 복구되었음을 의미하며, 이것만이 유일하게 신뢰할 수 있는 증거입니다. 작업 후에는 /srv/restore-drill를 삭제하십시오. 이 훈련을 매달 수행하고, 일 년에 한두 번은 전체 버전을 수행하십시오. 최신 스냅샷 전체를 임시 VPS에 복구하고 애플리케이션이 실제로 정상적으로 시작되는지 확인하십시오. 압박을 받는 상황에서 이 작업이 성공해야 한다면, 이미 익숙하게 수행해 온 일상적인 절차여야 합니다.
보존 정책: forget 및 prune
정책이 없으면 스냅샷이 무한히 누적되어 저장소 크기만 계속 커집니다. 스크립트의 forget 줄은 매일 밤 정책을 적용합니다. --keep-daily 7은 최근 7일간 하루에 하나씩, --keep-weekly 4은 4주간 일주일에 하나씩, --keep-monthly 6는 6개월간 한 달에 하나씩 스냅샷을 보존합니다. 규칙에 의해 보호되지 않는 모든 스냅샷은 삭제 대상(forget)이 됩니다.
forget만 실행하면 스냅샷 기록만 제거될 뿐, 데이터 청크는 여전히 저장소에 남아 있습니다. 이를 해결하는 것이 --prune입니다. 참조하는 스냅샷이 없는 청크를 찾아 삭제하며, 이 과정이 완료되어야 실제 디스크 공간이 확보됩니다. Prune은 저장소에 직접적인 작업을 수행하므로, 저장소 규모가 크다면 forget는 매일 밤, --prune은 매주 실행하는 경우도 있습니다. 일반적인 VPS 규모라면 매일 밤 실행해도 충분합니다.
데이터베이스: 먼저 덤프를 생성한 뒤 덤프 파일을 백업하십시오
Restic은 파일을 읽는 즉시 복사하지만, 데이터베이스는 지속적으로 파일에 데이터를 기록합니다. 쓰기 작업 중에 캡처된 라이브 데이터베이스 파일은 쓰기 전후의 페이지가 섞여 있어 복구 시 데이터베이스가 손상됩니다. 해결 방법은 표준적입니다. 데이터베이스 엔진이 일관된 상태의 내보내기 파일을 생성하게 한 다음, 해당 파일을 Restic으로 백업하는 것입니다.
PostgreSQL의 경우, restic backup 명령을 실행하기 전에 restic-backup.sh의 상단에 덤프 명령 줄을 추가하고, 백업 경로에 덤프 디렉터리를 포함하십시오.
mkdir -p /var/backups/db
sudo -u postgres pg_dump myapp | gzip > /var/backups/db/myapp.sql.gzmysqldump은 MariaDB와 MySQL에서 동일한 역할을 수행합니다. 전체 패턴에 대한 실제 예시로, Nextcloud 백업 섹션에서는 유지보수 모드를 활성화하고, Postgres를 덤프한 뒤, 파일들을 하나의 일관된 세트로 복사합니다. 이것이 바로 Restic이 매일 밤 서버 밖으로 전송해야 하는 정확한 데이터 세트입니다. SQLite도 같은 개념을 사용하지만 방식은 더 간단합니다. Vaultwarden 가이드에서는 컨테이너를 몇 초간 정지하여 db.sqlite3의 콜드 카피를 생성하며, Restic은 이 아카이브를 서버 밖으로 전송합니다.
FAQ
restic 백업은 암호화됩니까?
네, 항상 암호화됩니다. 모든 restic 저장소는 AES-256으로 암호화되며, 암호화되지 않은 모드는 존재하지 않습니다. 모든 명령은 저장소 비밀번호를 요구합니다. 저장소를 보관하는 기기나 제공자는 암호화된 블롭(blob)만 보유하므로, 백업 호스트가 침해당해도 파일이 노출되지 않습니다. 이는 절대적인 거래와 같습니다. 비밀번호가 없으면 누구도 데이터를 복구할 수 없으므로, 서버와 떨어진 곳에 비밀번호 사본을 보관하십시오.
restic은 증분 백업을 수행합니까?
모든 restic 스냅샷은 전체 백업처럼 작동하면서도 증분 백업의 저장 공간 효율성을 가집니다. restic은 파일을 청크 단위로 분할하고 저장소에 아직 없는 청크만 업로드하므로, 매일 실행하면 대략 그날 변경된 분량만큼만 전송됩니다. 기존의 증분 방식과 달리 재구성해야 할 체인이 없습니다. 어떤 스냅샷이든 직접 복구할 수 있으며, 오래된 스냅샷을 삭제해도 최신 스냅샷이 손상되지 않습니다.
restic 백업에서 파일을 어떻게 복구합니까?
restic snapshots을 실행하여 스냅샷 ID를 찾은 다음, restic restore <id> --target /some/empty/dir를 사용하여 복구하십시오. 일부만 복구하려면 --include /path을 추가합니다. latest은 ID 대신 사용할 수 있습니다. restic은 대상 경로 아래에 원래의 디렉터리 구조를 재현하므로, /etc/ssh를 복구하면 /some/empty/dir/etc/ssh에 저장됩니다. 테스트하지 않은 백업은 소문에 불과하므로, 필요하기 전에 미리 연습하십시오.
restic 백업은 얼마나 자주 실행해야 합니까?
서버의 경우 매일 밤 실행하는 것이 합리적인 최소 기준이며, 중복 제거 기능 덕분에 비용 부담이 적습니다. 각 실행 시 마지막 백업 이후 변경된 청크만 업로드하기 때문입니다. 빠르게 변경되는 데이터나 하루치라도 손실되면 치명적인 데이터는 동일한 타이머 패턴으로 몇 시간마다 실행할 수 있습니다. 빈도 설정은 쉬운 절반에 불과합니다. restic check를 정기적으로 실행하고 매달 복구 훈련을 수행하십시오. 검증 없는 일정은 거짓된 안도감일 뿐입니다.
restic 저장소 비밀번호를 분실하면 어떻게 됩니까?
백업을 복구할 수 없습니다. restic의 암호화에는 백도어나 재설정 기능이 없으므로, 비밀번호는 백업 그 자체만큼이나 중요합니다. 비밀번호 관리자나 백업 대상 서버가 아닌 안전하고 영구적인 곳에 사본을 보관하십시오. 아직 접근 권한이 있을 때 restic key add를 사용하면 동일한 저장소에 두 번째 비밀번호를 등록하여 예비용으로 사용할 수 있습니다.