> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nora.my/llms.txt
> Use this file to discover all available pages before exploring further.

# 에어갭 tarball

> 인터넷이 없는 머신에 Nora 를 설치합니다. 모든 컨테이너 이미지가 하나의 아카이브에 담겨 있습니다.

에어갭 tarball 은 **인터넷이 전혀 닿지 않는** 호스트에서 Nora 를 설치하기 위한 자기 완결 아카이브입니다. 다섯 개 서비스 이미지는 `docker save` 로 함께 구워져 있어 `install.sh` 는 레지스트리를 건드리지 않습니다.

## tarball 구성

tarball 은 `infra/onprem/build-tarball.sh` 가 만들고 이름은 `nora-onprem-<version>.tar.gz` 입니다. 안에는 다음 파일들이 들어 있습니다.

| 파일 | 용도 |
| - | - |
| `docker-images.tar` | 다섯 개 서비스 이미지의 `docker save` 출력 |
| `docker-compose.yml` | 온라인 설치와 동일한 compose 파일 |
| `.env.example` | `CHANGE_ME` sentinel 이 든 env 템플릿 |
| `install.sh` | `docker load` 를 실행하고 다음 단계 안내를 프린트합니다 |
| `README.md` | 한 페이지 설치 가이드 |
| `VERSION` | tarball 파일명과 일치하는 릴리스 태그 |

## 타겟 호스트 사전 조건

* **Docker Engine 20.10+** (`docker --version`).
* **Docker Compose plugin** (`docker compose version`).
* **디스크 여유 약 15 GB** — 이미지를 담을 공간.
* **Docker 에 4 GB RAM 이상 할당.**

레포 접근이나 `docker pull`, 패키지 다운로드는 타겟 호스트에 필요하지 않습니다.

## 설치

<Steps>
  <Step title="tarball 압축 해제">
    ```bash theme={null}
    tar -xzf nora-onprem-<version>.tar.gz -C /opt/nora
    cd /opt/nora
    ```
  </Step>

  <Step title="인스톨러 실행">
    ```bash theme={null}
    ./install.sh
    ```

    스크립트가 하는 일은 딱 세 가지입니다. 그 이상은 없고, 포트를 바인딩하지도 않습니다.

    1. 다섯 개 서비스 이미지를 로컬 Docker 데몬에 load 합니다 (`pgvector`, `redis`, `qdrant`, `nora-server`, `nora-llm-bridge`).
    2. `.env.onprem` 이 존재하지 않을 때만 `.env.example` 을 복사합니다 (업그레이드에 안전하게 재실행 가능).
    3. 다음 단계 안내를 프린트합니다.

    `--dry-run` 을 붙이면 Docker 를 건드리지 않고 미리보기만 합니다.
  </Step>
</Steps>

## 설정

`/opt/nora/.env.onprem` 을 열고 배포에 필요한 값을 넣습니다.

* **필수 — `POSTGRES_PASSWORD`.** 번들된 Postgres 컨테이너의 superuser 비밀번호입니다. `CHANGE_ME_*` placeholder 가 남아 있으면 compose 가 부팅을 거절합니다.
* **권장 — `NORA_LICENSE_FILE`.** Nora sales 에서 받은 라이선스 JSON 파일의 경로입니다. 파일을 `.env.onprem` 옆에 두고 경로를 지정하세요. 없으면 Nora 가 **free tier** (워크스페이스 1, 플로우 3, 하루 100 실행) 로 돕니다.
* **권장 — `NORA_AIRGAP=1`.** 부팅 프로브를 활성화합니다. 서버가 부팅 시점에 공용 인터넷에 여전히 닿을 수 있으면 exit 78 로 종료하므로, 잘못 설정된 egress 규칙이 격리를 조용히 깨지 않도록 방지합니다.
* **선택 — SSO · OAuth 페어** (`GOOGLE_OAUTH_CLIENT_ID/_SECRET`, `GITHUB_OAUTH_CLIENT_ID/_SECRET`). 네트워크가 프로바이더의 OAuth endpoint 에 닿을 수 있을 때만 유용합니다. 완전 에어갭 설치라면 비워 두세요 — 로컬 email + password 계정은 그대로 동작합니다.

