1. Offisite Backup
Offisite Backup은 장애나 사고에 대비하기 위해 반드시 필요하다.
로컬 스토리지에만 의존하면 화재, 침수, 하드웨어 고장 같은 문제가 발생했을 때 데이터 복구가 불가할 수 있다.

옛날에 조선왕조실록도 여러 지역에 외사고를 운영했던 것처럼 본진이 털릴 경우를 대비해서 별도의 물리적 공간이나 클라우드에 백업을 두는 게 좋다.
Proxmox VE를 사용하는 경우 S3 호환 스토리지, Cloud-PBS 같은 서비스를 고려할 수 있다.
Cloud-PBS는 프랑스, 독일, 미국 등에서 호스팅 되는 원격으로 관리되는 PBS 정도로 생각하면 된다.
Cloud-PBS는 관리가 편리한 만큼 요금이 비싸다.
(25년 기준으로 단순 용량당 비용만 비교했을 때 Backblaze B2 대비 약 4배 가까이 비싸다.)
장기간 대용량 데이터를 백업해야 한다면 꽤 부담스러운 차이다.
그런 면에서 가격 경쟁력은 S3 계열이 훨씬 낫다.
얼마전까지는 PBS가 직접 S3를 지원하지 않아 번거로움이 있었다.
하지만 PBS 4.0 버전부터는 공식적으로 S3 백업을 지원하기 시작했다.
덕분에 원하는 S3 호환 스토리지를 골라서 Offsite backup을 구현할 수 있게 됐다.
2. 백업 암호화
외부로 정보가 나가는 것이기 때문에 백업 데이터를 암호화한다.
기존에 연결된 스토리지를 수정하면 된다.

데이터센터 → 스토리지 → 백업할 스토리지 선택 후 ‘수정’ → 암호화 → 클라이언트 암호화 키 자동 생성
생성된 암호는 프린트, USB 등 안전한 여러 곳에 보관해 둔다.
(나중에 복구할 때 필요하다!)

암호화 후 백업하면 기존에 암호화되지 않은 스냅숏이랑 섞인다.
Encrypted 항목에 Mixed라고 표시된다.
일시적으로 용량은 기존의 2배가량 차지하게 된다.
모든 암호화되지 않은 스냅숏들이 prune 및 GC 되면 다시 돌아온다.
3. BackBlaze B2
가. 요금 비교
대표적인 오브젝트 스토리지 서비스 S3, Wasabi, Backblaze B2의 요금제를 비교해 보았다.
| 서비스 | 저장 요금 (월/1TB 기준) | 다운로드 요금 (1GB 기준) | 최소 보관/삭제 정책 | 특징 |
| AWS S3 Standard | 약 $23 | 복잡합. 대략 $0.09 이상 | 없음 | 비쌈. 요청 요금까지 붙음. |
| AWS S3 Glacier | 약 $4 | 복구 시 별도 요금 높음 | 90일 이내 삭제 시 요금 발생. | 장기 아카이브용. |
| Wasabi | 약 $6.99 | 무료 | 90일 이내 삭제 시 요금 발생. | 저렴. |
| Backblaze B2 | 약 $6 | 저장된 데이터 용량의 3배까지는 무료. 초과 시 GB당 $0.01 부과. | 없음 | 단순하고 예측 가능. |
S3는 기본적으로 비싸다.
스토리지 요금 외에도 API 요청, 다운로드(egress) 비용이 별도로 붙는다.
요금 정책이 지나치게 복잡한 것 같다.
Wasabi는 저렴한 편이지만 최소 보관 기간 조건이 붙는다.
S3 Glacier 계열도 저장 요금은 낮지만 조회나 복구 요청 시 요금이 크게 붙는다.
자주 백업하는 환경에서 불리하다 판단했다.
여러 측면을 종합하면 Backblaze B2가 가장 합리적이다.
요금 정책이 단순해서 예측이 쉽고, 가격도 저렴하다.
대부분의 사용자가 활용하는 기본적인 요금 모델(Pay-as-You-Go)을 바탕으로 설명하면 다음과 같다.
- 스토리지 요금
: 월 TB당 $6다. 환율 1400원 기준 8400원 정도.
: 첫 10GB는 무료임. - 업로드 요금
: 데이터를 B2에 업로드하는 비용은 무료. - 다운로드(데이터 전송) 요금
: 저장한 데이터의 월평균 저장량의 3배까지는 무료.
: 이 한도를 초과할 경우, 초과분에 대해 GB당 $0.01. - 최소 보관 기간 없음.
- API 요청 요금:
- 클래스 A:
b2_upload_file,b2_hide_file등과 같은 API 호출은 무료. - 클래스 B
:b2_download_file_by_id,b2_download_file_by_name,b2_get_file_info등과 같이 데이터를 다운로드하는 호출.
: 하루 첫 2,500회 호출까지는 무료이며, 이후 10,000회당 $0.004가 부과. - 클래스 C
:b2_list_file_names,b2_list_buckets등과 같이 메타데이터에 접근하는 호출.
: 하루 첫 2,500회 호출까지는 무료이며, 이후 1,000회당 $0.004가 부과.
- 클래스 A:
대부분의 개인 또는 소규모 기업 사용자에게는 API 호출 비용이 미미하거나 발생하지 않는다.

