# 백업과 복원

> 셀프 호스팅 Nodaro를 명령 하나로 백업하고, 다른 명령으로 복원하고, 안전하게 다운그레이드하세요. 아카이브에 담기는 내용과 키 보호 방법을 알아보세요.

Source: https://nodaro.ai/ko/docs/self-hosting/backups

셀프 호스팅 Nodaro는 명령 하나로 **백업**하고 다른 명령 하나로 **복원**합니다. 백업 아카이브에는 스택이 다시 만들어 낼 수 없는 모든 것, 즉 데이터베이스, 내 미디어, 인스턴스 암호화 키, `.env`가 담깁니다. 데이터베이스 마이그레이션은 앞으로만 진행되므로, 복원은 다운그레이드하는 유일한 방법이기도 합니다. 이전 버전으로 돌아가려면 업데이트 전에 만든 백업을 복원해야 합니다.

## 백업에 담기는 내용
`tools/community-backup.sh`는 `tar.gz` 아카이브 하나를 씁니다.

| 아카이브 안의 파일 | 내용 |
| --- | --- |
| `db.dump` | pg_dump의 사용자 지정 형식으로 저장한 Postgres: 워크플로, 사용자, 작업, 미디어 레코드 |
| `minio-data.tar` | 내가 생성한 미디어: 이미지, 동영상, 오디오 |
| `encryption-key` | 공급자 키와 소셜 로그인 토큰을 암호화하는 인스턴스 키. **이 키 없이 복원한 데이터베이스에는 아무도 읽을 수 없는 행만 남습니다.** |
| `env` | 내 `.env`: 공급자 키와 시크릿 |
| `manifest.json` | 복원 스크립트가 쓰는 앱 버전과 백업 시각 |

Redis는 의도적으로 제외합니다. 수명이 짧은 작업 상태만 들어 있기 때문입니다.

**아카이브는 자격 증명입니다:** 
아카이브에는 내 `.env`와 암호화 키가 들어 있습니다. 스크립트는 파일 접근 권한을 소유자로 제한합니다(`chmod 600`). 이 상태를 유지하고, 아카이브를 비밀번호처럼 보관하세요. Windows에서는 `chmod`가 실제로 효과가 없습니다. 파일을 동기화 폴더나 공유 드라이브에 두지 말고, 다른 사람도 그 컴퓨터를 쓴다면 NTFS 권한으로 접근을 제한하세요.

## 백업 만들기
`docker-compose.community.yml`이 있는 설치 디렉터리에서, 스택이 **실행 중인** 상태로 실행하세요.

```bash
tools/community-backup.sh
# -> ./backups/nodaro-backup-<date>-v<version>.tar.gz
```

| 옵션 | 동작 |
| --- | --- |
| `tools/community-backup.sh /path/to/backups` | 아카이브를 다른 디렉터리에 씁니다 |
| `COMPOSE_FILE=my-compose.yml tools/community-backup.sh` | 다른 이름의 Compose 파일을 사용합니다 |

스크립트는 아카이브에 들어간 내용을 출력합니다. 암호화 키가 없으면 이를 눈에 띄게 알리고 오류와 함께 종료하므로, 예약된 작업도 이를 알아챌 수 있습니다. 그런 아카이브로는 공급자 키를 복원할 수 없습니다.

데이터베이스 덤프는 항상 일관성이 있습니다. 백업이 진행되는 동안 기록된 미디어는 아카이브에서 빠질 수 있습니다. 미디어 스냅숏의 일관성을 보장하려면 먼저 앱을 중지하세요.

```bash
docker compose -f docker-compose.community.yml stop nodaro
```

**Windows에서는** Git for Windows가 설치하는 셸인 **Git Bash**에서 스크립트를 실행하세요. PowerShell과 WSL의 bash는 컨테이너 경로를 망가뜨립니다.

### 백업 시기
첫 번째 숫자가 바뀌는 **메이저** 버전으로 업데이트하기 전마다, 그리고 데이터의 중요도에 맞는 주기로 백업하세요. cron 한 줄을 그대로 쓸 수 있습니다.

```bash
0 3 * * * cd /path/to/install && tools/community-backup.sh >> backup.log 2>&1
```

## 백업 복원
```bash
tools/community-restore.sh backups/nodaro-backup-<date>-v<version>.tar.gz
```

복원은 데이터베이스와 미디어를 아카이브의 내용으로 바꾸므로, 무엇이든 건드리기 전에 `RESTORE`를 입력하라고 요청합니다. 그다음 스크립트는 다음을 수행합니다.

1. 앱과 데이터베이스 클라이언트인 `auth`와 `rest`를 중지합니다. 이들의 열린 연결이 복원을 막기 때문입니다.
2. Postgres를 복원하고, 종료 코드를 믿는 대신 실제로 작동하는지 확인합니다. Supabase 이미지가 내보내는 무해한 메시지 몇 개는 예상된 것이며 그대로 출력됩니다.
3. 미디어를 복원하고, 버킷이 돌아왔는지와 MinIO가 정상인지 확인합니다. 그다음 암호화 키를 복원하고 볼륨에서 키의 크기를 확인합니다. 그다음 기존 `.env`가 있으면 따로 보관한 뒤 내 `.env`를 복원합니다. 확인에 실패하면 앱이 시작되기 **전에** 스크립트가 멈춥니다. 올바른 키 없이 시작하면 새 키가 만들어지고, 복원된 공급자 키를 영영 읽을 수 없게 되기 때문입니다.
4. 모든 것을 다시 시작하고 앱 자체의 상태 확인을 기다립니다. 스크립트는 앱이 실행된 뒤에만 성공을 보고하고, 그렇지 않으면 오류와 함께 종료합니다.

