Уся конфігурація виконується через змінні середовища. Кожна змінна має розумне значення за замовчуванням, тож SnapOtter працює «з коробки» без задання жодної з них.
## Змінні середовища {#environment-variables}
### Сервер {#server}
| Змінна | За замовчуванням | Опис |
|---|---|---|
| `PORT` | `1349` | Порт, який слухає сервер. |
| `RATE_LIMIT_PER_MIN` | `1000` | Максимальна кількість запитів за хвилину на одну IP. Задайте 0, щоб вимкнути обмеження частоти запитів. |
| `CORS_ORIGIN` | (порожньо) | Розділені комами дозволені джерела для CORS або порожньо лише для того самого джерела. |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Яким вузлам дозволено задавати IP клієнта через `X-Forwarded-For`. Значення за замовчуванням вірить лише вузлу з приватної мережі, тож зворотному проксі в мережі Docker або в локальній мережі довіра є, а підробленому заголовку від публічного клієнта немає. Задавайте `true`, лише якщо попереду стоїть підконтрольний вам проксі з публічною адресою. |
Дві булеві змінні нижче приймають лише `true`і`false`. Будь-що інше, чи то `1`, `yes` чи `on`, не проходить перевірку, і сервер завершує роботу, так і не почавши слухати.
| `AUTH_ENABLED` | `true` | Вимагати вхід. Задайте `false`, щоб працювати взагалі без облікових записів: тоді будь-який запит отримує права адміністратора, тож лишайте так лише в довіреній мережі. |
| `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` | (порожньо) | Ключ, від якого ви відходите під час ротації, у тому самому форматі. Задайте обидва на час ротації, щоб наявні рядки й далі розшифровувалися, а потім приберіть цей. |
Запустіть образ без `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` або скористайтеся адміністративним відмовленням у застосунку, щоб її вимкнути.
| `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` | Як часто виконується завдання очищення. |
-`/data` (app) - моделі AI, Python venv і файли користувача. Змонтуйте його, щоб зберігати завантажені файли та встановлені пакети AI між перезапусками.
-`/tmp/workspace` (app) - тимчасове сховище для файлів, що обробляються. Воно може бути ефемерним, але монтування уникає заповнення записуваного шару контейнера.
-`SnapOtter-pgdata` (postgres) - каталог даних PostgreSQL. Він містить усі реляційні дані (користувачі, налаштування, конвеєри, завдання, журнал аудиту). Робіть резервну копію через `pg_dump` або знімок тому.
-`SnapOtter-redisdata` (redis) - файл append-only Redis для стійких черг завдань.