광고 아닙니다 🙂
다만 생각보다 업로드 속도가 느리다.
속도를 테스트해 보자.
나. Bucket 생성


아직 regex 인식 버그가 있다고 해서 Bucket 이름은 소문자로 지었다.
직접 확인해보진 않았습니다.
(출처 : https://youtu.be/iNiLr5mu864?si=G2I1-GUNrbYZXsSY&t=304)
💡2025.10.28 추가
GC와 prune이 정상 작동함에도 불구하고 GC 후에도 계속해서 용량이 증가하는 경우.
Backblaze B2는 기본적으로 object versioning이 켜져 있습니다.
PBS가 DELETE 요청을 보내도 B2는 파일을 “old version”으로 남겨둡니다.
- B2의 Web Console → Bucket Settings → Lifecycle Rules 확인
- “Keep only the last version of the file”으로 변경해야 실제 용량이 줄어듭니다.


Keep only the last version of the file 옵션 활성화
다. API Key 발급
마스터 키를 사용하는 것은 위험하므로 최소한의 권한만 부여한 새로운 키를 발급한다.
절대 유출하면 안 된다.


Application Key는 생성 당시 한 번만 보여주니깐 잘 복사해 두자.
라. Cap & Alert 설정
B2는 월별 상한선 설정 기능은 없지만, 일별 캡(Daily Cap) 기능을 전략적으로 사용하여 월 10,000원 이하로 지출을 통제할 수 있다.
1단계: 기본값 다시 확인
- 월 예산: 10,000원
- 환율: 1,400원 / USD
- 월 예산(USD): 10,000 ÷ 1,400 = 대략 $7.14
- 일일 예산: $7.142857 ÷ 30 = $0.238095… = 대략 $0.24/day
2단계: 일별 비용 배분
일별 $0.238을 세 항목(저장 / 다운로드 / 트랜잭션)으로 배분한다.
안전성과 현실성을 고려한 예시 배분은 다음과 같음.
| 일일 예산 | 이유 | |
| Class B/C 트랜잭션 | $0.01 | 일 2,500회 무료 범위가 있어 거의 요금 안 나옴. 소액만 할당해 안전망 확보. |
| Download Bandwidth | $0.02 | 다운로드가 변동성이 가장 크므로 약간의 여유를 둠. $0.02이면 유료 다운로드로 약 2GB 허용($0.01/GB). |
| Storage | $0.20 | 일일 예산 − (트랜잭션 + 다운로드) |
3단계: 저장 공간 비용 계산
- 이제 위에서 할당한 Storage 일별 예산 $0.198을 기준으로 계산한다.
- B2 저장 단가는 1GB 당 월 $0.006이고 하루에 $0.006 ÷ 30 = $0.0002 정도다.
- 따라서 하루에 저장할 수 있는 데이터량 = $0.20 ÷ $0.0002 + 무료 10GB= 대략 1000GB

결과적으로 1TB 아래로 저장 공간을 유지하면 1만 원 아래로 비용을 제한할 수 있다.
각 캡의 75%, 100% 도달 시 이메일 경고를 보낸다.
실제로 잘 지켜지는지 시간을 두고 검증할 필요가 있을 것 같다.
💡25.10.17 추가
Verify 시 모든 데이터를 Download 한다. 때문에 Verify를 사용하고 싶다면 Daily Download Bandwidth Caps를 저장할 용량만큼 허용해야 한다.
4. S3 Endpoint
공식문서에 따르면 아직 preview 단계의 기술이기 때문에 요금이 많이 발생할 수 있다고 경고한다.
그래도 최대한 요금을 줄이기 위한 노력이 엿보였다.
가. Local persistent cache 확보
성능을 높이고 백엔드에 대한 요청 수를 줄이기 위해 모든 데이터를 S3 오브젝트 스토어에 저장하더라도, 데이터스토어는 여전히 local persistent cache가 필요하다.
이를 위해 데이터스토어 생성 시, 일반 데이터스토어를 설정할 때처럼 로컬 파일시스템 경로를 지정해야 한다.
다만 일반 데이터스토어와 달리, 로컬 캐시의 크기는 제한할 수 있으며, 64 GiB에서 128 GiB 정도를 권장한다.
가장 좋은 방법은 너무 커지지 않게 전용 디스크, 파티션, 또는 쿼터가 설정된 ZFS 데이터셋을 로컬 캐시로 사용하는 것이다.
단, 기존에 존재하는 일반 데이터스토어를 로컬 캐시로 사용하는 것은 불가능하다.

당장은 PBS를 PVE 안에서 실행시키고 있는 관계로 가상의 하드디스크 64 GiB를 추가했다.



/mnt/datastore/b2_local_cache 경로를 기억해 둔다.
나. S3 Endpoint

S3 Endpoint ID
: 이 Endpoint를 구분하기 위한 PBS 내부의 ID(이름).Region
: 해당 스토리지가 속한 리전 이름.Endpoint
: 실제 S3 API 호출을 보낼 주소 템플릿.
: Backblaze B2는 일반적으로{{bucket}}.s3.{{region}}.backblazeb2.com다.Port
: 기본 HTTPS 포트443. 특별히 다른 포트를 쓰는 경우에만 수정합니다.Access Key
: S3 접근용 계정의 Access Key
: Backblaze B2에서는 “Application Key ID”에 해당.Secret Key
: S3 접근용 비밀 키 Secret Key
: Backblaze B2에서는 “Application Key”에 해당.
: 생성 당시 한 번만 보여준다.Path Style
: S3에 접근할 때 bucket 이름을 도메인에 넣을지(URL Style) 아니면 경로(Path Style) 로 넣을지 설정.Provider Quirks
: 벤더마다 약간씩 다른 S3 API 구현 차이를 해결하기 위한 옵션
: BackBlaze의 경우Skip if-None-Match-header를 선택한다.

다. Datastore 추가

Datastore Type
: S3 (tech preview)를 선택한다.Local Cache
: 앞서 생성한 Local cache의 절대 경로를 입력한다.S3 Endpoint ID
: 앞서 생성한 S3 Endpoint를 선택한다.Bucket
: Bucket을 생성할 당시 “Allow listing all bucket names ….” 옵션을 활성화해야 목록이 표시된다.
아직 Sync의 정확하게 동작을 이해하지 못했기 때문에 GC와 Prune은 비워두고 추후에 추가한다.

라. Sync 작업 추가
백업과 업로드를 동시에 수행하기엔 부담이 있기도 하고, 실패 시 모니터링도 어려울 것 같다.
일단 로컬 데이터스토어에 백업하고 후에 B2가 로컬 데이터스토어에서 Pull 하도록 했다.
즉, 먼저 PVE가 로컬 스토리지에 백업을 완료하고, 이후 Sync를 통해 B2로 안전하게 데이터를 옮기는 방식이다.
Sync 작업 주기는 백업 직후 바로 실행하는 것이 좋다고 판단했다.
Backup, Prune과 Verification이 끝나면 Sync 되도록 월, 수, 금 21:00에 Sync를 예약했다.
| mon | tue | wed | thu | fri | sat | sun | |
| Backup | 03:00 | 03:00 | 03:00 | ||||
| Prune | 09:00 | 09:00 | 09:00 | ||||
| Verify | 15:00 | 15:00 | 15:00 | ||||
| Sync | 21:00 | 21:00 | 21:00 | ||||
| GC | 03:00, 06:00 |

Local Owner: 동기화된 데이터의 소유자Max Depth: namespace 하위 구조를 몇 단계까지 동기화할지. 보통Full.Remove Vanished: Source에서 삭제된 스냅숏/백업이 Local에도 삭제되도록 동기화.Re-sync Corrupt: 손상된 chunk가 발견되면 원격에서 다시 가져옴.Verified Only: 검증된 스냅숏만 동기화.
Remove Vanished는 스냅샷 메타데이터를 맞춰주는 것일 뿐, 실제 chunk는 여전히 남아 있을 수 있음.
따라서 가져올 source datastore와 별개로 B2도 GC를 주기적으로 돌려줘야 한다.
GC는 Verfiy는 요금 나오는 것 보고서 조금씩 시도해야겠다.
💡25.10.17 추가
2주 정도 운영해 본 결과 GC 자체는 별도의 요금을 발생시키지 않는 것 같다.
local cache 덕분인지 거의 다운로드가 발생하지 않았음. 아마 읽어오지 않고 지우기만 하는 듯.
다만 Verify의 경우 업로드 용량만큼 다운로드가 발생하기 때문에 요금 압박이 있다. 최소화해야 함.
4. 요금
역시 가장 중요한 것은 안정성과 요금이다.
몇 달간 운영해 보고 스케줄을 최적화할 필요가 있다.
| Month | 요금 (USD) | 요금 (KRW) | 평균 용량 | 백업 | GC | Prune | Verify |
| 10월 | 0.57 | 819원 | 104 GB | 월,수,금 | 토 | 월,수,금 | 로컬 O, Offisite X |
| 11월 | 0.65 | 956원 | 109 GB | 월,수,금 | 토 | 월,수,금 | 로컬 O, Offisite X |
| 12월 | 0.59 | 874원 | 107 GB | 월,수,금 | 토 | 월,수,금 | 로컬 O, Offisite X |
달에 한번 정도는 Offisite에 저장된 백업도 Verify를 수행해도 될 듯 하다.

외장하드에 배드섹터가 생겼다 🙁
외장하드의 수명이 다한 거 같아서 외장 SSD로 교체했다.