## 부팅

```bash theme={null}
cd /opt/nora
docker compose --env-file .env.onprem up -d
```

스택은 `http://localhost:${NORA_HOST_PORT:-8090}` 에서 listen 합니다. 기본값이 `NORA_RUN_MIGRATIONS=1` 이므로 첫 부팅에서 SQL 마이그레이션이 자동으로 실행됩니다.

## 업그레이드

새 tarball 이 도착하면 현재 설치 옆에 압축을 풀고 `install.sh` 를 재실행합니다. 이미지 태그가 앞으로 이동하고 compose 가 재적용되며 DB 마이그레이션은 additive 입니다.

```bash theme={null}
tar -xzf nora-onprem-<newver>.tar.gz -C /opt/nora
cd /opt/nora
./install.sh
docker compose --env-file .env.onprem up -d
```

데스크톱 앱 운영자는 **Nora → \[Import Update…]** 로 같은 일을 합니다. [업데이트](/ko/local-app/desktop/updates) 를 참고하세요.

## 언인스톨 · 리셋

```bash theme={null}
cd /opt/nora
docker compose --env-file .env.onprem down -v
```

`-v` 가 Postgres 와 Qdrant 볼륨을 드랍합니다 — 워크스페이스, 사용자, 플로우, 벡터 인덱스가 모두 사라집니다. `-v` 없이 실행하면 `up` · `down` 사이에 데이터가 유지됩니다.

## 지금 버전 확인

```bash theme={null}
cat /opt/nora/VERSION
```

태그는 tarball 파일명과 같습니다. 실행 중인 SPA 의 **Settings → About** 에서도 확인할 수 있습니다.

## 문제 해결

서버 로그를 follow 합니다.

```bash theme={null}
docker compose -f /opt/nora/docker-compose.yml --env-file /opt/nora/.env.onprem \
  logs -f nora-server
```

첫 설치에서 흔한 실패 원인:

* **`POSTGRES_PASSWORD` 가 아직 `CHANGE_ME_*` placeholder 상태.** compose 가 start 전에 exit 합니다.
* **`NORA_LICENSE_FILE` 경로가 없거나 Docker 가 읽지 못함.** 서버가 missing path 를 로그에 남기고 free tier 로 떨어집니다. 워크스페이스를 두 개 이상 만들려 하면 거절됩니다.
* **호스트 포트 8090 이 이미 점유되어 있음.** `.env.onprem` 의 `NORA_HOST_PORT` 를 다른 값으로 바꿉니다.
* **`NORA_AIRGAP=1` 인데 egress 가 실제로 막혀 있지 않음.** 서버가 exit 78 로 종료합니다. 방화벽 규칙을 고치고 다시 부팅하세요.

## tarball 빌드 (릴리스 엔지니어)

Docker 데몬이 도는 호스트에서 플랫폼 레포로부터:

```bash theme={null}
./infra/onprem/build-tarball.sh                       # 태그 = git SHA
NORA_IMAGE_TAG=1.2.3 ./infra/onprem/build-tarball.sh  # semver 릴리스
```

결과물은 `dist/nora-onprem-<version>.tar.gz` 로 떨어집니다. 첫 빌드는 Rust 이미지 때문에 약 30 분 걸리고, warm 캐시로 재빌드하면 훨씬 빠릅니다.

## 관련

<CardGroup cols={2}>
  <Card title="Docker Compose" icon="docker" href="/ko/local-app/deploy/compose">
    같은 compose 파일의 온라인 버전.
  </Card>

  <Card title="Kubernetes (Helm)" icon="dharmachakra" href="/ko/local-app/deploy/kubernetes">
    tarball 이미지를 프라이빗 레지스트리에 load 한 뒤 차트 값을 오버라이드합니다.
  </Card>
</CardGroup>
