SnapOtter는 파일을 전적으로 사용자의 인프라에서 처리한다. 프로젝트 개선에 도움이 되도록 익명의, 콘텐츠 없는 제품 애널리틱스와 크래시 리포트를 기본으로 전송한다. 사용자의 파일, 파일 이름, 파일 내용, OCR 출력, 이미지 메타데이터, 문서 텍스트는 절대 전송하지 않는다. 선택적 피드백은 사용자가 제출한 뒤에만, 애널리틱스가 활성화된 경우에만 전송되며, 연락처 필드는 명시적 연락 동의가 있을 때만 포함된다. 관리자는 Settings > System > Privacy에서 리빌드 없이 원클릭으로 애널리틱스와 피드백 수집을 끌 수 있다. 파일 처리는 항상 컨테이너 안에 머문다.
컨테이너는 최소 필수 집합을 제외한 모든 Linux 기능(capability)을 제거한 전용 비root 사용자(`snapotter`)로 실행된다. 전체 취약점 공개 정책과 보안 아키텍처는 GitHub의 [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md)를 참고하라.
표준 [CPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) 및 [GPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose-gpu.yml) Compose 파일이 정보의 소스입니다. 축약된 예제를 프로덕션에 복사하지 마십시오. 확인한 릴리스 태그에서 파일을 배포합니다.
- 모든 서비스는 모든 Linux 기능을 삭제합니다. 애플리케이션은 볼륨 소유권, 단방향 `gosu` ID 삭제 및 정상적인 신호 전달을 위해 `CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL`만 다시 추가합니다. PostgreSQL 및 Redis는 공식 진입점에 필요한 하위 집합만 받습니다.
-`security_opt: [no-new-privileges:true]`는 애플리케이션, PostgreSQL 및 Redis 컨테이너의 프로세스가 추가 권한을 얻지 못하도록 방지합니다. 이는 `gosu`와의 호환성을 유지합니다. 진입점은 루트로 시작하고 볼륨을 준비하며 전용 `snapotter` 사용자에게만 전달됩니다.
- PostgreSQL 및 Redis 이미지 입력은 다이제스트에 의해 고정됩니다. 마찬가지로 애플리케이션은 `latest`가 아닌 확인된 릴리스 태그 또는 다이제스트에 고정되어야 합니다.
- 상태 확인, 제한된 JSON 로그 회전, 내구성 있는 Redis AOF 및 다시 시작 정책이 정식 파일에 중앙에서 정의됩니다.
PUID/PGID 재매핑은 시작 시 `/etc/passwd` 및 `/etc/group`에 쓰기 때문에 `read_only: true`가 설정되지 않았습니다. PUID/PGID 대신 Docker의 `--user` 플래그 또는 Kubernetes `runAsUser`를 사용하는 경우 읽기 전용 루트 파일 시스템을 안전하게 활성화할 수 있습니다.
파일 처리는 로컬이지만 기본 설치는 **송신 방지 시스템이 아닙니다**. 원격 측정이 활성화된 경우 익명 제품 분석은 PostHog를 사용하고 충돌 보고는 Sentry를 사용합니다. `SNAPOTTER_TELEMETRY=0`를 설정하거나 설정 > 시스템 > 개인 정보 보호에서 분석을 비활성화하여 둘 다 끄십시오. SnapOtter에는 해당 이벤트에 업로드된 파일, 파일 이름, OCR 출력, 문서 텍스트 또는 기타 파일 콘텐츠가 포함되지 않습니다.
기타 아웃바운드 트래픽은 기능 중심입니다. AI 번들/모델 설치는 서명된 릴리스 입력을 다운로드합니다. URL 가져오기는 사용자가 요청한 공개 URL을 가져옵니다. 명시적으로 구성된 OIDC, SAML, OpenTelemetry, 웹훅, S3 호환 스토리지 또는 유사한 통합은 관리자가 선택한 대상에 연결됩니다. 런타임 모델 다운로드는 기본적으로 비활성화되어 있습니다. 자동 대체 다운로드를 명시적으로 사용하려는 경우에만 `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=1`을 설정하세요. [오프라인 번들 가져오기](/ko/guide/deployment)는 런타임 모델 송신 없이 AI 기능을 프로비저닝할 수 있습니다.
|에어 갭|`SNAPOTTER_TELEMETRY=0` 및 `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0` 설정, 오프라인 AI 번들 가져오기 사용, URL 가져오기 및 외부 통합 비활성화, 송신 차단|
|기본 원격 측정|브라우저/네트워크 로그에 나열된 PostHog 및 Sentry 엔드포인트를 허용하십시오. 정책에서 허용하지 않는 경우 원격 측정을 비활성화합니다.|
|AI 번들이 필요함|설치 중에 HTTPS를 `huggingface.co, *.xethub.hf.co, cdn-lfs.huggingface.co, github.com, objects.githubusercontent.com, storage.googleapis.com, pypi.org, files.pythonhosted.org`로 허용하십시오. 그런 다음 해당 호스트를 차단하세요.|
|외부 통합|관리자가 구성한 정확한 OIDC/SAML/OTLP/webhook/객체 저장소 대상만 허용|
번들 아카이브는 `*.xethub.hf.co` 엔드포인트를 통해 병렬로 전송되고 다중 GB 번들 다운로드를 빠르게 만드는 Hugging Face의 Xet 스토리지에서 제공됩니다. 방화벽이 `huggingface.co`를 허용하지만 `*.xethub.hf.co`를 차단하는 경우 설치는 성공하지만 느린 단일 스트림 다운로드로 돌아가므로 Xet 호스트가 빠른 경로를 유지하도록 허용 목록에 추가하세요. 완전 오프라인 설치에서는 이 모든 과정을 건너뛰고 대신 [오프라인 번들 가져오기](/ko/guide/deployment)를 사용할 수 있습니다.
Docker Compose 시크릿(Swarm 없이)에는 Compose v2.23 이상이 필요하다.
:::
## Kubernetes 배포 {#kubernetes-deployment}
엔트리포인트는 컨테이너가 이미 비root로 실행 중인 경우(예: Kubernetes `runAsUser`을 통해)를 감지해 gosu 권한 강등을 자동으로 건너뛴다. 그 경우 볼륨을 스스로 chown할 수 없으므로, 쓰기 가능 여부를 확인하고 그렇지 않으면 실행 가능한 안내와 함께 조기에 종료한다. `fsGroup` 및 외부 UID 설정(TrueNAS, OpenShift)은 [스토리지 권한](/ko/guide/deployment#storage-permissions)을 참고하라.
**권장 Pod SecurityContext:**
```yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:snapotter
spec:
replicas:1
selector:
matchLabels:
app:snapotter
template:
metadata:
labels:
app:snapotter
spec:
securityContext:
runAsNonRoot:true
runAsUser:999
runAsGroup:999
fsGroup:999
containers:
- name:snapotter
image:snapotter/snapotter:latest
ports:
- containerPort:1349
securityContext:
allowPrivilegeEscalation:false
capabilities:
drop:[ALL]
resources:
requests:
cpu:"1"
memory:2Gi
limits:
cpu:"4"
memory:6Gi
livenessProbe:
httpGet:
path:/api/v1/health
port:1349
initialDelaySeconds:60
periodSeconds:30
timeoutSeconds:5
readinessProbe:
httpGet:
path:/api/v1/health
port:1349
initialDelaySeconds:10
periodSeconds:10
timeoutSeconds:5
volumeMounts:
- name:data
mountPath:/data
- name:workspace
mountPath:/tmp/workspace
volumes:
- name:data
persistentVolumeClaim:
claimName:snapotter-data
- name:workspace
emptyDir:
medium:Memory
sizeLimit:2Gi
```
`runAsUser: 999`이 파드 수준에서 설정되므로 엔트리포인트는 gosu를 완전히 건너뛴다. 이로써 `allowPrivilegeEscalation: false`과 `drop: [ALL]` 기능을 충돌 없이 사용할 수 있다.
리소스 산정은 [하드웨어 요구 사항](/ko/guide/deployment#hardware-requirements)을 참고하라.
|`SnapOtter-pgdata`|PostgreSQL 사용자, 설정, 파이프라인, 작업, 파일 메타데이터 및 감사 로그|비판적인; 휴대용 복구를 위해 빠른 실패 논리 덤프 사용|
|`SnapOtter-data`|저장된 라이브러리 개체, 로그 및 AI 상태(`/data/files, /data/logs, /data/ai, /data/ai/venv`)|전체 볼륨을 백업하십시오. 공간을 절약하기 위해 의도적으로 모든 AI 상태를 생략하고 해당 번들을 다시 설치합니다.|
|`SnapOtter-redisdata`|내구성 있는 BullMQ 대기열 상태를 위한 Redis AOF|앱을 일시 중지하고 `SAVE`를 강제 실행한 후 백업하세요. 대기 중인 작업을 정확하게 재개하는 데 필요|
|`SnapOtter-workspace`|임시 객체 스토리지 키(`/tmp/workspace/uploads, /tmp/workspace/outputs`)|모든 작업이 소진되거나 취소된 후에는 백업하지 마십시오. 작업이 활성 상태인 동안에는 절대 버리지 마세요.|
애플리케이션을 적용하기 전에 Redis를 다시 시작하십시오. `/data/ai`를 의도적으로 제외하는 경우 모델이나 가상 환경 없이 `installed.json` 레코드를 보존하는 대신 전체 AI 하위 트리를 제거하십시오. 백업 파일을 암호화하고 액세스를 제어하며 SnapOtter를 실행하는 호스트와 별도로 보관하세요.
매니페스트는 `releaseTag`, `releaseCommit` 및 `workflowTriggerCommit`를 별도로 기록합니다. `releaseCommit`가 불변 태그에서 벗겨낸 커밋인지 확인한 다음 아카이브, 이미지, SBOM의 SHA-256 다이제스트를 확인하거나 `subjects`의 해당 항목에 대해 사용하는 스캔을 확인하세요. 이러한 구분은 의도적인 것입니다. 새로 생성된 릴리스 커밋을 체크아웃해도 워크플로의 OIDC 자격 증명에서 커밋 ID가 변경되지 않습니다.