From 6085c6b186495b6869e034c13f5e7316686c0757 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Thu, 9 Apr 2026 23:57:40 +0000 Subject: [PATCH] =?UTF-8?q?PBS=20=EA=B5=AC=EC=B6=95=E2=86=92=EC=99=B8?= =?UTF-8?q?=EB=B6=80=EB=85=B8=EC=B6=9C=E2=86=92=EB=B0=B1=EC=97=85=E2=86=92?= =?UTF-8?q?=EB=B3=B5=EC=9B=90=20=EC=A0=84=EC=B2=B4=20=EA=B0=80=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PBS LXC 구축 (물리 디스크 마운트, Tailscale, 듀얼 NIC) - OPNsense Caddy API로 pbs.medivault.co.kr 외부 노출 - Fingerprint 이슈: Caddy 경유 시 Let's Encrypt 인증서 fingerprint 사용 필수 - 실측 백업 속도: CT 110MB/s, VM 115MiB/s (OPNsense 경유) - 외부 약국(태령) 120GB VM 백업 17분 - CT 복원: 다른 VMID로 복원 + 충돌 주의사항 - 디스크 이식성: ext4 디스크 분리 후 다른 서버에서 재사용 가능 - Headscale IP 고정 할당 방법 (DB 직접 수정) Co-Authored-By: Claude Opus 4.6 (1M context) --- pbs-setup-backup-restore.md | 360 ++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 pbs-setup-backup-restore.md diff --git a/pbs-setup-backup-restore.md b/pbs-setup-backup-restore.md new file mode 100644 index 0000000..4bd0f85 --- /dev/null +++ b/pbs-setup-backup-restore.md @@ -0,0 +1,360 @@ +# PBS 구축 → 외부 노출 → 백업 → 복원 전체 가이드 + +> 날짜: 2026-04-09 +> 환경: Proxmox VE 9, PBS 3.4.8, OPNsense Caddy, Headscale VPN + +## 1. 전체 아키텍처 + +``` +[아산힐링탑 PVE2] [pqserver (Dell R740)] + CT 201 (shc) ──────┐ CT 130 (PBS) + CT 200 (dev) ──────┤ 백업 ├── /mnt/datastore (sdb1, 931GB) + CT 106 (neo4j)──────┤──────────→ │ + │ │ +[태령약국 PVE] │ │ 복원 + VM 201 (SERVER)─────┘ └──────→ CT 400, 401, 402 + (pqserver local-lvm) + +경로: + 약국 PVE → 인터넷 → pbs.medivault.co.kr (OPNsense Caddy) + → 192.168.1.130:8007 (PBS CT) + → /mnt/datastore/backups (sdb1 물리 디스크) +``` + +## 2. PBS LXC 구축 (pqserver) + +### 2-1. 물리 디스크 확인 + 마운트 + +```bash +# 미사용 디스크 확인 +lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE +# → sdb 931G, sdb1 ext4, 마운트 안 됨 + +# 기존 데이터 확인 (goodpharm 627MB — 보존) +mkdir -p /mnt/pbs-disk +mount /dev/sdb1 /mnt/pbs-disk +ls /mnt/pbs-disk/ # goodpharm/ 확인 + +# fstab 영구 마운트 +echo 'UUID=2e087ebd-e0bc-437f-b3b2-5c77dd33ad3e /mnt/pbs-disk ext4 defaults 0 2' >> /etc/fstab + +# PBS 데이터스토어 디렉토리 생성 +mkdir -p /mnt/pbs-disk/backups +``` + +### 2-2. LXC 생성 + +```bash +pct create 130 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \ + --hostname pbs-local \ + --cores 2 --memory 1024 \ + --rootfs local-lvm:8 \ + --net0 name=eth0,bridge=vmbr0,ip=dhcp \ + --nameserver 8.8.8.8 \ + --password 'trajet6640' \ + --unprivileged 0 \ + --features nesting=1 +``` + +**주의**: PBS LXC는 `--unprivileged 0` (privileged). 백업/복원에 root 권한 필요. + +### 2-3. TUN 디바이스 (Tailscale용) + +```bash +# CT 중지 상태에서 +echo 'lxc.cgroup2.devices.allow: c 10:200 rwm' >> /etc/pve/lxc/130.conf +echo 'lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file' >> /etc/pve/lxc/130.conf +``` + +### 2-4. sdb1 마운트 포인트 연결 + +```bash +pct set 130 -mp0 /mnt/pbs-disk/backups,mp=/mnt/datastore +pct start 130 +# 확인 +pct exec 130 -- df -h /mnt/datastore +# → /dev/sdb1 916G 627M 869G 1% /mnt/datastore +``` + +### 2-5. Tailscale 설치 + Headscale 등록 + +```bash +pct exec 130 -- bash -c ' +apt-get update -qq && apt-get install -y curl +curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null +curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list >/dev/null +apt-get update -qq && apt-get install -y tailscale +systemctl enable --now tailscaled +tailscale up --login-server=http://head.pharmq.kr \ + --authkey= \ + --accept-routes --accept-dns=false \ + --hostname=pbs-pqserver +' +``` + +### 2-6. IP 고정 할당 (100.64.0.100) + +Headscale은 순차 IP 할당이라 원하는 IP를 직접 지정 불가. +**DB 직접 수정** 방식: + +```bash +# 1. Headscale Docker 중지 +docker stop headscale + +# 2. SQLite DB에서 IP 변경 +sqlite3 /srv/headscale-tailscale-replacement/data/db.sqlite \ + "UPDATE nodes SET ipv4 = '100.64.0.100' WHERE given_name = 'pbs-pqserver';" + +# 3. Headscale 재시작 +docker start headscale + +# 4. CT에서 tailscaled 재시작 (새 IP 반영) +pct exec 130 -- systemctl restart tailscaled +pct exec 130 -- tailscale ip -4 +# → 100.64.0.100 +``` + +### 2-7. 듀얼 NIC (OPNsense 외부 노출용) + +```bash +# pqserver 브릿지 확인: vmbr0=192.168.0.x(ipTIME), vmbr1=WAN 직결 +# 다른 CT 참고: net1은 vmbr0에 192.168.1.x 고정 IP + +pct set 130 -net1 name=eth1,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.130/24,type=veth +pct reboot 130 +``` + +속도 비교: +| NIC | 경로 | Download | Upload | +|-----|------|----------|--------| +| eth0 (192.168.0.3) | ipTIME | 34 Mbps | 302 Mbps | +| eth1 (192.168.1.130) | **OPNsense** | **123 Mbps** | 321 Mbps | + +### 2-8. PBS 설치 + +```bash +pct exec 130 -- bash -c ' +apt-get install -y curl wget gnupg2 +wget -qO /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg \ + https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg +echo "deb http://download.proxmox.com/debian/pbs bookworm pbs-no-subscription" \ + > /etc/apt/sources.list.d/pbs.list +apt-get update +DEBIAN_FRONTEND=noninteractive apt-get install -y proxmox-backup-server +' +``` + +### 2-9. 데이터스토어 생성 + 비밀번호 설정 + +```bash +pct exec 130 -- bash -c ' +proxmox-backup-manager datastore create pbs-local /mnt/datastore/backups +echo "root:trajet6640" | chpasswd +' +# 인증 테스트 +curl -sk -d "username=root@pam&password=trajet6640" \ + https://100.64.0.100:8007/api2/json/access/ticket +``` + +### 최종 PBS 정보 + +| 항목 | 값 | +|------|-----| +| CT VMID | 130 | +| hostname | pbs-local | +| LAN IP | 192.168.0.3 (ipTIME) | +| OPNsense IP | 192.168.1.130 | +| VPN IP | 100.64.0.100 | +| 웹 UI | https://pbs.medivault.co.kr (외부) | +| 인증 | root@pam / trajet6640 | +| 데이터스토어 | pbs-local (869GB) | +| 디스크 | /dev/sdb1 (931GB, ext4) | + +## 3. OPNsense Caddy로 외부 도메인 노출 + +### 3-1. OPNsense Caddy API로 리버스프록시 추가 + +OPNsense는 GUI로 Caddy 관리. **Caddyfile 직접 수정 금지** (GUI 저장 시 덮어씀). + +API 사용 (opnsense-admin MCP): + +```python +from opnsense_api import OPNsense +op = OPNsense() + +# 리버스프록시 추가 +op.caddy_add_reverse_proxy('pbs.medivault.co.kr', '192.168.1.130', 8007) + +# TLS insecure 설정 (PBS 자체 서명 인증서) +handles = op.get('caddy/ReverseProxy/searchHandle') +for h in handles['rows']: + if '192.168.1.130' in h.get('ToDomain', ''): + op.post(f'/api/caddy/reverse_proxy/setHandle/{h["uuid"]}', { + 'handle': {'HttpTls': '1', 'HttpTlsInsecureSkipVerify': '1'} + }) + +# Caddy 재적용 +op.caddy_reconfigure() +``` + +### 3-2. OPNsense Caddy TLS 특성 + +| 항목 | pharmq.kr Caddy (LXC 103) | OPNsense Caddy | +|------|---------------------------|----------------| +| TLS 챌린지 | **DNS-01** (Cloudflare API) | **HTTP-01** (Let's Encrypt) | +| 와일드카드 | ✅ `*.pharmq.kr` | ❌ 불가 | +| 서브도메인 | 자동 (와일드카드) | **개별 등록 필수** | +| 도메인 | `*.pharmq.kr` | `*.medivault.co.kr` (개별) | + +### 3-3. Cloudflare DNS + +`pbs.medivault.co.kr` → `59.30.154.182` (OPNsense 공인 IP) +- ⚠️ **프록시 모드: DNS only** (회색 구름) — HTTP-01 인증서 발급에 필요 + +## 4. Fingerprint 이슈 (핵심 트러블슈팅) + +### 문제 + +PVE에서 PBS를 `pbs.medivault.co.kr:443`으로 등록할 때: + +```bash +pvesm add pbs PBS-PQ \ + --server pbs.medivault.co.kr --port 443 \ + --fingerprint 83:86:78:49:... # PBS 자체 인증서 fingerprint +# → 에러: fingerprint '2D:30:06:82:...' not verified, abort! +``` + +### 원인 + +``` +PVE → HTTPS → Caddy (Let's Encrypt 인증서) → HTTPS → PBS (자체 서명 인증서) + ↑ ↑ + PVE가 보는 인증서 PBS 자체 인증서 + = Caddy 인증서 = 다른 fingerprint +``` + +PVE가 연결할 때 보는 인증서는 **Caddy의 Let's Encrypt 인증서**이지, PBS 자체 인증서가 아님. +따라서 **Caddy 인증서의 fingerprint**를 사용해야 함. + +### 해결 + +```bash +# Caddy(Let's Encrypt) 인증서 fingerprint 가져오기 +echo | openssl s_client -connect pbs.medivault.co.kr:443 2>/dev/null | \ + openssl x509 -fingerprint -sha256 -noout | sed 's/.*=//' +# → 2D:30:06:82:5D:F7:66:1F:5A:91:01:CD:F6:9B:AB:E4:... + +# 이 fingerprint로 PVE에 등록 +pvesm add pbs PBS-PQ \ + --server pbs.medivault.co.kr --port 443 \ + --datastore pbs-local \ + --username root@pam --password trajet6640 \ + --fingerprint 2D:30:06:82:5D:F7:66:1F:... +``` + +### ⚠️ 주의: Let's Encrypt 인증서 갱신 시 + +Let's Encrypt 인증서는 90일마다 자동 갱신. 갱신되면 **fingerprint가 바뀜**. +→ 모든 PVE에서 PBS 스토리지 재등록 필요. + +대안: +- VPN(Tailscale) 경유로 직접 연결하면 PBS 자체 인증서 사용 → fingerprint 고정 +- Caddy에서 고정 인증서 사용 (권장하지 않음) + +## 5. 약국 PVE에서 PBS 등록 + 백업 + +### 5-1. PBS 등록 + +```bash +# Caddy fingerprint 가져오기 +FINGERPRINT=$(echo | openssl s_client -connect pbs.medivault.co.kr:443 2>/dev/null | \ + openssl x509 -fingerprint -sha256 -noout | sed 's/.*=//') + +# PVE에 PBS 스토리지 추가 +pvesm add pbs PBS-PQ \ + --server pbs.medivault.co.kr \ + --port 443 \ + --datastore pbs-local \ + --username root@pam \ + --password trajet6640 \ + --fingerprint "$FINGERPRINT" + +# 확인 +pvesm status -storage PBS-PQ +``` + +### 5-2. 백업 + +```bash +# CT 백업 +vzdump 201 --storage PBS-PQ --mode snapshot --compress zstd \ + --notes-template 'CT201-백업설명' + +# VM 백업 +vzdump 201 --storage PBS-PQ --mode snapshot --compress zstd \ + --notes-template 'VM201-SERVER-백업설명' +``` + +### 5-3. 실측 백업 속도 + +| 소스 | 대상 | 크기 | 시간 | 속도 | 경로 | +|------|------|------|------|------|------| +| 힐링탑 CT 201 | PBS-PQ | 1.8 GiB | 2분 6초 | ~110 MB/s | OPNsense 직접 | +| 힐링탑 CT 106 | PBS-PQ | ~1 GiB | ~2분 | ~110 MB/s | OPNsense 직접 | +| 힐링탑 CT 200 | PBS-PQ | ~10 GiB | 9분 11초 | ~120 MB/s | OPNsense 직접 | +| 태령약국 VM 201 | PBS-PQ | 120 GiB | 17분 27초 | ~115 MiB/s | 인터넷 직접 | + +## 6. 복원 + +### 6-1. CT 복원 (다른 VMID로) + +```bash +# PBS 백업 목록 확인 +pvesm list PBS-Local --content backup | grep 'ct/' + +# CT 201 백업 → CT 401로 복원 +pct restore 401 PBS-Local:backup/ct/201/2026-04-09T15:19:55Z \ + --storage local-lvm --unprivileged 1 + +# 확인 +pct status 401 +pct config 401 +``` + +### 6-2. 복원 시 주의사항 + +- **hostname 충돌**: 원본과 같은 hostname으로 복원됨 → 시작 전 변경 필요 +- **네트워크 충돌**: 같은 DHCP 환경이면 IP 충돌 가능 → 고정 IP 설정 권장 +- **Tailscale 충돌**: 원본과 동시에 Tailscale 실행하면 충돌 → 복원된 CT에서 `tailscale logout` 후 재등록 + +### 6-3. 실제 복원 결과 + +``` +pqserver에 복원된 CT: + CT 400 ← ct/200 (ubuntu-dev, DEV) 14 GiB + CT 401 ← ct/201 (ubuntu-test, shc) 3.5 GiB + CT 402 ← ct/106 (neo4j) 1.9 GiB +``` + +## 7. 디스크 이식성 + +sdb1(ext4)에 PBS 데이터스토어가 만들어져있으므로: + +1. pqserver에서 sdb 물리적으로 분리 +2. 다른 서버에 장착 +3. `mount /dev/sdX1 /mnt/datastore` +4. PBS에서 데이터스토어 등록: `proxmox-backup-manager datastore create pbs-local /mnt/datastore/backups` +5. 기존 백업 데이터 모두 인식됨 + +**PBS 메타데이터가 디스크 안에 저장**되므로 서버가 바뀌어도 데이터 유실 없음. + +## 8. 관련 파일/설정 위치 + +| 항목 | 위치 | +|------|------| +| PBS CT 설정 | pqserver `/etc/pve/lxc/130.conf` | +| PBS 데이터스토어 | `/mnt/pbs-disk/backups` (sdb1) | +| PVE fstab | pqserver `/etc/fstab` (sdb1 마운트) | +| Headscale DB | `/srv/headscale-tailscale-replacement/data/db.sqlite` | +| OPNsense Caddy | OPNsense GUI → Services → Caddy | +| opnsense-admin | `/srv/opnsense-admin/` (API 클라이언트) |