fix: release QA hardening across processing, media, security, and CI gates (#649)

A release-readiness QA pass over the whole product. The commits split into
defects a user would hit and gates that were reporting green while measuring
nothing.

## Fixes that change behaviour

Rate limiting was bypassable on every install: TRUST_PROXY defaulted to true, so
request.ip came from a client-set header and a forged X-Forwarded-For got past
the login limiter. The default is now a private-network trust list.

A transient Postgres outage stranded in-flight jobs, leaving finished output on
disk with no row pointing at it. A reconciler now resolves those rows and adopts
the bytes rather than dropping the work.

A Redis connection that moved to a new address wedged every read-blocked
consumer, so completions stopped signalling while health still answered 200.
Socket timeouts plus subscriber pings recover it.

Installing more than one AI bundle left the shared venv multi-versioned and
silently broke three tools. The installer now reconciles distributions to one
version each.

Converting an image to JXL at quality 1 through 4 returned a 500, because
libjxl 0.7 rejects the distance those values compute. The quality is floored at
what the encoder honours. A missing ffmpeg was also reported to the user as a
corrupt upload; it now says the engine is unavailable.

RAW uploads reached an unpatched LibRaw on arm64, so it is built from source at
0.22.2, and the release scan was split so it can fail on an unfixed critical
instead of hiding it behind ignore-unfixed.

## Gates that could not fail

Two mutation lanes ran zero mutants because Stryker crawled the gitignored docs
build; coverage discarded its whole report on any failing test; the lint gate
skipped root tests, scripts, and two workspaces; and several generated matrices
counted a host missing ffmpeg as a passing tool. Each now measures what it
claims.

Full evidence and the outstanding release items are tracked locally and are not
part of this branch.
This commit is contained in:
SnapOtter
2026-07-27 15:37:30 +08:00
committed by GitHub
parent bc32f86a07
commit d10d0f544f
855 changed files with 54564 additions and 13092 deletions
+4 -3
View File
@@ -1,8 +1,9 @@
---
description: "โครงสร้าง monorepo, สถาปัตยกรรมของแอปและแพ็กเกจ, วงจรชีวิตของคำขอ และรอยเท้าทรัพยากรของ SnapOtter"
i18n_output_hash: d1d73eea741b
i18n_source_hash: a53946e760b0
i18n_source_hash: 50e076925c4b
i18n_provenance: human
i18n_output_hash: b3755300060a
i18n_hash_version: 2
---
# Architecture {#architecture}
@@ -52,7 +53,7 @@ snapotter/
### API (`apps/api`) {#api-apps-api}
เซิร์ฟเวอร์ Fastify v5 ที่เปิดเผยเส้นทางเครื่องมือ 241 เส้นทางครอบคลุมห้ารูปแบบ (image, video, audio, PDF, file) ที่จัดการ:
เซิร์ฟเวอร์ Fastify v5 ที่เปิดเผยเส้นทางเครื่องมือ 243 เส้นทางครอบคลุมห้ารูปแบบ (image, video, audio, PDF, file) ที่จัดการ:
- การอัปโหลดไฟล์, การจัดการพื้นที่ทำงานชั่วคราว และที่จัดเก็บไฟล์แบบถาวร
- คลังไฟล์ผู้ใช้ (ตาราง `user_files`): โดยค่าเริ่มต้น การแก้ไขที่บันทึกไว้จะถูกจัดเก็บเป็นไฟล์ใหม่อิสระ หรือเป็นเวอร์ชันที่เชื่อมโยงกับแถวแม่เมื่อคุณเขียนทับไฟล์ต้นฉบับ โดยจะบันทึกว่าใช้เครื่องมือใดบ้าง (`toolChain`) และได้ภาพขนาดย่อที่สร้างอัตโนมัติสำหรับหน้า Files
- การเรียกใช้เครื่องมือ (กำหนดเส้นทางคำขอเครื่องมือแต่ละรายการไปยังเอนจินรูปภาพหรือบริดจ์ AI)
+40 -17
View File
@@ -1,8 +1,9 @@
---
description: "ตัวแปรสภาพแวดล้อมทั้งหมดของ SnapOtter พร้อมค่าเริ่มต้น กำหนดค่าการยืนยันตัวตน, ที่จัดเก็บ, โมเดล AI, การวิเคราะห์ข้อมูล และอื่น ๆ"
i18n_source_hash: 8e9e9ca2840c
i18n_source_hash: 25970c776f7c
i18n_provenance: human
i18n_output_hash: 891bad80245a
i18n_output_hash: 9a6f66699ce0
i18n_hash_version: 2
---
# Configuration {#configuration}
@@ -19,28 +20,51 @@ i18n_output_hash: 891bad80245a
| `RATE_LIMIT_PER_MIN` | `1000` | จำนวนคำขอสูงสุดต่อนาทีต่อ IP ตั้งเป็น 0 เพื่อปิดการจำกัดอัตรา |
| `CORS_ORIGIN` | (ว่าง) | ต้นทางที่อนุญาตสำหรับ CORS คั่นด้วยเครื่องหมายจุลภาค หรือว่างไว้สำหรับต้นทางเดียวกันเท่านั้น |
| `LOG_LEVEL` | `info` | ระดับความละเอียดของบันทึก หนึ่งใน: `fatal`, `error`, `warn`, `info`, `debug`, `trace` |
| `TRUST_PROXY` | `true` | เชื่อถือส่วนหัว `X-Forwarded-For` จาก reverse proxy ตั้งเป็น `false` หากไม่ได้อยู่หลัง proxy |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | เพียร์ใดบ้างที่ตั้งค่า IP ของไคลเอนต์ผ่าน `X-Forwarded-For` ได้ ค่าเริ่มต้นจะเชื่อเฉพาะเพียร์ในเครือข่ายส่วนตัว ดังนั้น reverse proxy บนเครือข่าย Docker หรือบน LAN จึงได้รับความเชื่อถือ ส่วนส่วนหัวที่ปลอมแปลงมาจากไคลเอนต์บนเครือข่ายสาธารณะจะไม่ได้รับ ตั้งเป็น `true` เฉพาะเมื่อมี proxy ที่คุณควบคุมเองวางอยู่ด้านหน้าบนที่อยู่สาธารณะ |
### Authentication {#authentication}
บูลีนสองตัวด้านล่างรับเฉพาะ `true` และ `false` เท่านั้น ค่าอื่นใด เช่น `1` หรือ `yes` หรือ `on` จะไม่ผ่านการตรวจสอบ และเซิร์ฟเวอร์จะออกก่อนที่จะเริ่มรับฟัง
| Variable | Default | Description |
|---|---|---|
| `AUTH_ENABLED` | `false` | ตั้งเป็น `true` เพื่อบังคับให้เข้าสู่ระบบ อิมเมจ Docker มีค่าเริ่มต้นเป็น `true` |
| `AUTH_ENABLED` | `true` | บังคับให้เข้าสู่ระบบ ตั้งเป็น `false` เพื่อรันโดยไม่มีบัญชีใด ๆ เลย ซึ่งให้สิทธิ์ admin แก่ทุกคำขอ ดังนั้นควรจำกัดไว้เฉพาะเครือข่ายที่เชื่อถือได้ |
| `DEFAULT_USERNAME` | `admin` | ชื่อผู้ใช้สำหรับบัญชี admin เริ่มต้น ใช้เฉพาะตอนรันครั้งแรก |
| `DEFAULT_PASSWORD` | `admin` | รหัสผ่านสำหรับบัญชี admin เริ่มต้น เปลี่ยนหลังจากเข้าสู่ระบบครั้งแรก |
| `MAX_USERS` | `0` (ไม่จำกัด) | จำนวนบัญชีผู้ใช้ที่ลงทะเบียนสูงสุด ตั้งเป็น 0 สำหรับไม่จำกัด |
| `SESSION_DURATION_HOURS` | `168` | อายุของ session การเข้าสู่ระบบเป็นชั่วโมง (ค่าเริ่มต้นคือ 7 วัน) |
| `SKIP_MUST_CHANGE_PASSWORD` | - | ตั้งเป็นค่าที่ไม่ว่างใด ๆ เพื่อข้ามการแจ้งให้เปลี่ยนรหัสผ่านแบบบังคับตอนเข้าสู่ระบบครั้งแรก |
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | ตั้งเป็น `true` เพื่อข้ามการแจ้งให้เปลี่ยนรหัสผ่านแบบบังคับตอนเข้าสู่ระบบครั้งแรก |
### Storage {#storage}
| Variable | Default | Description |
|---|---|---|
| `STORAGE_MODE` | `local` | `local` หรือ `s3` S3/MinIO ต้องใช้ใบอนุญาตที่มีฟีเจอร์ s3_storage |
| `DATABASE_URL` | `postgres://snapotter:snapotter@postgres:5432/snapotter` | สตริงการเชื่อมต่อ PostgreSQL |
| `REDIS_URL` | `redis://redis:6379` | สตริงการเชื่อมต่อ Redis (ใช้สำหรับคิวงาน BullMQ) |
| `WORKSPACE_PATH` | `./tmp/workspace` | ไดเรกทอรีสำหรับไฟล์ชั่วคราวระหว่างการประมวลผล ล้างข้อมูลโดยอัตโนมัติ |
| `FILES_STORAGE_PATH` | `./data/files` | ไดเรกทอรีสำหรับไฟล์ผู้ใช้แบบถาวร (ภาพที่อัปโหลด, ผลลัพธ์ที่บันทึก) |
| `STORAGE_MODE` | `local` | `local` หรือ `s3` S3 และ MinIO ต้องใช้ใบอนุญาตที่มีฟีเจอร์ s3_storage พร้อมกับตัวแปร `S3_*` ด้านล่าง |
| `DATABASE_URL` | `postgres://snapotter:snapotter@localhost:5432/snapotter` | สตริงการเชื่อมต่อ PostgreSQL สแตก Compose ชี้ค่านี้ไปยังบริการ `postgres` ของมัน ปล่อยไม่ตั้งค่า (พร้อมกับ `REDIS_URL`) เพื่อใช้โหมด embedded |
| `REDIS_URL` | `redis://localhost:6379` | สตริงการเชื่อมต่อ Redis (ใช้สำหรับคิวงาน BullMQ) Compose ชี้ค่านี้ไปยังบริการ `redis` ของมัน |
| `WORKSPACE_PATH` | `./tmp/workspace` | ไดเรกทอรีสำหรับไฟล์ชั่วคราวระหว่างการประมวลผล ล้างข้อมูลโดยอัตโนมัติ อิมเมจตั้งค่าเป็น `/tmp/workspace` |
| `FILES_STORAGE_PATH` | `./data/files` | ไดเรกทอรีสำหรับไฟล์ผู้ใช้แบบถาวร (ภาพที่อัปโหลด, ผลลัพธ์ที่บันทึก) อิมเมจตั้งค่าเป็น `/data/files` |
### S3 object storage {#s3-object-storage}
อ่านค่าเหล่านี้เฉพาะเมื่อ `STORAGE_MODE=s3` เท่านั้น หากขาดตัวใดตัวหนึ่งในสามตัวที่จำเป็น การเริ่มระบบจะล้มเหลวพร้อมบอกชื่อตัวแปรที่คุณละไว้
| Variable | Default | Description |
|---|---|---|
| `S3_BUCKET` | (ว่าง) | บักเก็ตที่เก็บไฟล์อัปโหลดและเอาต์พุต จำเป็น |
| `S3_ACCESS_KEY_ID` | (ว่าง) | แอ็กเซสคีย์ จำเป็น ในคอนเทนเนอร์คุณสามารถเมานต์เป็นไฟล์แทนได้ ผ่าน `S3_ACCESS_KEY_ID_FILE` |
| `S3_SECRET_ACCESS_KEY` | (ว่าง) | ซีเคร็ตคีย์ จำเป็น ใช้แบบแผนไฟล์เดียวกัน: `S3_SECRET_ACCESS_KEY_FILE` |
| `S3_REGION` | `us-east-1` | ภูมิภาคของบักเก็ต |
| `S3_ENDPOINT` | (ว่าง) | เอนด์พอยต์แบบกำหนดเองสำหรับ MinIO, R2, Backblaze และที่จัดเก็บอื่น ๆ ที่รองรับ S3 ค่าว่างหมายถึง AWS |
| `S3_FORCE_PATH_STYLE` | `false` | ตั้งเป็น `true` สำหรับ MinIO และสิ่งอื่นใดที่ต้องการ `endpoint/bucket/key` แทนการระบุที่อยู่แบบ virtual-host |
| `S3_PREFIX` | (ว่าง) | คำนำหน้าคีย์ เพื่อให้บักเก็ตเดียวเก็บได้หลายอินสแตนซ์ |
### Encryption at rest {#encryption-at-rest}
| Variable | Default | Description |
|---|---|---|
| `DATA_ENCRYPTION_KEY` | (ว่าง) | อักขระเลขฐานสิบหก 64 ตัว (32 ไบต์) เข้ารหัสการตั้งค่าที่ละเอียดอ่อนซึ่งเก็บอยู่ในฐานข้อมูล สิ่งใดที่ไม่ใช่อักขระเลขฐานสิบหก 64 ตัวจะถูกปฏิเสธตอนเริ่มระบบ |
| `DATA_ENCRYPTION_KEY_PREVIOUS` | (ว่าง) | คีย์ที่คุณกำลังหมุนเปลี่ยนออกไป รูปแบบเดียวกัน ตั้งค่าทั้งสองตัวระหว่างการหมุนคีย์เพื่อให้แถวที่มีอยู่ยังถอดรหัสได้ แล้วจึงลบตัวนี้ออก |
### Embedded mode {#embedded-mode}
@@ -59,16 +83,15 @@ i18n_output_hash: 891bad80245a
| Variable | Default | Description |
|---|---|---|
| `MAX_UPLOAD_SIZE_MB` | `100` | ขนาดไฟล์สูงสุดต่อการอัปโหลดเป็นเมกะไบต์ ตั้งเป็น 0 สำหรับไม่จำกัด |
| `MAX_BATCH_SIZE` | `100` | จำนวนไฟล์สูงสุดในคำขอชุดเดียว ตั้งเป็น 0 สำหรับไม่จำกัด |
| `MAX_UPLOAD_SIZE_MB` | `0` (ไม่จำกัด) | ขนาดไฟล์สูงสุดต่อการอัปโหลดเป็นเมกะไบต์ ตั้งเป็น 0 สำหรับไม่จำกัด อิมเมจที่เผยแพร่มาพร้อมค่า `0` ส่วนการบิลด์จากซอร์สเริ่มต้นที่ 100 |
| `MAX_BATCH_SIZE` | `0` (ไม่จำกัด) | จำนวนไฟล์สูงสุดในคำขอชุดเดียว ตั้งเป็น 0 สำหรับไม่จำกัด อิมเมจที่เผยแพร่มาพร้อมค่า `0` ส่วนการบิลด์จากซอร์สเริ่มต้นที่ 100 |
| `CONCURRENT_JOBS` | `0` (อัตโนมัติ) | จำนวนงานชุดที่รันแบบขนาน ตั้งเป็น 0 เพื่อตรวจจับอัตโนมัติตามแกน CPU ที่มีอยู่ |
| `MAX_MEGAPIXELS` | `0` (ไม่จำกัด) | ความละเอียดภาพสูงสุดที่อนุญาตเป็นเมกะพิกเซล ตั้งเป็น 0 สำหรับไม่จำกัด |
| `MAX_WORKER_THREADS` | `0` (อัตโนมัติ) | เธรด worker สูงสุดสำหรับการประมวลผลรูปภาพ ตั้งเป็น 0 เพื่อตรวจจับอัตโนมัติตามแกน CPU ที่มีอยู่ |
| `PROCESSING_TIMEOUT_S` | `0` (ไม่มีขีดจำกัด) | เวลาการประมวลผลสูงสุดต่อคำขอเป็นวินาที ตั้งเป็น 0 สำหรับไม่มีการหมดเวลา |
| `MAX_PIPELINE_STEPS` | `20` | จำนวนขั้นตอนสูงสุดในไปป์ไลน์ ตั้งเป็น 0 สำหรับไม่มีขีดจำกัด |
| `MAX_CANVAS_PIXELS` | `0` (ไม่มีขีดจำกัด) | ขนาดแคนวาสสูงสุดเป็นพิกเซลสำหรับภาพเอาต์พุต ตั้งเป็น 0 สำหรับไม่มีขีดจำกัด |
| `MAX_SVG_SIZE_MB` | `0` (ไม่จำกัด) | ขนาดไฟล์ SVG สูงสุดเป็นเมกะไบต์ ตั้งเป็น 0 สำหรับไม่จำกัด |
| `MAX_SPLIT_GRID` | `100` | มิติตารางสูงสุดสำหรับเครื่องมือแยกภาพ |
| `MAX_SVG_SIZE_MB` | `50` | ขนาด SVG ใหญ่ที่สุดที่รับได้ก่อนการทำ sanitize เป็นเมกะไบต์ ที่นี่ `0` ทำงานต่างจากแถวรอบ ๆ มัน โดยจะลบขีดจำกัดขนาดก่อนการแปลงออกทั้งหมดแทนที่จะเพิ่มขีดจำกัด ดังนั้นควรตั้งค่าตัวนี้ไว้เสมอ |
| `MAX_PDF_PAGES` | `0` (ไม่จำกัด) | จำนวนหน้า PDF สูงสุดสำหรับการแปลง PDF-to-image ตั้งเป็น 0 สำหรับไม่จำกัด |
### Cleanup {#cleanup}
@@ -82,7 +105,7 @@ i18n_output_hash: 891bad80245a
| Variable | Default | Description |
|---|---|---|
| `DEFAULT_THEME` | `light` | ธีมเริ่มต้นสำหรับ session ใหม่ `light` หรือ `dark` |
| `DEFAULT_THEME` | `light` | ธีมเริ่มต้นสำหรับ session ใหม่ `light`, `dark` หรือ `system` |
| `DEFAULT_LOCALE` | `en` | ภาษาอินเทอร์เฟซเริ่มต้น |
| `DEFAULT_TOOL_VIEW` | `sidebar` | เลย์เอาต์เครื่องมือเริ่มต้น `sidebar` หรือ `fullscreen` |
@@ -124,13 +147,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # เปลี่ยนสิ่งนี้สำหรับการปรับใช้ที่ไม่ใช่ภายในเครื่อง
POSTGRES_DB: snapotter
volumes:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
interval: 10s
timeout: 5s
retries: 12
+5 -4
View File
@@ -1,8 +1,9 @@
---
description: "วิธีมีส่วนร่วมกับ SnapOtter รายงานบั๊ก คำขอฟีเจอร์ pull request และข้อกำหนดเรื่อง CLA"
i18n_source_hash: 528802503035
i18n_source_hash: 6c920a5f83e0
i18n_provenance: human
i18n_output_hash: 33d63a5f1932
i18n_output_hash: 88395fe58149
i18n_hash_version: 2
---
# การมีส่วนร่วม {#contributing}
@@ -53,7 +54,7 @@ i18n_output_hash: 33d63a5f1932
### สิ่งที่ต้องมีก่อน {#prerequisites}
- Node.js 22+
- Node.js 22.22+
- pnpm 9+
- Python 3.11+ (สำหรับเครื่องมือ AI เท่านั้น)
- Docker (ไม่บังคับ สำหรับการทดสอบ integration เต็มรูปแบบ)
@@ -71,7 +72,7 @@ docker compose -f docker-compose.dev.yml up -d
# Install dependencies
pnpm install
# Start dev servers (web on :1349, API on :13490)
# Start dev servers (web on :1351, API on :13490)
pnpm dev
```
+35 -15
View File
@@ -1,8 +1,9 @@
---
description: "สคีมาฐานข้อมูล PostgreSQL ตาราง การย้ายข้อมูล และขั้นตอนการสำรองข้อมูลสำหรับ SnapOtter"
i18n_source_hash: 50d5d4f220cf
i18n_provenance: human
i18n_output_hash: b589c2175a16
i18n_source_hash: a68264552836
i18n_provenance: machine
i18n_output_hash: ec41785970af
i18n_hash_version: 2
---
# ฐานข้อมูล {#database}
@@ -145,6 +146,17 @@ SnapOtter ใช้ PostgreSQL 17 กับ [Drizzle ORM](https://orm.drizzle.te
| `details` | jsonb | ข้อมูลเฉพาะการกระทำ |
| `createdAt` | timestamp | เวลาที่กระทำ |
### user_preferences {#user-preferences}
สถานะ UI ของผู้ใช้แต่ละคน โดยใช้ชื่อการตั้งค่าเป็นคีย์ เก็บเครื่องมือที่ปักหมุดบนหน้าหลัก ซึ่งเขียนผ่าน `PUT /api/v1/preferences`
| คอลัมน์ | ชนิด | หมายเหตุ |
|---|---|---|
| `userId` | text | FK ไปยัง users ลบแบบต่อเนื่อง เป็นคีย์หลักร่วมกับ `key` |
| `key` | text | ชื่อการตั้งค่า เป็นคีย์หลักร่วมกับ `userId` |
| `value` | jsonb | ข้อมูลของการตั้งค่า |
| `updatedAt` | timestamp | เวลาที่เขียนล่าสุด |
## การย้ายข้อมูล (Migrations) {#migrations}
Drizzle จัดการการย้ายสคีมา ไฟล์การย้ายข้อมูลอยู่ใน `apps/api/drizzle/` ระหว่างการพัฒนา:
@@ -157,29 +169,37 @@ npx drizzle-kit migrate # apply pending migrations
ในโปรดักชัน การย้ายข้อมูลที่ค้างอยู่จะถูกนำมาใช้โดยอัตโนมัติเมื่อเริ่มต้น
## การสำรองและกู้คืนข้อมูล {#backup-and-restore}
## สำรองและกู้คืน {#backup-and-restore}
ฐานข้อมูลเชิงสัมพันธ์อยู่ใน volume `SnapOtter-pgdata` ของคอนเทนเนอร์ Postgres ไม่ใช่ volume `/data` ของแอป
ฐานข้อมูลเชิงสัมพันธ์อยู่ในโวลุ่ม `SnapOtter-pgdata` ของคอนเทนเนอร์ Postgres ไม่ใช่โวลุ่ม `/data` ของแอป
**ตัวเลือกที่ 1: pg_dump (แนะนำ)**
**การสำรองข้อมูลแบบลอจิคัลพร้อมการตรวจสอบความถูกต้อง (แนะนำ)**
```bash
# Dump the database while the stack is running
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
# Dump into PostgreSQL's portable custom archive format
docker exec SnapOtter-postgres \
pg_dump --format=custom --no-owner -U snapotter snapotter > snapotter.dump
test -s snapotter.dump
docker exec -i SnapOtter-postgres pg_restore --list < snapotter.dump >/dev/null
# Restore into a fresh database
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
# Restore into a fresh/disposable target first and fail on the first SQL error
docker exec -i SnapOtter-postgres \
pg_restore --exit-on-error --clean --if-exists --no-owner \
-U snapotter -d snapotter < snapotter.dump
```
**ตัวเลือกที่ 2: Volume snapshot**
ดัมพ์ฐานข้อมูลนี้ไม่มีอ็อบเจ็กต์ไลบรารีที่บันทึกไว้ใน `/data/files` หรือสถานะ BullMQ แบบทนทานใน Redis สำรองและกู้คืนข้อมูลเหล่านั้นด้วยขั้นตอนการประสานงานใน [Security & Hardening](/th/guide/security#backup-and-recovery)
**สแนปชอตวอลุ่มเย็น**
```bash
# Stop the stack, then snapshot the pgdata volume
docker compose down
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
# Stop every service first, then use your storage platform to snapshot the
# PostgreSQL, app-data, and Redis volumes as one crash-consistent set.
docker compose -f docker/docker-compose.yml stop
```
อย่าคัดลอกไดเร็กทอรีข้อมูล PostgreSQL แบบสดด้วย `tar` เขียนคำนำหน้าชื่อวอลุ่มตามโปรเจ็กต์ ดังนั้นแก้ไข ID วอลุ่มที่ติดตั้งจาก `docker inspect` หรือแพลตฟอร์มพื้นที่จัดเก็บข้อมูลของคุณ แทนที่จะใช้ป้ายกำกับตัวอักษร `SnapOtter-pgdata`
### การย้ายข้อมูลจาก 1.x (SQLite) {#migrating-from-1-x-sqlite}
การอัปเกรดจาก SnapOtter 1.x มีคู่มือของตัวเอง ดู [การอัปเกรดจาก 1.x ไปยัง 2.0](./upgrading) สรุปสั้นๆ ให้ใช้ volume `/data` ที่มีอยู่เดิมซ้ำ และ 2.0 จะตรวจจับและนำเข้า `/data/snapotter.db` โดยอัตโนมัติเมื่อบูตครั้งแรก (หรือกำหนด `SQLITE_MIGRATE_PATH` เพื่อชี้ไปยังไฟล์นั้นอย่างชัดเจน) สำรอง volume `/data` ทั้งหมดก่อน ไม่ใช่แค่ `snapotter.db`: 1.x ใช้โหมด SQLite WAL ดังนั้นคอนเทนเนอร์ที่หยุดทำงานมักจะทิ้งข้อมูลส่วนใหญ่ไว้ใน `snapotter.db-wal` ข้างๆ `snapotter.db` ที่แทบจะว่างเปล่า
+24 -13
View File
@@ -1,8 +1,9 @@
---
description: "ปรับใช้ SnapOtter สู่โปรดักชันด้วย Docker ความต้องการฮาร์ดแวร์ การตั้งค่า GPU และคอนฟิก reverse proxy สำหรับ Nginx, Traefik และ Cloudflare"
i18n_output_hash: d21da61a4516
i18n_source_hash: 98172965118b
i18n_source_hash: 2a722f86da75
i18n_provenance: human
i18n_output_hash: ba36e2dd62d1
i18n_hash_version: 2
---
# Deployment {#deployment}
@@ -47,7 +48,7 @@ services:
# - MAX_USERS=0 # Max user accounts
# --- Networking ---
# - TRUST_PROXY=true # Trust X-Forwarded-For headers (set false if not behind a proxy)
# - TRUST_PROXY=loopback,linklocal,uniquelocal # Which peers may set the client IP via X-Forwarded-For (default shown)
# --- Bind mount permissions ---
# - PUID=1000 # Match your host user's UID (run: id -u)
@@ -82,7 +83,7 @@ services:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
interval: 10s
timeout: 5s
retries: 12
@@ -170,13 +171,13 @@ services:
container_name: SnapOtter-postgres
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # เปลี่ยนสิ่งนี้สำหรับการปรับใช้ที่ไม่ใช่ภายในเครื่อง
POSTGRES_DB: snapotter
volumes:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
interval: 10s
timeout: 5s
retries: 12
@@ -207,13 +208,17 @@ volumes:
docker compose -f docker-compose-gpu.yml up -d
```
ตรวจสอบการตรวจพบ CUDA ในบันทึกล็อก:
### ตรวจสอบการเร่งความเร็ว GPU {#verify-gpu-acceleration}
ตรวจสอบการตรวจจับ CUDA ในบันทึก:
```bash
docker logs SnapOtter 2>&1 | head -20
# Look for: [gpu] CUDA available via torch
```
หากเครื่องมือ AI ทำงานบน CPU แม้ว่า `--gpus all` และ NVIDIA Container Toolkit ได้รับการตั้งค่าอย่างถูกต้อง ให้ติดตั้งบันเดิลที่ได้รับผลกระทบอีกครั้ง (เช่น การลบพื้นหลัง) จาก **การตั้งค่า → คุณสมบัติ AI** โปรแกรมติดตั้งจะกู้คืนโครงสร้าง GPU ของรันไทม์ ONNX ซึ่งโครงสร้างเฉพาะ CPU ที่ดึงเข้ามาโดยบันเดิลอื่น (เช่น การถอดเสียง) อาจเกิดเงาในสภาพแวดล้อม AI ที่ใช้ร่วมกัน หากการติดตั้งใหม่จาก UI ไม่สามารถกู้คืน GPU บนอิมเมจเก่าได้ โปรดดูการซ่อมแซมด้วยตนเองใน [ปัญหา #490](https://github.com/snapotter-hq/SnapOtter/issues/490)
## Hardware Requirements {#hardware-requirements}
ตัวเลขเหล่านี้มาจากการทดสอบประสิทธิภาพบนระบบหลากหลาย ตั้งแต่เวิร์กสเตชัน amd64 รุ่นใหม่ที่มี NVIDIA RTX 4070 ไปจนถึง Raspberry Pi โดยรันแคตตาล็อกเครื่องมือทั้งชุดบนแต่ละเครื่อง และกวาดค่าขีดจำกัดทรัพยากรของ Docker เพื่อหาขีดต่ำสุดที่แท้จริง
@@ -436,11 +441,11 @@ securityContext:
| `AUTH_ENABLED` | `true` | เปิด/ปิดข้อกำหนดการล็อกอิน |
| `DEFAULT_USERNAME` | `admin` | ชื่อผู้ใช้แอดมินเริ่มต้น |
| `DEFAULT_PASSWORD` | `admin` | รหัสผ่านแอดมินเริ่มต้น (บังคับเปลี่ยนตอนล็อกอินครั้งแรก) |
| `MAX_UPLOAD_SIZE_MB` | `100` | ขีดจำกัดการอัปโหลดต่อไฟล์ |
| `MAX_BATCH_SIZE` | `100` | จำนวนไฟล์สูงสุดต่อคำขอชุด |
| `MAX_UPLOAD_SIZE_MB` | `0` (ไม่จำกัด) | ขีดจำกัดการอัปโหลดต่อไฟล์เป็น MB อิมเมจมาพร้อมค่า `0` ส่วนการบิลด์จากซอร์สเริ่มที่ 100 |
| `MAX_BATCH_SIZE` | `0` (ไม่จำกัด) | จำนวนไฟล์สูงสุดต่อคำขอชุด อิมเมจมาพร้อมค่า `0` ส่วนการบิลด์จากซอร์สเริ่มที่ 100 |
| `RATE_LIMIT_PER_MIN` | `1000` | คำขอ API ต่อนาทีต่อ IP (ตั้ง 0 เพื่อปิด) |
| `MAX_USERS` | `0` (ไม่จำกัด) | จำนวนบัญชีผู้ใช้สูงสุด |
| `TRUST_PROXY` | `true` | เชื่อถือส่วนหัว X-Forwarded-For จาก reverse proxy |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | เพียร์ใดบ้างที่ตั้งค่า IP ของไคลเอนต์ผ่าน `X-Forwarded-For` ได้ ค่าเริ่มต้นคือเฉพาะเครือข่ายส่วนตัวเท่านั้น |
| `PUID` | `999` | รันเป็น UID นี้ (สำหรับสิทธิ์ bind mount) |
| `PGID` | `999` | รันเป็น GID นี้ (สำหรับสิทธิ์ bind mount) |
| `LOG_LEVEL` | `info` | ระดับความละเอียดของล็อก: fatal, error, warn, info, debug, trace |
@@ -483,7 +488,13 @@ curl http://localhost:1349/api/v1/health
## Reverse Proxy {#reverse-proxy}
SnapOtter ตั้งค่า `TRUST_PROXY=true` โดยค่าเริ่มต้น เพื่อให้การจำกัดอัตราและการบันทึกล็อกใช้ IP จริงของไคลเอนต์จากส่วนหัว `X-Forwarded-For`
`TRUST_PROXY` มีค่าเริ่มต้นเป็น `loopback,linklocal,uniquelocal` ดังนั้น SnapOtter จะเชื่อ `X-Forwarded-For` เฉพาะจากเพียร์ในเครือข่ายส่วนตัวเท่านั้น reverse proxy บนโฮสต์เดียวกัน บนเครือข่าย Docker หรือบน LAN ของคุณจึงได้รับความเชื่อถือตั้งแต่แรก นั่นหมายความว่าการจำกัดอัตรา ตัวจำกัดการเดารหัสผ่านตอนล็อกอิน บันทึกการตรวจสอบ และรายการ IP ที่อนุญาตในรุ่น enterprise ต่างเห็น IP จริงของไคลเอนต์โดยไม่ต้องตั้งค่าใด ๆ
ตั้ง `TRUST_PROXY=true` เฉพาะเมื่อพร็อกซีที่อยู่ด้านหน้าเข้าถึง SnapOtter จากที่อยู่**สาธารณะ** เช่น โหลดบาลานเซอร์บนคลาวด์ที่อยู่คนละเครือข่าย บนอินสแตนซ์ที่เปิดออกสู่ภายนอกโดยตรง ค่านี้จะทำให้ `request.ip` ตกอยู่ในการควบคุมของผู้โจมตี เพราะผู้เรียกที่หมุนเปลี่ยนส่วนหัวไปเรื่อย ๆ จะได้ตัวนับขีดจำกัดอัตราใหม่ในทุกคำขอ
มีสองเรื่องที่ควรรู้ก่อนจะลงมือวัด IP ของไคลเอนต์ Docker Desktop บน macOS และ Windows ให้บริการพอร์ตที่เผยแพร่ผ่านพร็อกซีในพื้นที่ผู้ใช้ ซึ่งเขียนที่อยู่ต้นทางทุกรายการใหม่เป็นเกตเวย์ของ VM `192.168.65.1` ที่นั่นจึงไม่มีค่า `TRUST_PROXY` ใดกู้ไคลเอนต์จริงกลับมาได้ ให้ติดตั้งบน Linux สำหรับทุกอย่างที่เปิดสู่อินเทอร์เน็ต และไม่ว่าจะแพลตฟอร์มใด การเข้าถึงพอร์ตที่เผยแพร่ผ่าน `localhost` จะถูกมองว่าเป็นเกตเวย์ของบริดจ์ ไม่ใช่ไคลเอนต์ของคุณ ดังนั้นการทดสอบผ่าน localhost จึงบอกอะไรไม่ได้เลยว่าไคลเอนต์จริงจะถูกระบุอย่างไร ตารางค่าทั้งหมดของ `TRUST_PROXY` และข้อควรระวังเรื่อง Docker Desktop อยู่ใน [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md#client-ip-resolution-trust_proxy)
สองสิ่งที่สำคัญสำหรับทุกพร็อกซีด้านล่าง: อนุญาตเนื้อหาคำขอขนาดใหญ่ (อัปโหลด) และไม่บัฟเฟอร์การตอบสนอง พร็อกซีบัฟเฟอร์การตอบสนองจะทำลายความคืบหน้าของ SSE และทำให้การดาวน์โหลดไฟล์ขนาดใหญ่ "เริ่มต้นแต่ไม่สิ้นสุด" อย่างเห็นได้ชัด เนื่องจากพร็อกซีจะเก็บไฟล์ทั้งหมดก่อนที่จะส่งต่อ SnapOtter ส่ง `X-Accel-Buffering: no` ในการดาวน์โหลด ดังนั้น nginx สตรีมสิ่งเหล่านั้นแม้ว่าการบัฟเฟอร์จะถูกทิ้งไว้ที่อื่น แต่พรอกซีอื่นที่ไม่ใช่ nginx จำเป็นต้องปิดใช้งานการบัฟเฟอร์การตอบสนองอย่างชัดเจน (แสดงอยู่ในการกำหนดค่าแต่ละรายการด้านล่าง) หากการดาวน์โหลดค้างกลางคัน พร็อกซีการบัฟเฟอร์ที่อยู่ด้านหน้าคือสิ่งแรกที่ต้องตรวจสอบ
### Nginx {#nginx}
@@ -505,7 +516,7 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE support (batch progress, feature install progress)
# สตรีมการตอบสนองแทนการบัฟเฟอร์: จำเป็นสำหรับความคืบหน้าของ SSE (แบทช์, AI, การติดตั้งฟีเจอร์) และสำหรับการดาวน์โหลดไฟล์ขนาดใหญ่
proxy_buffering off;
proxy_read_timeout 300s;
}
@@ -549,7 +560,7 @@ images.example.com {
}
```
`flush_interval -1` ปิดการบัฟเฟอร์การตอบสนอง ซึ่งจำเป็นสำหรับเหตุการณ์ความคืบหน้า SSE (การประมวลผลชุด, เครื่องมือ AI, การติดตั้งฟีเจอร์) การหมดเวลาที่ยืดออกช่วยให้การอัโหลดไฟล์ขนาดใหญ่เสร็จสมบูรณ์โดยที่ Caddy ไม่ปิดการเชื่อมต่อก่อนกำหนด
`flush_interval -1` ปิดใช้งานการบัฟเฟอร์การตอบสนอง ซึ่งจำเป็นสำหรับเหตุการณ์ความคืบหน้าของ SSE (การประมวลผลเป็นชุด เครื่องมือ AI การติดตั้งคุณสมบัติ) และสำหรับการดาวน์โหลดไฟล์ขนาดใหญ่เพื่อสตรีมผ่านแทนที่จะหยุดชะงัก การหมดเวลาแบบขยายทำให้การอัโหลดไฟล์ขนาดใหญ่เสร็จสิ้นโดยไม่ต้อง Caddy ปิดการเชื่อมต่อก่อนกำหนด
### Cloudflare Tunnels {#cloudflare-tunnels}
+19 -7
View File
@@ -1,8 +1,9 @@
---
description: "การตั้งค่าสภาพแวดล้อมการพัฒนาในเครื่อง คำสั่ง แนวทางการเขียนโค้ด และวิธีเพิ่มเครื่องมือใหม่ใน SnapOtter"
i18n_source_hash: cb03724d2829
i18n_provenance: human
i18n_output_hash: 66d6a87e1e3d
i18n_source_hash: 56acc1bf9a9b
i18n_provenance: machine
i18n_output_hash: a42eaf432db1
i18n_hash_version: 2
---
# คู่มือนักพัฒนา {#developer-guide}
@@ -11,12 +12,12 @@ i18n_output_hash: 66d6a87e1e3d
## สิ่งที่ต้องมีก่อน {#prerequisites}
- [Node.js](https://nodejs.org/) 22+
- [Node.js](https://nodejs.org/) 22.22+
- [pnpm](https://pnpm.io/) 9+ (`corepack enable && corepack prepare pnpm@latest --activate`)
- [Docker](https://www.docker.com/) (จำเป็นสำหรับ Postgres + Redis ในเครื่อง, การ build คอนเทนเนอร์ และฟีเจอร์ AI)
- Git
ต้องมี Python 3.10+ เฉพาะเมื่อคุณกำลังทำงานกับ AI/ML sidecar (การลบพื้นหลัง, การขยายภาพ, OCR) เท่านั้น
ต้องมี Python 3.11+ เฉพาะเมื่อคุณกำลังทำงานกับ AI/ML sidecar (การลบพื้นหลัง, การขยายภาพ, OCR) เท่านั้น
## การตั้งค่า {#setup}
@@ -32,10 +33,10 @@ pnpm dev
| บริการ | URL | หมายเหตุ |
|----------|--------------------------|------------------------------------|
| Frontend | http://localhost:1349 | Vite dev server, proxy /api |
| Frontend | http://localhost:1351 | Vite dev server, proxy /api |
| Backend | http://localhost:13490 | Fastify API (เข้าถึงผ่าน proxy) |
เปิด http://localhost:1349 ในเบราว์เซอร์ของคุณ เข้าสู่ระบบด้วย `admin` / `admin` คุณจะได้รับแจ้งให้เปลี่ยนรหัสผ่านตอนเข้าสู่ระบบครั้งแรก
เปิด http://localhost:1351 ในเบราว์เซอร์ของคุณ เข้าสู่ระบบด้วย `admin` / `admin` คุณจะได้รับแจ้งให้เปลี่ยนรหัสผ่านตอนเข้าสู่ระบบครั้งแรก
## โครงสร้างโปรเจกต์ {#project-structure}
@@ -220,6 +221,17 @@ docker build -f docker/Dockerfile -t snapotter:latest .
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
```
## โดเมนเวอร์ชันวางจำหน่าย {#release-version-domains}
SnapOtter มีเจตนาให้มีโดเมนสามเวอร์ชัน อย่าคัดลอกโดเมนหนึ่งไปยังอีกโดเมนหนึ่งในระหว่างการเผยแพร่:
- เวอร์ชันเผยแพร่ของแอปพลิเคชันครอบคลุม Root Manifest แพ็คเกจพื้นที่ทำงานส่วนตัวทั้งหมด และ `APP_VERSION` Semantic-release ระบุค่านี้ และ `pnpm version:sync <version>` จะอัปเดตทุกพื้นที่ทำงานก่อนที่จะเผยแพร่แอปพลิเคชัน
- OpenAPI `info.version` เป็นสัญญาหลัก API สาธารณะที่มีความเสถียร ข้อมูลจำเพาะที่แปลเป็นภาษาท้องถิ่นทั้งหมดจะยังคงอยู่ใน `<major>.0.0` สำหรับการเปิดตัวแอปพลิเคชันที่เข้ากันได้ และเปลี่ยนแปลงเฉพาะเมื่อสัญญา API ย้ายไปเป็นเวอร์ชันหลักใหม่
- `docker/feature-manifest.json` คง `imageVersion: 2.0.0` ไว้เป็นยุคพื้นที่จัดเก็บข้อมูลบันเดิลฟีเจอร์ดั้งเดิมที่ไม่เปลี่ยนรูปแบบ เส้นทางการเก็บถาวร v2 เหล่านั้นไม่ใช่เวอร์ชันแพ็คเกจแอปพลิเคชัน OCR ที่แม่นยำใช้รูปแบบรันไทม์ v3 และบันทึกที่มาของการเปิดตัวแอปพลิเคชันแยกกัน
`tests/unit/infra/release-version-policy.test.ts` บังคับใช้ขอบเขตเหล่านี้ โดเมนเวอร์ชันใหม่หรือการโยกย้ายจะต้องอัปเดตสัญญานั้นและการออกแบบการโยกย้ายส่วนที่เกี่ยวข้องร่วมกัน
ค่า API อิสระและชุดดั้งเดิมอยู่ใน `config/release-version-policy.json` การซิงโครไนซ์เวอร์ชันแอปพลิเคชันจะต้องไม่เขียนไฟล์นโยบายนั้นซ้ำโดยปริยาย
## ตัวแปรสภาพแวดล้อม {#environment-variables}
ดู [คู่มือการกำหนดค่า](/th/guide/configuration) สำหรับรายการทั้งหมด ตัวแปรสำคัญสำหรับการพัฒนา:
+8 -7
View File
@@ -1,8 +1,9 @@
---
description: "แท็กของ Docker image สำหรับ SnapOtter, การเปรียบเทียบประสิทธิภาพ GPU, การล็อกเวอร์ชัน และการรองรับหลายแพลตฟอร์มสำหรับ AMD64 และ ARM64"
i18n_output_hash: 6df1f68453ec
i18n_source_hash: fda322e78b4b
i18n_source_hash: 566e20ca07fc
i18n_provenance: human
i18n_output_hash: 119de6d8c1c4
i18n_hash_version: 2
---
# Docker Image {#docker-image}
@@ -93,13 +94,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # เปลี่ยนสิ่งนี้สำหรับการปรับใช้ที่ไม่ใช่ภายในเครื่อง
POSTGRES_DB: snapotter
volumes:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
interval: 10s
timeout: 5s
retries: 12
@@ -140,9 +141,9 @@ volumes:
| แท็ก | คำอธิบาย |
|-----|------------|
| `latest` | รุ่นล่าสุด |
| `1.11.0` | เวอร์ชันที่ระบุแน่นอน |
| `1.11` | patch ล่าสุดใน 1.11.x |
| `1` | minor ล่าสุดใน 1.x |
| `2.1.0` | เวอร์ชันที่ระบุแน่นอน |
| `2.1` | patch ล่าสุดใน 2.1.x |
| `2` | minor ล่าสุดใน 2.x |
## แพลตฟอร์ม {#platforms}
+28 -61
View File
@@ -1,8 +1,9 @@
---
description: "ติดตั้ง SnapOtter ด้วย Docker ในคำสั่งเดียว รวมถึงการตั้งค่า Docker Compose การ build จากซอร์ส และภาพรวมฟีเจอร์ทั้งหมด"
i18n_output_hash: 5353dda97d38
i18n_source_hash: 68bf7f60b68d
i18n_provenance: human
i18n_source_hash: 8040133a6982
i18n_provenance: machine
i18n_output_hash: 8e92205fb44d
i18n_hash_version: 2
---
# Getting Started {#getting-started}
@@ -17,7 +18,7 @@ i18n_provenance: human
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
```
คอนเทนเนอร์เดียวนี้รันทุกอย่างที่จำเป็น: เมื่อไม่ได้ตั้งค่า `DATABASE_URL` มันจะเริ่ม PostgreSQL และ Redis ของตัวเองบนอินเทอร์เฟซ loopback (โหมด embedded) และเก็บข้อมูลทั้งหมดไว้ในวลุ่ม `SnapOtter-data` นี่คือวิธีที่เร็วที่สุดในการลอง SnapOtter หรือ self-host บน homelab สำหรับโปรดักชัน ให้รันสแตก [Docker Compose](#docker-compose) ด้านล่าง ซึ่งเก็บ PostgreSQL และ Redis ไว้ในคอนเทนเนอร์ของตัวเอง โหมด embedded รันเป็น root (ค่าเริ่มต้น) และปิดโดยอัตโนมัติทันทีที่คุณตั้งค่า `DATABASE_URL`
คอนเทนเนอร์เดียวนี้รันทุกสิ่งที่ต้องการ: โดยไม่ต้องตั้งค่า `DATABASE_URL` คอนเทนเนอร์จะเริ่มต้น PostgreSQL และ Redis ของตัวเองบนอินเทอร์เฟซแบบย้อนกลับ (โหมดฝังตัว) และเก็บข้อมูลทั้งหมดไว้ในวลุ่ม `SnapOtter-data` นี่เป็นวิธีที่เร็วที่สุดในการลองใช้ SnapOtter หรือโฮสต์เองบนโฮมแล็บ สำหรับการใช้งานจริง ให้ใช้ [canonical Docker Compose stack](#docker-compose) ซึ่งจะเก็บ PostgreSQL และ Redis ไว้ในคอนเทนเนอร์ของตัวเอง โหมดฝังตัวจะทำงานในฐานะรูท (ค่าเริ่มต้น) และปิดโดยอัตโนมัติทันทีที่คุณตั้งค่า `DATABASE_URL`
หากกำลังติดตั้งบน Raspberry Pi แล็ปท็อปเครื่องเก่า หรือ VPS ขนาดเล็ก ดู [Low-Resource Setups](/th/guide/low-resource) สำหรับคู่มือทีละขั้นที่ปรับจูนมาแล้ว และสิ่งที่ควรคาดหวังจากฮาร์ดแวร์ที่จำกัด
@@ -40,7 +41,7 @@ SnapOtter มีการวิเคราะห์ผลิตภัณฑ์
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest
```
ต้องใช้ [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) จะสำรองไปใช้ CPU โดยอัตโนมัติเมื่อไม่มี CUDA ปัจจุบันยังไม่รองรับการเร่งความเร็วด้วย iGPU ของ Intel/AMD ผ่าน VA-API, Quick Sync หรือ OpenCL สำหรับการอนุมาน AI ดู [Docker Tags](/th/guide/docker-tags) สำหรับผลการทดสอบประสิทธิภาพ
ต้องใช้ [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) ถอยกลับไปที่ CPU โดยอัตโนมัติเมื่อ CUDA ไม่พร้อมใช้งาน การเร่งความเร็ว Intel/AMD iGPU ผ่าน VA-API, Quick Sync หรือ OpenCL ไม่รองรับการอนุมาน AI ในปัจจุบัน ดู [แท็กนักเทียบท่า](/th/guide/docker-tags) สำหรับการวัดประสิทธิภาพ หากเครื่องมือ AI ทำงานบน CPU แม้ว่าจะเป็น `--gpus all` โปรดดู [ตรวจสอบการเร่งความเร็ว GPU](/th/guide/deployment#verify-gpu-acceleration)
:::
::: details มีบน GHCR ด้วย
@@ -51,67 +52,33 @@ docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snap
ทั้งสอง registry เผยแพร่อิมเมจเดียวกันในทุกรีลีส
:::
## Docker Compose {#docker-compose}
## นักเทียบท่าเขียน {#docker-compose}
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest
ports:
- "1349:1349"
volumes:
- SnapOtter-data:/data
environment:
- AUTH_ENABLED=true
- DEFAULT_USERNAME=admin
- DEFAULT_PASSWORD=admin
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
- REDIS_URL=redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
ใช้ไฟล์ที่ใช้งานจริงที่ได้รับการดูแลและทดสอบกับแต่ละรีลีส แทนที่จะคัดลอกตัวอย่างการเขียนแบบย่อจากหน้านี้:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_DB: snapotter
volumes:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
interval: 10s
timeout: 5s
retries: 12
```bash
install -d -m 700 snapotter && cd snapotter
curl --proto '=https' --tlsv1.2 -fsSLo docker-compose.yml \
https://raw.githubusercontent.com/snapotter-hq/SnapOtter/v2.1.0/docker/docker-compose.yml
redis:
image: redis:8-alpine
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
volumes:
- SnapOtter-redisdata:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 12
# Keep generated service credentials out of shell history and world-readable files.
umask 077
POSTGRES_PASSWORD="$(openssl rand -hex 32)"
REDIS_PASSWORD="$(openssl rand -hex 32)"
printf 'POSTGRES_PASSWORD=%s\nREDIS_PASSWORD=%s\n' \
"$POSTGRES_PASSWORD" "$REDIS_PASSWORD" > .env
volumes:
SnapOtter-data:
SnapOtter-pgdata:
SnapOtter-redisdata:
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d --no-build
```
ดู [Configuration](/th/guide/configuration) สำหรับตัวแปรสภาพแวดล้อมทั้งหมด
Canonical [`docker/docker-compose.yml`](https://github.com/snapotter-hq/SnapOtter/blob/v2.1.0/docker/docker-compose.yml) ประกอบด้วยรันไทม์วอลุ่มทั้งสี่ การตรวจสอบสภาพ ขีดจำกัดทรัพยากร การกำหนดค่า Redis ที่คงทน ฐานข้อมูล/อิมเมจแคชที่ปักหมุดไว้ และการทำให้คอนเทนเนอร์ปัจจุบันแข็งตัว เปลี่ยนรหัสผ่านผู้ดูแลระบบเริ่มต้นทันทีหลังจากเข้าสู่ระบบครั้งแรก สำหรับการปรับใช้ที่ทำซ้ำได้ ให้ปักหมุดอิมเมจแอปพลิเคชัน SnapOtter ไว้ที่แท็ก release หรือแยกย่อยที่คุณตรวจสอบแล้ว แทนที่จะติดตาม `latest`
ดู [การกำหนดค่า](/th/guide/configuration) สำหรับตัวแปรสภาพแวดล้อมทั้งหมด และ [ความปลอดภัยและการป้องกัน](/th/guide/security) สำหรับความลับ นโยบายเครือข่าย และคำแนะนำในการสำรองข้อมูล
## Build from Source {#build-from-source}
**ข้อกำหนดเบื้องต้น:** Node.js 22+, pnpm 9+, Docker (สำหรับ Postgres + Redis), Python 3.10+ (สำหรับฟีเจอร์ AI), Git
**ข้อกำหนดเบื้องต้น:** Node.js 22.22+, pnpm 9+, Docker (สำหรับ Postgres + Redis), Python 3.11+ (สำหรับฟีเจอร์ AI), Git
```bash
git clone https://github.com/snapotter-hq/SnapOtter.git
@@ -121,7 +88,7 @@ pnpm install
pnpm dev
```
- Frontend: [http://localhost:1349](http://localhost:1349)
- Frontend: [http://localhost:1351](http://localhost:1351)
- Backend: [http://localhost:13490](http://localhost:13490)
## What You Can Do {#what-you-can-do}
@@ -130,11 +97,11 @@ pnpm dev
| โมดัลลิตี | จำนวน | เครื่องมือตัวอย่าง |
|----------|-------|---------------|
| **รูปภาพ** | 105 | ปรับขนาด, ครอป, บีบอัด, แปลง, ลบพื้นหลัง, ขยายภาพ, OCR, ลายน้ำ, คอลลาจ, ลงสี, เครื่องมือ GIF, พรีเซ็ตรูปแบบ |
| **รูปภาพ** | 107 | ปรับขนาด, ครอป, บีบอัด, แปลง, ลบพื้นหลัง, ขยายภาพ, OCR, ลายน้ำ, คอลลาจ, ลงสี, เครื่องมือ GIF, พรีเซ็ตรูปแบบ |
| **วิดีโอ** | 57 | ตัด, ครอป, บีบอัด, แปลง, รวม, แยกเสียง, คำบรรยายอัตโนมัติ, วิดีโอเป็น GIF, ปรับขนาด, ทำให้ภาพนิ่ง, พรีเซ็ตรูปแบบ |
| **เสียง** | 27 | ตัด, รวม, แปลง, นอร์มัลไลซ์, ลดสัญญาณรบกวน, ถอดเสียง, ปรับระดับเสียง, เฟด, สร้างริงโทน, พรีเซ็ตรูปแบบ |
| **PDF / เอกสาร** | 42 | รวม, แยก, บีบอัด, OCR, ลายน้ำ, ปกปิดข้อมูล, Word เป็น PDF, Excel เป็น PDF, หมุน, ป้องกัน, ซ่อมแซม |
| **ไฟล์** | 10 | CSV เป็น JSON, JSON เป็น XML, รวม CSV, แยก CSV, สร้าง ZIP, แตก ZIP, สร้างแผนภูมิ, YAML/JSON |
| **PDF / เอกสาร** | 29 | รวม, แยก, บีบอัด, OCR, ลายน้ำ, ปกปิดข้อมูล, Word เป็น PDF, Excel เป็น PDF, หมุน, ป้องกัน, ซ่อมแซม |
| **ไฟล์** | 23 | CSV เป็น JSON, JSON เป็น XML, รวม CSV, แยก CSV, สร้าง ZIP, แตก ZIP, สร้างแผนภูมิ, YAML/JSON |
### Pipelines {#pipelines}
+4 -3
View File
@@ -1,7 +1,8 @@
---
i18n_source_hash: f5de74aee1b9
i18n_source_hash: 521c03a6416c
i18n_provenance: machine
i18n_output_hash: 9c3979ddfb1f
i18n_output_hash: 9c99a77621ae
i18n_hash_version: 2
---
# Low-Resource Setups {#low-resource-setups}
@@ -59,7 +60,7 @@ services:
image: postgres:17-alpine
environment:
- POSTGRES_USER=snapotter
- POSTGRES_PASSWORD=snapotter
- POSTGRES_PASSWORD=snapotter # เปลี่ยนสิ่งนี้สำหรับการปรับใช้ที่ไม่ใช่ภายในเครื่อง
- POSTGRES_DB=snapotter
volumes:
- ./postgres-data:/var/lib/postgresql/data
+12 -7
View File
@@ -1,8 +1,9 @@
---
description: "ตั้งค่าการจัดสรร SCIM 2.0 เพื่อซิงก์ผู้ใช้และกลุ่มจากผู้ให้บริการข้อมูลประจำตัว (identity provider) ของคุณไปยัง SnapOtter ครอบคลุม Okta, Azure AD / Entra ID และการผสานรวมแบบกำหนดเอง"
i18n_source_hash: bbd50119ec12
i18n_source_hash: 06ee702b386e
i18n_provenance: human
i18n_output_hash: 8629fd86555f
i18n_output_hash: e8ab3b07c519
i18n_hash_version: 2
---
# การจัดสรรด้วย SCIM {#scim-provisioning}
@@ -17,7 +18,7 @@ SnapOtter รองรับ SCIM 2.0 (System for Cross-domain Identity Manageme
- อินสแตนซ์ SnapOtter ที่ทำงานอยู่และเข้าถึงได้ผ่าน URL สาธารณะ
- คีย์ไลเซนส์ enterprise ที่มีคุณสมบัติ `scim`
- สิทธิ์ผู้ดูแลระบบใน SnapOtter (ต้องมีสิทธิ์ `users:manage` เพื่อสร้างหรือเพิกถอนโทเคน SCIM)
- บัญชี SnapOtter `admin` ในตัวพร้อมชุดสิทธิ์ที่มีผลเต็มรูปแบบ บทบาทที่กำหนดเองที่ได้รับมอบสิทธิ์หรือคีย์ API ของผู้ดูแลระบบที่ขาดสิทธิ์ของผู้ดูแลระบบไม่สามารถสร้างหรือเพิกถอนโทเคน SCIM ส่วนกลางได้
- สิทธิ์ผู้ดูแลระบบในการตั้งค่าการจัดสรรของผู้ให้บริการข้อมูลประจำตัวของคุณ
## เริ่มต้นใช้งานอย่างรวดเร็ว {#quick-start}
@@ -34,7 +35,7 @@ curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
```json
{
"token": "a1b2c3d4e5f6...",
"token": "so_scim_v2_a1b2c3d4e5f6...",
"message": "Save this token - it cannot be retrieved again"
}
```
@@ -49,15 +50,19 @@ curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
### การสร้างโทเคน {#generating-a-token}
`POST /api/v1/enterprise/scim/token` สร้างโทเคน SCIM ใหม่ ปลายทางนี้ต้องมีเซสชันที่ถูกต้องพร้อมสิทธิ์ `users:manage`
`POST /api/v1/enterprise/scim/token` สร้างโทเคน SCIM ใหม่ เนื่องจากโทเค็นสามารถจัดเตรียมและเปลี่ยนผู้ใช้ข้ามอินสแตนซ์ได้ ตำแหน่งข้อมูลนี้จึงต้องมีบทบาท `admin` ในตัวพร้อมชุดสิทธิ์ผู้ดูแลระบบที่มีผลสมบูรณ์ การถือ `users:manage` ในบทบาทที่กำหนดเองนั้นไม่เพียงพอ
โทเคนจะถูกคืนค่าเป็นข้อความธรรมดาเพียงครั้งเดียวเท่านั้น SnapOtter จัดเก็บเฉพาะแฮชแบบ scrypt เท่านั้น หากคุณทำโทเคนหาย ให้เพิกถอนและสร้างใหม่
มีโทเคน SCIM ที่ใช้งานได้เพียงหนึ่งโทเคนในแต่ละครั้ง การสร้างโทเคนใหม่จะแทนที่โทเคนก่อนหน้า
::: warning โทเค็นออกใหม่หลังจากอัปเกรด
โทเค็น SCIM ที่ไม่มีเวอร์ชันเดิมถูกปฏิเสธ หลังจากอัปเกรดเป็นรุ่นที่ออกโทเค็น `so_scim_v2_...` แล้ว ให้สร้างโทเค็นใหม่และอัปเดตผู้ให้บริการข้อมูลประจำตัวของคุณก่อนดำเนินการจัดสรรต่อ
:::
### การเพิกถอนโทเคน {#revoking-a-token}
`DELETE /api/v1/enterprise/scim/token` เพิกถอนโทเคน SCIM ปัจจุบัน ปลายทางนี้ก็ต้องมี `users:manage` เช่นกั
`DELETE /api/v1/enterprise/scim/token` เพิกถอนโทเคน SCIM ปัจจุบัน มีข้อกำหนดผู้ดูแลระบบในตัวเต็มรูปแบบเหมือนกับการสร้างโทเค็
### การจำกัดอัตรา {#rate-limiting}
@@ -279,7 +284,7 @@ Azure จัดสรรผู้ใช้และกลุ่มตามร
### 401 "Invalid token" {#_401-invalid-token}
โทเคไม่ตรงกับแฮชที่จัดเก็บไว้ กรณีนี้เกิดขึ้นหากโทเคนถูกเพิกถอนและสร้างใหม่ อัปเดตโทเคนในการตั้งค่าการจัดสรรของ IdP ของคุณ
โทเค็นมีรูปแบบไม่ถูกต้อง ใช้รูปแบบที่เลิกใช้แล้ว หรือไม่ตรงกับแฮชที่เก็บไว้ สร้างโทเค็น `so_scim_v2_...` ปัจจุบันและอัปเดตโทเคนในการตั้งค่าการจัดสรรของ IdP
### 401 "SCIM not configured" {#_401-scim-not-configured}
+94 -166
View File
@@ -1,8 +1,9 @@
---
description: "คู่มือการเสริมความแข็งแกร่งด้านความปลอดภัยสำหรับ SnapOtter ความปลอดภัยของคอนเทนเนอร์ การแยกเครือข่าย Docker secrets การปรับใช้ Kubernetes และอาร์ทิแฟกต์ด้านการปฏิบัติตามข้อกำหนด"
i18n_source_hash: 986f7658430c
i18n_provenance: human
i18n_output_hash: 3c4f44580e5e
i18n_source_hash: 9ff337fa0417
i18n_provenance: machine
i18n_output_hash: 06f28d0ea62d
i18n_hash_version: 2
---
# Security & Hardening {#security-hardening}
@@ -11,133 +12,42 @@ SnapOtter ประมวลผลไฟล์ทั้งหมดบนโค
คอนเทนเนอร์รันเป็นผู้ใช้ที่ไม่ใช่ root โดยเฉพาะ (`snapotter`) โดยตัด Linux capabilities ทั้งหมดออก ยกเว้นชุดขั้นต่ำที่จำเป็น สำหรับนโยบายการเปิดเผยช่องโหว่ฉบับเต็มและสถาปัตยกรรมความปลอดภัย ดู [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) บน GitHub
## Container Hardening {#container-hardening}
## การชุบแข็งตู้คอนเทนเนอร์ {#container-hardening}
[docker-compose.yml เริ่มต้น](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) มีการเสริมความแข็งแกร่งด้านความปลอดภัยระดับโปรดักชัน นี่คือรายละเอียดของแต่ละตัวเลือกและเหตุผลที่มันสำคัญ:
ไฟล์เขียน Canonical [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) เป็นแหล่งที่มาของความจริง อย่าคัดลอกตัวอย่างย่อไปสู่การใช้งานจริง ปรับใช้ไฟล์จากแท็ก release ที่คุณตรวจสอบแล้ว
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
ports:
# Bind to localhost only for internet-facing deployments:
- "127.0.0.1:1349:1349"
volumes:
- SnapOtter-data:/data
- SnapOtter-workspace:/tmp/workspace
environment:
- AUTH_ENABLED=true
- DEFAULT_PASSWORD=change-me-immediately
- RATE_LIMIT_PER_MIN=1000
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
- REDIS_URL=redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
สแต็กทั้งสองใช้การควบคุมต่อไปนี้:
# --- Resource limits ---
mem_limit: 6g # Prevents runaway memory from crashing the host
memswap_limit: 6g # No swap - fail fast instead of degrading the host
cpus: 4 # Cap CPU usage to 4 cores
pids_limit: 512 # Prevents fork bombs
- ขีดจำกัดหน่วยความจำ, การสลับ, CPU และ PID มีการประมวลผลแบบเนทีฟแบบควบคุมไม่ได้
- ทุกบริการจะลดความสามารถของ Linux ทั้งหมด แอปพลิเคชันเพิ่มกลับเฉพาะ `CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL` สำหรับการเป็นเจ้าของโวลุ่ม การลดการระบุตัวตน `gosu` ทางเดียว และการส่งต่อสัญญาณที่สวยงาม PostgreSQL และ Redis ได้รับเฉพาะส่วนย่อยที่ต้องการสำหรับจุดเข้าใช้งานอย่างเป็นทางการเท่านั้น
- `security_opt: [no-new-privileges:true]` ป้องกันไม่ให้กระบวนการในแอปพลิเคชัน, PostgreSQL และคอนเทนเนอร์ Redis ได้รับสิทธิพิเศษเพิ่มเติม สิ่งนี้ยังคงเข้ากันได้กับ `gosu`: จุดเข้าใช้งานเริ่มต้นในฐานะรูท เตรียมวอลุ่ม และส่งไปยังผู้ใช้ `snapotter` เฉพาะเท่านั้น
- อินพุตรูปภาพ PostgreSQL และ Redis ถูกตรึงโดยไดเจสต์ นอกจากนี้ ควรปักหมุดแอปพลิเคชันไว้ที่แท็ก Release ที่ได้รับการยืนยันหรือแยกย่อย แทนที่จะปักหมุด `latest`
- การตรวจสอบประสิทธิภาพการทำงาน, การหมุนเวียนบันทึก JSON แบบมีขอบเขต, Redis AOF ที่คงทน และนโยบายการรีสตาร์ทจะถูกกำหนดไว้ที่ส่วนกลางในไฟล์ Canonical
# --- Capability restrictions ---
cap_drop:
- ALL # Drop ALL Linux capabilities first
cap_add:
- CHOWN # Needed for volume permission setup
- SETUID # Needed for gosu privilege drop (root -> snapotter)
- SETGID # Needed for gosu privilege drop
- DAC_OVERRIDE # Needed for volume permission setup
- FOWNER # Needed for volume permission setup
สำหรับการปรับใช้ผ่านอินเทอร์เน็ต ให้ผูกพอร์ต 1349 เข้ากับลูปแบ็คและยุติ TLS ที่พร็อกซีย้อนกลับที่ได้รับการดูแล สร้างข้อมูลรับรอง PostgreSQL และ Redis ที่ไม่ซ้ำกัน จัดเก็บข้อมูลลับในไฟล์ที่ได้รับการป้องกันหรือเครื่องมือจัดการความลับ และเปลี่ยนรหัสผ่านผู้ดูแลระบบเริ่มต้นทันที
# --- Logging ---
logging:
driver: json-file
options:
max-size: "50m" # Rotate logs at 50 MB
max-file: "5" # Keep 5 rotated log files
### ทำไม `read_only` ถึงไม่ได้ตั้งค่า {#why-read-only-is-not-set}
# --- Health check ---
healthcheck:
test: ["CMD", "curl", "-sf", "--max-time", "5", "http://localhost:1349/api/v1/health"]
interval: 30s
timeout: 5s
start_period: 60s
retries: 3
ไม่ได้ตั้งค่า `read_only: true` เนื่องจากการรีแมป PUID/PGID เขียนไปยัง `/etc/passwd` และ `/etc/group` เมื่อเริ่มต้น หากคุณใช้แฟล็ก `--user` ของ Docker หรือ Kubernetes `runAsUser` แทน PUID/PGID คุณสามารถเปิดใช้งานระบบไฟล์รูทแบบอ่านอย่างเดียวได้อย่างปลอดภัย
shm_size: "2gb" # Required for Python ML shared memory
restart: unless-stopped
## การแยกเครือข่าย {#network-isolation}
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_DB: snapotter
volumes:
- SnapOtter-pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
interval: 10s
timeout: 5s
retries: 12
start_period: 15s
การประมวลผลไฟล์เป็นแบบโลคัล แต่การติดตั้งเริ่มต้นคือ **ไม่ใช่ระบบที่ไม่มีทางออก** การวิเคราะห์ผลิตภัณฑ์แบบไม่เปิดเผยตัวตนใช้ PostHog และการรายงานข้อขัดข้องจะใช้ Sentry เมื่อเปิดใช้งานการวัดและส่งข้อมูลทางไกล ตั้งค่า `SNAPOTTER_TELEMETRY=0` (หรือปิดใช้งานการวิเคราะห์ภายใต้การตั้งค่า > ระบบ > ความเป็นส่วนตัว) เพื่อปิดทั้งสองอย่าง SnapOtter จะไม่รวมไฟล์ที่อัพโหลด ชื่อไฟล์ เอาต์พุต OCR ข้อความในเอกสาร หรือเนื้อหาไฟล์อื่น ๆ ในเหตุการณ์เหล่านั้น
redis:
image: redis:8-alpine
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
volumes:
- SnapOtter-redisdata:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
การรับส่งข้อมูลขาออกอื่นๆ ขับเคลื่อนด้วยฟีเจอร์: ดาวน์โหลดการติดตั้งชุด AI/โมเดล อินพุตรีลีสที่เซ็นชื่อ; การนำเข้า URL ดึง URL สาธารณะที่ผู้ใช้ร้องขอ และการกำหนดค่า OIDC, SAML, OpenTelemetry, webhooks, พื้นที่เก็บข้อมูลที่เข้ากันได้กับ S3 หรือการบูรณาการที่คล้ายกันที่กำหนดค่าไว้อย่างชัดเจน จะติดต่อกับปลายทางที่ผู้ดูแลระบบเลือก การดาวน์โหลดโมเดลขณะรันไทม์ถูกปิดใช้งานโดยค่าเริ่มต้น ตั้งค่า `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=1` เฉพาะเมื่อต้องการเปิดใช้การดาวน์โหลดสำรองอัตโนมัติอย่างชัดเจน [การนำเข้าบันเดิลออฟไลน์](/th/guide/deployment) สามารถจัดเตรียมฟีเจอร์ AI โดยไม่ต้องมีโมเดลรันไทม์ขาออก
volumes:
SnapOtter-data:
SnapOtter-workspace:
SnapOtter-pgdata:
SnapOtter-redisdata:
```
**คำแนะนำไฟร์วอลล์:**
### Why `no-new-privileges` Is Not Set {#why-no-new-privileges-is-not-set}
`security_opt: [no-new-privileges:true]` ถูกละไว้โดยตั้งใจ entrypoint เริ่มเป็น root เพื่อแก้ไขความเป็นเจ้าของของวอลุ่ม จากนั้นลดสิทธิ์เป็นผู้ใช้ `snapotter` ผ่าน [gosu](https://github.com/tianon/gosu) ซึ่งต้องใช้ setuid เมื่อการลดสิทธิ์เสร็จสมบูรณ์ กระบวนการจะรันเป็น `snapotter` โดยตัด capabilities ทั้งหมดออก ยกเว้นห้ารายการที่ระบุไว้ด้านบน
หากคุณใช้ Kubernetes หรือแฟล็ก `--user` ของ Docker เพื่อรันเป็น non-root โดยตรง (ข้าม gosu) การเปิดใช้ `no-new-privileges` ก็ปลอดภัย
### Why `read_only` Is Not Set {#why-read-only-is-not-set}
`read_only: true` ไม่ได้ถูกตั้งค่า เพราะการรีแมป PUID/PGID เขียนลง `/etc/passwd` และ `/etc/group` ตอนเริ่มทำงาน หากคุณใช้แฟล็ก `--user` ของ Docker หรือ `runAsUser` ของ Kubernetes แทน PUID/PGID คุณสามารถเปิดใช้ระบบไฟล์รากแบบอ่านอย่างเดียวได้อย่างปลอดภัย
## Network Isolation {#network-isolation}
ระหว่างการทำงานปกติ คอนเทนเนอร์ทำการเชื่อมต่อเครือข่ายขาออก **เป็นศูนย์** การประมวลผลไฟล์ทั้งหมดเกิดขึ้นในเครื่องโดยใช้ไลบรารีที่มาพร้อมกับตัวโปรแกรม
```
Browser --> Reverse Proxy (TLS) --> SnapOtter container --> (nothing)
```
ข้อยกเว้นเดียวคือ **การดาวน์โหลดโมเดล AI**: เมื่อผู้ใช้ติดตั้งบันเดิลฟีเจอร์ AI ผ่าน UI คอนเทนเนอร์จะดาวน์โหลดไฟล์เก็บบันเดิลที่สร้างไว้ล่วงหน้าจาก Hugging Face รวมถึงไฟล์โมเดลแต่ละไฟล์อีกไม่กี่ไฟล์จาก GitHub Releases, Google Storage และ PyPI การดาวน์โหลดเหล่านี้เกิดขึ้นครั้งเดียวต่อบันเดิลและเก็บไว้ในวอลุ่ม `/data`
**คำแนะนำเรื่องไฟร์วอลล์:**
| สถานการณ์ | กฎขาออก |
|สถานการณ์|กฎขาออก|
|---|---|
| Air-gapped (ไม่มี AI) | บล็อกทราฟฟิกขาออกทั้งหมดจากคอนเทนเนอร์ |
| ต้องการบันเดิล AI | อนุญาต HTTPS ไปยัง `huggingface.co`, `*.xethub.hf.co`, `cdn-lfs.huggingface.co`, `github.com`, `objects.githubusercontent.com`, `storage.googleapis.com`, `pypi.org`, `files.pythonhosted.org` ระหว่างการติดตั้ง จากนั้นบล็อก |
| หลังติดตั้ง 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/object-storage ที่ผู้ดูแลระบบกำหนดค่าไว้เท่านั้น|
ไฟล์เก็บบันเดิลถูกให้บริการจาก Xet storage ของ Hugging Face ซึ่งถ่ายโอนผ่าน endpoint `*.xethub.hf.co` แบบขนาน และเป็นสิ่งที่ทำให้การดาวน์โหลดบันเดิลขนาดหลาย GB รวดเร็ว หากไฟร์วอลล์ของคุณอนุญาต `huggingface.co` แต่บล็อก `*.xethub.hf.co` การติดตั้งยังคงสำเร็จ แต่จะสำรองไปใช้การดาวน์โหลดแบบสตรีมเดียวที่ช้ากว่า ดังนั้นให้ allowlist โฮสต์ Xet ไว้เพื่อคงอยู่ในเส้นทางที่เร็ว การติดตั้งแบบออฟไลน์ทั้งหมดสามารถข้ามทั้งหมดนี้และใช้ [Offline Bundle Import](/th/guide/deployment) แทนได้
ไฟล์เก็บถาวรแบบบันเดิลให้บริการจากพื้นที่จัดเก็บ Xet ของ Hugging Face ซึ่งถ่ายโอนผ่านตำแหน่งข้อมูล `*.xethub.hf.co` แบบขนาน และเป็นสิ่งที่ทำให้การดาวน์โหลดบันเดิลหลาย GB รวดเร็ว หากไฟร์วอลล์ของคุณอนุญาต `huggingface.co` แต่บล็อก `*.xethub.hf.co` การติดตั้งยังคงสำเร็จแต่กลับไปดาวน์โหลดแบบสตรีมเดียวที่ช้ากว่า ดังนั้นให้อนุญาตโฮสต์ Xet ให้อยู่ในเส้นทางที่รวดเร็ว การติดตั้งแบบออฟไลน์โดยสมบูรณ์สามารถข้ามทั้งหมดนี้ได้และใช้ [การนำเข้าชุดออฟไลน์](/th/guide/deployment) แทน
สำหรับการกำหนดค่า reverse proxy (Nginx, Traefik, Caddy, Cloudflare Tunnels) ดู [คู่มือ Deployment](/th/guide/deployment#reverse-proxy)
สำหรับการกำหนดค่าพร็อกซีย้อนกลับ (Nginx, Traefik, Caddy, Cloudflare Tunnels) โปรดดู [คู่มือการปรับใช้](/th/guide/deployment#reverse-proxy)
## Docker Secrets {#docker-secrets}
@@ -255,85 +165,103 @@ spec:
สำหรับการกำหนดขนาดทรัพยากร ดู [Hardware Requirements](/th/guide/deployment#hardware-requirements)
## Backup and Recovery {#backup-and-recovery}
## สำรองและกู้คืน {#backup-and-recovery}
ถานะถาวรถูกแบ่งออกเป็นสองวอลุ่ม:
แต็ก Compose ที่ใช้งานจริงจะกำหนดสี่วอลุ่ม หยุดข้อมูลเข้าและปล่อยให้งานที่ใช้งานอยู่เสร็จสิ้นก่อนทำการสำรองข้อมูลแบบประสานงาน ดังนั้น PostgreSQL, Redis และสถานะไฟล์จะอธิบายจุดเวลาเดียวกัน
| วอลุ่ม | เนื้อหา | สำคัญไหม? |
|ปริมาณ|สารบัญ|การบำบัดฟื้นฟู|
|---|---|---|
| `SnapOtter-pgdata` | ฐานข้อมูล PostgreSQL (ผู้ใช้, การตั้งค่า, ไปป์ไลน์, งาน, บันทึกการตรวจสอบ) | ใช่ |
| `/data` (วอลุ่มแอป) | ไฟล์ที่ผู้ใช้อัปโหลด, โมเดล AI, Python venv | บางส่วน (ดูด้านล่าง) |
|`SnapOtter-pgdata`|ผู้ใช้ PostgreSQL การตั้งค่า ไปป์ไลน์ งาน ข้อมูลเมตาของไฟล์ และบันทึกการตรวจสอบ|วิกฤต; ใช้การถ่ายโอนข้อมูลแบบลอจิคัลที่รวดเร็วเมื่อล้มเหลวสำหรับการกู้คืนแบบพกพา|
|`SnapOtter-data`|ออบเจ็กต์ไลบรารี บันทึก และสถานะ AI ที่บันทึกไว้ (`/data/files, /data/logs, /data/ai, /data/ai/venv`)|สำรองข้อมูลทั้งหมด เพื่อประหยัดพื้นที่ จงละเว้นสถานะ AI ทั้งหมดอย่างจงใจ และติดตั้งบันเดิลใหม่|
|`SnapOtter-redisdata`|Redis AOF สำหรับสถานะคิว BullMQ ที่ทนทาน|สำรองข้อมูลหลังจากหยุดแอปชั่วคราวและบังคับให้ `SAVE`; จำเป็นต้องกลับมาทำงานต่อคิวอย่างแน่นอน|
|`SnapOtter-workspace`|คีย์การจัดเก็บอ็อบเจ็กต์ชั่วคราว (`/tmp/workspace/uploads, /tmp/workspace/outputs`)|อย่าสำรองข้อมูลหลังจากที่งานทั้งหมดหมดหรือยกเลิก อย่าทิ้งมันในขณะที่งานกำลังทำงานอยู่|
ภายในวอลุ่ม `/data`:
โดยปกติแล้ว เขียนคำนำหน้าชื่อวอลุ่มด้วยชื่อโปรเจ็กต์ แก้ไขวอลลุมแหล่งที่มาจริงจากคอนเทนเนอร์ที่เมาท์ แทนที่จะสมมติว่าชื่อที่แสดง เช่น `SnapOtter-data` เป็นชื่อวอลลุม Docker
| พาธ | เนื้อหา | สำคัญไหม? |
|---|---|---|
| `/data/uploads/`, `/data/outputs/` | ไฟล์ผู้ใช้และผลการประมวลผล | ใช่ |
| `/data/ai/` | ไฟล์โมเดล AI ที่ดาวน์โหลด | ไม่ (ดาวน์โหลดใหม่ได้) |
| `/data/venv/` | Python virtual environment | ไม่ (สร้างใหม่ตอนเริ่ม) |
### สำรองฐานข้อมูล {#database-backup}
### Database backup {#database-backup}
ใช้ `pg_dump` เพื่อสำรองฐานข้อมูลขณะที่สแตกกำลังรัน:
ใช้รูปแบบไฟล์เก็บถาวรที่กำหนดเองของ PostgreSQL และตรวจสอบไฟล์เก็บถาวรก่อนที่จะดำเนินการกับการสำรองข้อมูลว่าเสร็จสมบูรณ์:
```bash
# Dump the database
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
docker exec SnapOtter-postgres \
pg_dump --format=custom --no-owner -U snapotter snapotter > snapotter.dump
test -s snapotter.dump
docker exec -i SnapOtter-postgres pg_restore --list < snapotter.dump >/dev/null
# Restore into a fresh database
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
# Restore only into a fresh/disposable target first; any SQL error fails the command.
docker exec -i SnapOtter-postgres \
pg_restore --exit-on-error --clean --if-exists --no-owner \
-U snapotter -d snapotter < snapotter.dump
```
หรืออีกทางเลือกหนึ่ง ให้หยุดสแตกและ snapshot วอลุ่ม `SnapOtter-pgdata`:
ทดสอบการสำรองข้อมูลทุกครั้งโดยการกู้คืนลงในสแตกแยก ตรวจสอบบันทึกฐานข้อมูลและเช็คซัมไฟล์ และเริ่มต้นแอปพลิเคชัน `tests/qa/backup-restore-drill.sh` ของที่เก็บจะปล่อยเกตโดยอัตโนมัติกับ `QA_IMAGE` ที่ชัดเจน
หากแพลตฟอร์มของคุณใช้สแนปช็อตปริมาณที่สอดคล้องกับข้อขัดข้องแทน ให้หยุดทั้งสแต็กก่อนและสแน็ปช็อตวอลุ่มที่สำคัญทั้งหมดเป็นชุดเดียว สำเนาไดเรกทอรีข้อมูล PostgreSQL แบบ Raw จากคอนเทนเนอร์ที่ทำงานอยู่ไม่ใช่การสำรองข้อมูลแบบลอจิคัลที่รองรับ
### ไฟล์และคิวสำรอง {#file-and-queue-backup}
หยุดแอปพลิเคชันชั่วคราวก่อนจับปริมาณไฟล์และคิว ใช้ `docker inspect` เพื่อแก้ไขชื่อวอลุ่มจริง บังคับให้ Redis คงสถานะปัจจุบันไว้ และเก็บถาวรโดยคงความเป็นเจ้าของและสิทธิ์ไว้:
```bash
docker compose down
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
docker stop SnapOtter
docker exec SnapOtter-redis redis-cli -a "$REDIS_PASSWORD" --no-auth-warning SAVE
docker stop SnapOtter-redis
DATA_VOLUME="$(docker inspect SnapOtter --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')"
REDIS_VOLUME="$(docker inspect SnapOtter-redis --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')"
install -d -m 700 backup
docker run --rm -v "$DATA_VOLUME:/source:ro" -v "$PWD/backup:/backup" \
alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce tar czf /backup/snapotter-data.tar.gz -C /source .
docker run --rm -v "$REDIS_VOLUME:/source:ro" -v "$PWD/backup:/backup" \
alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce tar czf /backup/snapotter-redis.tar.gz -C /source .
sha256sum backup/snapotter-*.tar.gz > backup/SHA256SUMS
```
### User files backup {#user-files-backup}
รีสตาร์ท Redis ก่อนแอปพลิเคชัน หากคุณตั้งใจยกเว้น `/data/ai` ให้ลบทรีย่อย AI ทั้งหมด แทนที่จะเก็บบันทึก `installed.json` โดยไม่มีโมเดลหรือสภาพแวดล้อมเสมือน เก็บไฟล์สำรองเข้ารหัส ควบคุมการเข้าถึง และแยกจากโฮสต์ที่ใช้งาน SnapOtter
```bash
# Snapshot the app data volume (excluding re-downloadable AI models)
docker run --rm -v SnapOtter-data:/data -v $(pwd)/backup:/backup \
alpine tar czf /backup/snapotter-files.tar.gz \
--exclude='ai' --exclude='venv' -C /data .
```
## สิ่งประดิษฐ์การปฏิบัติตามข้อกำหนด {#compliance-artifacts}
โมเดล AI รวมกันมีขนาดสูงสุดราว 24 GB สำหรับบันเดิลทั้งหมด เนื่องจากมันดาวน์โหลดใหม่ได้ ให้ยกเว้น `/data/ai/` และ `/data/venv/` จากการสำรองข้อมูลเพื่อประหยัดพื้นที่ มีเพียงฐานข้อมูลและไฟล์ผู้ใช้เท่านั้นที่สำคัญ
SnapOtter แต่ละรุ่นมีอาร์ติแฟกต์ด้านความปลอดภัยต่อไปนี้:
## Compliance Artifacts {#compliance-artifacts}
แต่ละรีลีสของ SnapOtter มีอาร์ทิแฟกต์ด้านความปลอดภัยต่อไปนี้:
| อาร์ทิแฟกต์ | รูปแบบ | หาได้ที่ไหน |
| สิ่งประดิษฐ์ | รูปแบบ | จะหาได้ที่ไหน |
|---|---|---|
| SBOM (CycloneDX) | JSON | asset ของ [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.cdx.json` |
| SBOM (SPDX) | JSON | asset ของ [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.spdx.json` |
| การสแกนช่องโหว่ | Trivy JSON | asset ของ [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-trivy.json` |
| ปล่อยเรื่องผูกมัด | การรับรอง Canonical JSON + GitHub | [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases) เนื้อหา: `snapotter-v{version}-release-subjects.json` |
| เก็บถาวร SBOM | CycloneDX และ SPDX JSON | เนื้อหาที่เผยแพร่: `snapotter-v{version}-archive-linux-{arch}-sbom.{cdx,spdx}.json` |
| รูปภาพ SBOM | CycloneDX และ SPDX JSON | เนื้อหาที่เผยแพร่: `snapotter-v{version}-image-linux-{arch}-sbom.{cdx,spdx}.json` |
| การสแกนช่องโหว่ | Trivy JSON | เผยแพร่เนื้อหาที่มีคำนำหน้า `archive-linux-{arch}` หรือ `image-linux-{arch}` ที่ตรงกัน |
| การสแกนช่องโหว่ | SARIF | แท็บ [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) |
| การวิเคราะห์แบบสถิต | CodeQL (JS/TS + Python) | แท็บ [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security), รันรายสัปดาห์ + ต่อ PR |
| การตรวจสอบ dependency | GitHub native | การตรวจสอบต่อ PR ล้มเหลวเมื่อมีการเพิ่มความรุนแรงสูง |
| การตรวจสอบ dependency ของ Python | pip-audit | ล็อกการรัน CI ในทุก push |
| นโยบายความปลอดภัย | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) ในที่เก็บ |
| การอัปเดต dependency | Dependabot | PR อัตโนมัติรายสัปดาห์สำหรับ npm, pip, Docker, Actions |
| การวิเคราะห์แบบคงที่ | CodeQL (JS/TS + Python) | แท็บ [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) รันรายสัปดาห์ + ต่อ PR |
| การตรวจสอบการพึ่งพา | GitHub เนทิฟ | การตรวจสอบต่อ PR ล้มเหลวในการเพิ่มที่มีความรุนแรงสูง |
| การตรวจสอบการพึ่งพา Python | pip-audit | CI รันบันทึกทุกครั้งที่กด |
| นโยบายความปลอดภัย | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) ในพื้นที่เก็บข้อมูล |
| การอัปเดตการพึ่งพา | Dependabot | PR รายสัปดาห์อัตโนมัติสำหรับ npm, pip, Docker, Actions |
**การรันสแกนของคุณเอง:**
**เรียกใช้การสแกนของคุณเอง:**
ดาวน์โหลด SBOM จากรีลีสและสแกนด้วยเครื่องมือที่คุณต้องการ:
ดาวน์โหลดรายการหัวข้อการเผยแพร่และตรวจสอบว่าได้รับการยืนยันโดยเวิร์กโฟลว์การเผยแพร่:
```bash
gh attestation verify snapotter-v2.1.0-release-subjects.json \
--repo snapotter-hq/SnapOtter \
--signer-workflow snapotter-hq/SnapOtter/.github/workflows/release.yml
```
ไฟล์ Manifest จะบันทึก `releaseTag`, `releaseCommit` และ `workflowTriggerCommit` แยกกัน ตรวจสอบว่า `releaseCommit` เป็นคอมมิตที่ลอกออกจากแท็กที่ไม่เปลี่ยนรูปแบบ จากนั้นตรวจสอบการแยกย่อย SHA-256 ของไฟล์เก็บถาวร รูปภาพ SBOM หรือการสแกนที่คุณใช้โดยเทียบกับรายการใน `subjects` ความแตกต่างนี้มีเจตนา: การตรวจสอบการคอมมิตรีลีสที่สร้างขึ้นใหม่จะไม่เปลี่ยนเอกลักษณ์การคอมมิตในข้อมูลรับรอง OIDC ของเวิร์กโฟลว์
คุณยังสามารถสแกน SBOM ที่ดาวน์โหลดมาหรือรูปภาพได้โดยตรง:
```bash
# Scan with Grype using the CycloneDX SBOM
grype sbom:snapotter-v1.17.2-sbom.cdx.json
grype sbom:snapotter-v2.1.0-image-linux-amd64-sbom.cdx.json
# Scan with Trivy using the SPDX SBOM
trivy sbom snapotter-v1.17.2-sbom.spdx.json
trivy sbom snapotter-v2.1.0-image-linux-amd64-sbom.spdx.json
# Scan the Docker image directly
trivy image snapotter/snapotter:1.17.2
trivy image snapotter/snapotter:2.1.0
```
::: info
SBOM และการสแกนช่องโหว่สะท้อนอิมเมจที่เผยแพร่สำหรับรีลีสนั้นอย่างแน่นอน บันเดิลโมเดล AI ที่ติดตั้งหลังการปรับใช้ไม่ได้รวมอยู่ใน SBOM เนื่องจากดาวน์โหลดขณะรันไทม์
::: info
รูปภาพ SBOMs และการสแกนสะท้อนถึงรูปภาพเฉพาะทางสถาปัตยกรรมที่เผยแพร่สำหรับรุ่นนั้น ไฟล์เก็บถาวร SBOMs และการสแกนจะอธิบายไฟล์เก็บถาวรที่สร้างไว้ล่วงหน้าแยกกัน บันเดิลโมเดล AI ที่ติดตั้งหลังจากการปรับใช้จะไม่รวมอยู่ใน SBOMs เหล่านี้ เนื่องจากมีการดาวน์โหลดขณะรันไทม์
:::
+6 -2
View File
@@ -11,7 +11,7 @@ SnapOtter ประมวลผลไฟล์ในห้าโมดัลล
## รูปแบบรูปภาพ {#image-formats}
SnapOtter รองรับรูปแบบรูปภาพ 55+ รูปแบบสำหรับอินพุต และ 13 รูปแบบสำหรับเอาต์พุต
SnapOtter รองรับรูปแบบรูปภาพ 55+ รูปแบบสำหรับอินพุต และ 17 รูปแบบสำหรับเอาต์พุต
## รูปแบบอินพุต {#input-formats}
@@ -104,7 +104,7 @@ SnapOtter รองรับรูปแบบรูปภาพ 55+ รูป
| PAM | .pam | Sharp (native) | แผนที่ตามอำเภอใจ |
| PFM | .pfm | Sharp (native) | แผนที่แบบ float |
## รูปแบบเอาต์พุต (13) {#output-formats-13}
## รูปแบบเอาต์พุต (17) {#output-formats-13}
| รูปแบบ | ตัวเข้ารหัส | การควบคุมคุณภาพ | มีในเครื่องมือ |
|--------|---------|----------------|-------------|
@@ -121,6 +121,10 @@ SnapOtter รองรับรูปแบบรูปภาพ 55+ รูป
| ICO | ImageMagick CLI | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
| JP2 | opj_compress CLI | อัตราการบีบอัด | เครื่องมือแปลง |
| QOI | ตัวเข้ารหัสแบบอินไลน์ | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
| PSD | ImageMagick CLI | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
| PPM | ImageMagick CLI | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
| EPS | ImageMagick CLI | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
| TGA | ImageMagick CLI | ไม่สูญเสียคุณภาพ | เครื่องมือแปลง |
## รูปแบบวิดีโอ {#video-formats}
+13 -10
View File
@@ -1,8 +1,9 @@
---
description: "จัดการผู้ใช้ บทบาทในตัวและบทบาทกำหนดเอง สิทธิ์ API key ทีม เซสชัน และบันทึกการตรวจสอบใน SnapOtter"
i18n_source_hash: 5e28af686c96
i18n_source_hash: bea8955f3aff
i18n_provenance: human
i18n_output_hash: 28b3c25775a5
i18n_output_hash: 0e3f6328f403
i18n_hash_version: 2
---
# ผู้ใช้ บทบาท และสิทธิ์ {#users-roles-permissions}
@@ -82,12 +83,12 @@ SnapOtter มีบทบาทในตัวสามบทบาท ไม่
| `pipelines:all` | ดูและจัดการไปป์ไลน์ของผู้ใช้ทั้งหมด |
| `settings:read` | ดูการตั้งค่าอินสแตนซ์ |
| `settings:write` | แก้ไขการตั้งค่าอินสแตนซ์ |
| `users:manage` | สร้าง อัปเดต และลบบัญชีผู้ใช้ |
| `users:manage` | สร้างและจัดการบัญชีผู้ใช้ภายในขอบเขตอำนาจของนักแสดง |
| `teams:manage` | สร้าง อัปเดต และลบทีม |
| `features:manage` | ติดตั้งและจัดการบันเดิลฟีเจอร์ AI |
| `system:health` | เข้าถึงเอ็นด์พอยต์ health และ readiness |
| `audit:read` | ดูบันทึกการตรวจสอบและแสดงรายการบทบาท |
| `compliance:manage` | จัดการวงจร GDPR และฟีเจอร์การปฏิบัติตามข้อกำหนด |
| `compliance:manage` | จัดการวงจรการใช้งาน GDPR และฟีเจอร์การปฏิบัติตามข้อกำหนด การดำเนินการของผู้ใช้แบบทำลายล้างยังคงมีขอบเขตอำนาจ |
| `webhooks:manage` | กำหนดค่า webhook ขาออก |
| `security:manage` | จัดการการตั้งค่าความปลอดภัย (IP allowlist, การบังคับใช้ SSO) |
@@ -110,15 +111,17 @@ curl -X POST http://localhost:1349/api/v1/roles \
ชื่อบทบาทต้องมี 2-30 อักขระ เป็นตัวอักษรและตัวเลขพิมพ์เล็ก พร้อมยัติภังค์และขีดล่าง
### สิทธิ์ที่สงวนไว้สำหรับผู้ดูแลระบบ {#admin-reserved-permissions}
### ขอบเขตการบริหารที่ได้รับมอบหมาย {#delegated-administration-boundaries}
สิทธิ์สามรายการสงวนไว้สำหรับบทบาทในตัวและไม่สามารถกำหนดให้กับบทบาทกำหนดเองได้:
สิทธิ์ทั้ง 17 รายการสามารถมอบหมายผ่านบทบาทที่กำหนดเองได้ แต่สิทธิ์ผู้ดูแลระบบไม่ได้ทำให้บทบาทนั้นเทียบเท่ากับบทบาท `admin` ในตัว การกลายพันธุ์ของผู้ใช้ที่ได้รับอนุญาตโดย `users:manage` การดำเนินการทำลายล้างที่ได้รับอนุญาตโดย `compliance:manage` และการจัดการบทบาทแบบกำหนดเองที่ได้รับอนุญาตโดย `security:manage` อยู่ภายใต้ขอบเขตอำนาจปัจจุบันของนักแสดง:
- `compliance:manage`
- `webhooks:manage`
- `security:manage`
- บทบาทในตัวเป็นไปตาม `admin` > `editor` > `user`; บทบาทที่กำหนดเองอยู่ใต้บทบาทในตัว
- การอนุญาตของเป้าหมายจะต้องอยู่ภายใต้การอนุญาต **มีผล** ของนักแสดง คีย์ API ที่กำหนดขอบเขตจึงไม่สามารถใช้สิทธิ์ที่ละเว้นจากขอบเขตได้
- การเข้าถึงเครื่องมือของบทบาทเป้าหมายจะต้องอยู่ในการเข้าถึงเครื่องมือของนักแสดงเอง
- บัญชีที่ถูกปิดใช้งานจะถูกตรวจสอบกับบทบาทเดิมเมื่อบทบาทนั้นถูกบันทึกเป็น `disabled:<original-role>`
- การลบบทบาทที่กำหนดเองยังต้องได้รับสิทธิ์ในการกำหนดทางเลือกสำรอง `user` ในตัว สมาชิกที่พิการยังคงปิดการใช้งานเป็น `disabled:user`
roles API จะปฏิเสธคำขอใด ๆ ที่มีสิทธิ์เหล่านี้ มีเพียงบทบาท `admin` ในตัวเท่านั้นที่มีสิทธิ์เข้าถึง
ข้อมูลประจำตัวและการกำหนดค่าส่วนกลางมีความเข้มงวดมากขึ้น: การออกหรือเพิกถอนโทเค็น SCIM และการนำเข้าการกำหนดค่าอินสแตนซ์จำเป็นต้องมีบทบาท `admin` ในตัวที่มีสิทธิ์ผู้ดูแลระบบที่มีประสิทธิภาพโดยสมบูรณ์
### สิทธิ์ระดับเครื่องมือ {#tool-level-permissions}