mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
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.
188 lines
17 KiB
Markdown
188 lines
17 KiB
Markdown
---
|
||
description: "Усі змінні середовища SnapOtter зі значеннями за замовчуванням. Налаштуйте автентифікацію, сховище, моделі AI, аналітику тощо."
|
||
i18n_source_hash: 25970c776f7c
|
||
i18n_provenance: human
|
||
i18n_output_hash: 52fb4064af72
|
||
i18n_hash_version: 2
|
||
---
|
||
|
||
# Конфігурація {#configuration}
|
||
|
||
Уся конфігурація виконується через змінні середовища. Кожна змінна має розумне значення за замовчуванням, тож SnapOtter працює «з коробки» без задання жодної з них.
|
||
|
||
## Змінні середовища {#environment-variables}
|
||
|
||
### Сервер {#server}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `PORT` | `1349` | Порт, який слухає сервер. |
|
||
| `RATE_LIMIT_PER_MIN` | `1000` | Максимальна кількість запитів за хвилину на одну IP. Задайте 0, щоб вимкнути обмеження частоти запитів. |
|
||
| `CORS_ORIGIN` | (порожньо) | Розділені комами дозволені джерела для CORS або порожньо лише для того самого джерела. |
|
||
| `LOG_LEVEL` | `info` | Детальність журналювання. Одне з: `fatal`, `error`, `warn`, `info`, `debug`, `trace`. |
|
||
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Яким вузлам дозволено задавати IP клієнта через `X-Forwarded-For`. Значення за замовчуванням вірить лише вузлу з приватної мережі, тож зворотному проксі в мережі Docker або в локальній мережі довіра є, а підробленому заголовку від публічного клієнта немає. Задавайте `true`, лише якщо попереду стоїть підконтрольний вам проксі з публічною адресою. |
|
||
|
||
### Автентифікація {#authentication}
|
||
|
||
Дві булеві змінні нижче приймають лише `true` і `false`. Будь-що інше, чи то `1`, `yes` чи `on`, не проходить перевірку, і сервер завершує роботу, так і не почавши слухати.
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `AUTH_ENABLED` | `true` | Вимагати вхід. Задайте `false`, щоб працювати взагалі без облікових записів: тоді будь-який запит отримує права адміністратора, тож лишайте так лише в довіреній мережі. |
|
||
| `DEFAULT_USERNAME` | `admin` | Ім'я користувача для початкового облікового запису адміністратора. Використовується лише під час першого запуску. |
|
||
| `DEFAULT_PASSWORD` | `admin` | Пароль для початкового облікового запису адміністратора. Змініть його після першого входу. |
|
||
| `MAX_USERS` | `0` (необмежено) | Максимальна кількість зареєстрованих облікових записів користувачів. Задайте 0 для необмеженої кількості. |
|
||
| `SESSION_DURATION_HOURS` | `168` | Тривалість сеансу входу в годинах (за замовчуванням 7 днів). |
|
||
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | Задайте `true`, щоб пропустити примусовий запит на зміну пароля під час першого входу. |
|
||
|
||
### Сховище {#storage}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `STORAGE_MODE` | `local` | `local` або `s3`. S3 і MinIO потребують ліцензії з функцією s3_storage, а також змінних `S3_*` нижче. |
|
||
| `DATABASE_URL` | `postgres://snapotter:snapotter@localhost:5432/snapotter` | Рядок підключення до PostgreSQL. Стек Compose спрямовує його на власний сервіс `postgres`; лишіть його незаданим (разом із `REDIS_URL`), щоб отримати вбудований режим. |
|
||
| `REDIS_URL` | `redis://localhost:6379` | Рядок підключення до Redis (використовується для черг завдань BullMQ). Compose спрямовує його на власний сервіс `redis`. |
|
||
| `WORKSPACE_PATH` | `./tmp/workspace` | Каталог для тимчасових файлів під час обробки. Очищується автоматично. Образ задає `/tmp/workspace`. |
|
||
| `FILES_STORAGE_PATH` | `./data/files` | Каталог для постійних файлів користувача (завантажені зображення, збережені результати). Образ задає `/data/files`. |
|
||
|
||
### Об'єктне сховище S3 {#s3-object-storage}
|
||
|
||
Читається лише тоді, коли задано `STORAGE_MODE=s3`. Пропустіть будь-яку з трьох обов'язкових змінних, і запуск завершиться помилкою з назвою тієї змінної, яку ви не задали.
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `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` замість адресації за віртуальним хостом. |
|
||
| `S3_PREFIX` | (порожньо) | Префікс ключів, щоб один бакет міг обслуговувати кілька екземплярів. |
|
||
|
||
### Шифрування збережених даних {#encryption-at-rest}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `DATA_ENCRYPTION_KEY` | (порожньо) | 64 шістнадцяткові символи (32 байти). Шифрує чутливі налаштування, збережені в базі даних. Будь-що, що не є 64 шістнадцятковими символами, відхиляється під час запуску. |
|
||
| `DATA_ENCRYPTION_KEY_PREVIOUS` | (порожньо) | Ключ, від якого ви відходите під час ротації, у тому самому форматі. Задайте обидва на час ротації, щоб наявні рядки й далі розшифровувалися, а потім приберіть цей. |
|
||
|
||
### Вбудований режим {#embedded-mode}
|
||
|
||
Запустіть образ без `DATABASE_URL` і без `REDIS_URL`, і він запустить власні PostgreSQL 17 і Redis усередині контейнера, прив'язані до loopback, з усіма даними на томі `/data`. Це відновлює однокомандний досвід `docker run` для швидкого старту, домашньої лабораторії та оновлень з 1.x. Це шлях для зручності, а не продакшн-розгортання: для продакшну запускайте стек Compose з 3 контейнерів з окремими PostgreSQL і Redis. Вбудований режим вимагає запуску контейнера від root і несумісний із середовищами з довільним UID (OpenShift, Kubernetes `runAsNonRoot`); там використовуйте Compose.
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `EMBEDDED` | `auto` | Автоматично вмикається, коли і `DATABASE_URL`, і `REDIS_URL` не задано. Задайте `0`, щоб вимкнути (тоді застосунок швидко завершує роботу, якщо не задано зовнішні `DATABASE_URL`/`REDIS_URL`, замість тихого запуску бази даних усередині контейнера). |
|
||
| `REDIS_MAXMEMORY` | `512mb` | Обмеження пам'яті для вбудованого Redis (лише вбудований режим). Знизьте його на хостах з обмеженою пам'яттю, як-от Raspberry Pi. |
|
||
|
||
Оновлення з 1.x: покладіть вашу стару `snapotter.db` за адресою `/data/snapotter.db` у томі, і вбудований режим імпортує її у вбудований PostgreSQL під час першого запуску. Імпорт виконується один раз; наступні запуски його пропускають.
|
||
|
||
Примітка про телеметрію: вбудований режим успадковує стандартну аналітику образу, як і будь-яка інша конфігурація. Опублікований образ постачається з увімкненою аналітикою; збирайте з `--build-arg SNAPOTTER_ANALYTICS=off` або скористайтеся адміністративним відмовленням у застосунку, щоб її вимкнути.
|
||
|
||
### Обмеження обробки {#processing-limits}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `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` (авто) | Максимальна кількість робочих потоків для обробки зображень. Задайте 0 для автовизначення на основі доступних ядер CPU. |
|
||
| `PROCESSING_TIMEOUT_S` | `0` (без обмеження) | Максимальний час обробки на один запит у секундах. Задайте 0 для відсутності таймауту. |
|
||
| `MAX_PIPELINE_STEPS` | `20` | Максимальна кількість кроків у конвеєрі. Задайте 0 для відсутності обмеження. |
|
||
| `MAX_CANVAS_PIXELS` | `0` (без обмеження) | Максимальний розмір полотна в пікселях для вихідних зображень. Задайте 0 для відсутності обмеження. |
|
||
| `MAX_SVG_SIZE_MB` | `50` | Найбільший SVG, який приймається перед очищенням, у мегабайтах. Тут `0` поводиться інакше, ніж у сусідніх рядках: він повністю знімає обмеження розміру до розбору, а не піднімає його, тож цю змінну краще лишити заданою. |
|
||
| `MAX_PDF_PAGES` | `0` (необмежено) | Максимальна кількість сторінок PDF для конвертації PDF-у-зображення. Задайте 0 для необмеженого. |
|
||
|
||
### Очищення {#cleanup}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `FILE_MAX_AGE_HOURS` | `72` | Як довго незбережені результати обробки (сирі завантаження та виводи інструментів) зберігаються перед автоматичним видаленням. Файли, які ви явно зберегли до бібліотеки Files, не зачіпаються й лишаються, доки ви їх не видалите. |
|
||
| `CLEANUP_INTERVAL_MINUTES` | `60` | Як часто виконується завдання очищення. |
|
||
|
||
### Зовнішній вигляд {#appearance}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `DEFAULT_THEME` | `light` | Типова тема для нових сеансів. `light`, `dark` або `system`. |
|
||
| `DEFAULT_LOCALE` | `en` | Типова мова інтерфейсу. |
|
||
| `DEFAULT_TOOL_VIEW` | `sidebar` | Типове компонування інструментів. `sidebar` або `fullscreen`. |
|
||
|
||
### Дозволи Docker {#docker-permissions}
|
||
|
||
| Змінна | За замовчуванням | Опис |
|
||
|---|---|---|
|
||
| `PUID` | `999` | Запускати процес контейнера з цим UID. Задайте відповідно до вашого хост-користувача для монтувань bind (`id -u`). |
|
||
| `PGID` | `999` | Запускати процес контейнера з цим GID. Задайте відповідно до вашої хост-групи для монтувань bind (`id -g`). |
|
||
|
||
## Приклад Docker {#docker-example}
|
||
|
||
```yaml
|
||
services:
|
||
SnapOtter:
|
||
image: snapotter/snapotter:latest
|
||
ports:
|
||
- "1349:1349"
|
||
volumes:
|
||
- SnapOtter-data:/data
|
||
- SnapOtter-workspace:/tmp/workspace
|
||
environment:
|
||
- AUTH_ENABLED=true
|
||
- DEFAULT_USERNAME=admin
|
||
- DEFAULT_PASSWORD=changeme
|
||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||
- REDIS_URL=redis://redis:6379
|
||
- MAX_UPLOAD_SIZE_MB=200
|
||
- CONCURRENT_JOBS=4
|
||
- FILE_MAX_AGE_HOURS=12
|
||
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 -d snapotter"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
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
|
||
|
||
volumes:
|
||
SnapOtter-data:
|
||
SnapOtter-workspace:
|
||
SnapOtter-pgdata:
|
||
SnapOtter-redisdata:
|
||
```
|
||
|
||
## Томи {#volumes}
|
||
|
||
Стек Docker Compose використовує чотири томи:
|
||
|
||
- `/data` (app) - моделі AI, Python venv і файли користувача. Змонтуйте його, щоб зберігати завантажені файли та встановлені пакети AI між перезапусками.
|
||
- `/tmp/workspace` (app) - тимчасове сховище для файлів, що обробляються. Воно може бути ефемерним, але монтування уникає заповнення записуваного шару контейнера.
|
||
- `SnapOtter-pgdata` (postgres) - каталог даних PostgreSQL. Він містить усі реляційні дані (користувачі, налаштування, конвеєри, завдання, журнал аудиту). Робіть резервну копію через `pg_dump` або знімок тому.
|
||
- `SnapOtter-redisdata` (redis) - файл append-only Redis для стійких черг завдань.
|