완료되면 `http://localhost:3000/setup`을 여세요. 모든 카드가 초록색이어야 합니다.

## 버전 다운그레이드
마이그레이션 롤백은 없습니다. 이전 버전으로 돌아가려면 다음과 같이 하세요.

1. 위와 같이 업데이트 **전에** 만든 백업을 복원합니다.
2. `NODARO_IMAGE`나 `docker-compose.community.yml`에서 이전 이미지를 고정합니다. 예: `ghcr.io/nodaroai/nodaro-community:v1.25.1`. 정확한 `vX.Y.Z` 태그는 절대 바뀌지 않습니다.
3. `docker compose -f docker-compose.community.yml up -d nodaro`를 실행합니다.

태그는 [업데이트](https://nodaro.ai/docs/self-hosting/updating)를 참고하세요.

## 관리형 배포 백업
Compose 스택 밖에서는 네 가지가 상태를 보관합니다.

| 대상 | 보호 방법 |
| --- | --- |
| **Supabase Postgres**: 워크플로, 프로필, 작업, 미디어 레코드 | 유료 요금제에서 Supabase의 특정 시점 복구를 쓰거나, `pg_dump`를 정기적으로 실행하세요. 가장 중요한 백업입니다. |
| **스토리지 버킷**: 생성한 이미지, 동영상, 오디오 | 삭제된 파일을 복구할 수 있도록 버킷 버전 관리와 긴 수명 주기 규칙을 켜세요. 재해 복구가 필요하면 리전 간 복제를 추가하세요. |
| **Redis** | 백업할 것이 없습니다. 수명이 짧은 작업 상태만 들어 있습니다. Redis를 잃으면 진행 중인 실행은 실패하고, 나머지는 모두 다음 시작 때 Postgres에서 복구됩니다. |
| **인스턴스 암호화 키**, `NODARO_ENCRYPTION_KEY` | Postgres 백업과 함께 보관하세요. 이 키가 없으면 복원된 공급자 키, 소셜 로그인 토큰, Webhook 출력 자격 증명 행을 읽을 수 없습니다. 이때 타일에는 `missing`이 표시되고 키를 다시 입력해야 하지만, 다른 것은 망가지지 않습니다. |

마이그레이션이나 복구 중에 Postgres가 중단되면, API는 데이터베이스에 연결할 수 있을 때까지 재시작을 반복합니다. Postgres가 돌아오면 Nodaro 컨테이너를 재시작하세요.

## 문제 해결
- **`the db service is not running`.** 먼저 스택을 시작하세요: `docker compose -f docker-compose.community.yml up -d`.
- **복원 후 공급자 키가 `missing`으로 표시됩니다.** 데이터베이스가 짝이 맞는 `encryption-key` 없이, 또는 다른 키와 함께 복원되었습니다. 키가 들어 있는 아카이브에서 복원하거나 `/setup`에서 키를 다시 입력하세요.
- **복원 검증에 실패했습니다.** 스크립트는 반쯤 복원된 데이터베이스를 조용히 남겨 두지 않습니다. 복원을 다시 실행하세요. 계속 실패하면 아카이브가 잘렸을 수 있으니 원본과 크기를 비교하세요.
- **Windows에서 백업 중 `could not read the encryption key`가 나타납니다.** Git Bash에서 실행하지 않았거나 앱 컨테이너가 실행 중이 아닙니다. 스택을 실행한 상태로 Git Bash에서 백업을 다시 실행하세요. 스크립트가 경고한 아카이브는 쓸 수 있는 백업이 아닙니다.
- **`media restore verification FAILED` 또는 `encryption key verification FAILED`가 나타납니다.** 스크립트가 의도적으로 멈추고 앱을 시작하지 않았습니다. 스크립트가 알려 준 볼륨을 확인하고, 대개 중지된 컨테이너나 가득 찬 디스크인 원인을 해결한 뒤 복원을 다시 실행하세요. 반복해도 안전합니다.

## 자주 묻는 질문

### 셀프 호스팅 Nodaro는 어떻게 백업하나요?

스택이 실행 중인 상태에서 설치 디렉터리에서 tools/community-backup.sh를 실행하세요. 데이터베이스, 미디어, 인스턴스 암호화 키, .env를 담은 아카이브 하나를 ./backups에 씁니다.

### 백업은 어떻게 복원하나요?

아카이브 경로를 지정해 tools/community-restore.sh를 실행하세요. 복원은 기존 데이터를 덮어쓰므로 먼저 RESTORE를 입력하라고 요청합니다. 앱을 다시 시작하기 전에 데이터베이스, 미디어, 암호화 키를 검증합니다.

### 복원 후 공급자 키가 누락됨으로 표시되는 이유는 무엇인가요?

데이터베이스가 짝이 맞는 암호화 키 없이 복원되었기 때문입니다. 키가 들어 있는 아카이브에서 복원하거나 /setup에서 키를 다시 입력하세요. 다른 것은 망가지지 않습니다.

### Redis도 백업해야 하나요?

아니요. Redis에는 수명이 짧은 작업 상태만 들어 있습니다. Redis를 잃으면 진행 중인 실행은 실패하고, 나머지는 모두 다음 시작 때 데이터베이스에서 복구됩니다.

### Windows에서 백업 스크립트를 실행할 수 있나요?

네. Git for Windows가 설치하는 셸인 Git Bash에서 실행하세요. PowerShell과 WSL의 bash는 컨테이너 경로를 망가뜨리고, 그러면 암호화 키가 아카이브에서 빠집니다.
