---
title: "Инсталиране на Quire с Docker Compose"
description: "Инсталирайте Quire на собствена инфраструктура чрез Docker Compose."
image: "https://docs.quirelms.com/og.png"
---

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

# Инсталиране на Quire с Docker Compose

<span id="installing-quire-with-docker-compose"></span>

Това е пълният продукт на един хост: LMS, фоновите задачи,
услугите за реално време и съвместно редактиране, както и всички незадължителни услуги,
активирани чрез профил. Архитектурата е описана в раздел 2 на `docs/architecture/23-ops.md`.

Другите цели: [Vercel](/bg/ops/vercel/) и [Cloudflare Workers](/bg/ops/cloudflare/) изпълняват
само уеб слоя. Информация за надстройване има в [upgrade.md](/bg/ops/upgrade/), а за архивиране и
пробно възстановяване — в [backup-restore.md](/bg/ops/backup-restore/).

## Необходими ресурси <!--quire:what-you-need-->

- Docker Engine 27 или по-нова версия с приставката Compose 2.30 или по-нова.
- 4 CPU ядра и 8 GB памет за стандартния стек; 8 ядра и 16 GB
  с `--profile full` (само ClamAV заема около 1,5 GB за сигнатури).
- DNS име за уеб слоя и второ за ненадеждно съдържание. Това трябва да са различни хостове: SCORM пакетите и каченият HTML работят от източника за съдържание, така че никога да не могат да четат бисквитките на LMS.
- За локален тест `lvh.me` и `*.localhost` водят към 127.0.0.1, както е зададено в `docker/.env.example`. Собствената услуга `proxy` в стека обслужва и двата източника чрез https и локален сертифициращ орган, затова не е нужно да се инсталира друго (вижте „TLS“).
- Портовете 80 и 443 трябва да са свободни на хоста (`QUIRE_PROXY_HTTP_PORT` и
  `QUIRE_PROXY_HTTPS_PORT` могат да ги променят).

## Първо стартиране <!--quire:first-run-->

```sh
QUIRE_APP_ORIGIN=https://learn.example.org \
QUIRE_CONTENT_ORIGIN=https://content.example-content.org \
QUIRE_SETUP_ADMIN_EMAIL=you@example.org \
  docker/scripts/init-env.sh
docker compose -f docker/compose.yaml up -d --build
docker compose -f docker/compose.yaml logs init
```

`docker/scripts/init-env.sh` създава `docker/.env` от `docker/.env.example`
и генерира всички тайни (пароли за базата, ключовете за подписване и главния ключ,
чифта ключове за стартиране на съдържанието), както и ключа за подписване на контрольната точка за одит в
`docker/secrets/audit-signing-key.pem`, който Compose монтира като тайна в worker-ите.
Нужни са само `sh`, `awk` и `openssl`; скриптът отказва да презапише съществуващ
`docker/.env`. Копирайте двата файла извън хоста: без `QUIRE_MASTER_KEY` възстановена база данни не може да декриптира съхранените идентификационни данни.
За ръчно попълване изпълнете `cp docker/.env.example docker/.env`; файлът обяснява как да създадете всяка тайна.

И двата източника трябва да използват `https`: услугата content отказва обикновен http в производствен режим и домейните им не трябва да споделят регистриран домейн. Услугата `proxy` завършва TLS и за двата (вижте „TLS“); `init-env.sh` отказва източник `http://`.

Стекът се стартира в постоянен ред, като всяка стъпка изчаква предишната:

1. `postgres` достига здравословно състояние. При първото стартиране скриптът за инициализация
   (`docker/postgres/init/90-passwords.sh`) задава четирите пароли за ролите.
2. `migrate` прилага всички миграции и инициализира опашката на задачите в
   управляващата база и във всяка отделна база на клиента, проверява, че всички са съгласувани, след което приключва (docs/ops/upgrade.md).
   Миграциите се изпълняват при всяко стартиране и са идемпотентни, затова надстройването е нов образ и рестартиране.
3. `init` (`apps/web/src/first-run.ts`) записва базата на приложението под
   `QUIRE_DATABASE_ID` и, когато е зададен `QUIRE_SETUP_ADMIN_EMAIL`, създава първата организация и администратора ѝ. Адресът за вход и генерираната парола се отпечатват веднъж в `docker compose logs init`.
4. Стартират `web`, `content`, `worker`, `scheduler`, `collab` и `centrifugo`.
5. `proxy` стартира, след като `web` и `content` са здрави.

Отворете `https://demo.` последвано от домейна на приложението (журналът `init` показва точния адрес за вход) и влезте. При локална инсталация първо се доверете на сертифициращия орган на proxy (вижте „TLS“). Сменете генерираната парола на `/account/security`.

Процес, стартиран без задължителна тайна, отказва да се изпълни и посочва липсващата настройка в журнала. Нищо не стартира в частично конфигурирано състояние.

## Услуги и профили <!--quire:services-and-profiles-->

| Услуга | Профил | Предназначение |
| --- | --- | --- |
| postgres | винаги | Базата данни (PostgreSQL 18 с pgvector, компилиран от `docker/postgres.Dockerfile`), с архивиране на WAL още от първото стартиране |
| migrate, init | винаги | Еднократни задачи: миграции, после първо стартиране |
| web | винаги | LMS, на `QUIRE_HTTP_PORT` (8080) |
| content | винаги | Източникът за ненадеждно съдържание, на `QUIRE_CONTENT_PORT` (8081) |
| worker | винаги | Фонови задачи: поща, отчети, обработка на файлове, уебкуки |
| scheduler | винаги | Периодични задачи: регистрира 64 изпълнявани графика и предава задачите на worker; едновременно има един лидер |
| collab | винаги | WebSocket за съвместно редактиране, на `QUIRE_COLLAB_HTTP_PORT` (1234) |
| centrifugo | винаги | Разпращане на събития в реално време, на `QUIRE_REALTIME_PORT` (8000) |
| proxy | винаги | Caddy, TLS предна врата на портове 80 и 443 (вижте „TLS“) |
| valkey | `cache` | Кеш и ограничаване на честотата |
| clamav | `scan` | Сканиране на качени файлове за зловреден софтуер |
| gotenberg | `preview` | Визуализации на Office в PDF, рендиране на сертификати |
| imgproxy | `images` | Преоразмеряване и конвертиране на изображения |
| transcoder | `video` | Образ на worker с LGPL-only ffmpeg за видео варианти |
| seaweedfs | `storage` | Съвместимо със S3 обектно хранилище на този хост |
| otelcol | `observability` | Колектор OpenTelemetry |
| mailpit | `devmail` | Улавя цялата изходяща поща за пробно използване на Quire |
| backup | `backup` | Еднократно базово копие; вижте backup-restore.md |
| backup-scheduler, backup-offsite | `backup` | Базово копие през `QUIRE_BACKUP_INTERVAL_HOURS` и криптирани копия извън хоста със седмична проверка за възстановяване |
| h5p | `h5p` | Образ на H5P LTI 1.3 инструмент, който предоставяте в `QUIRE_H5P_IMAGE`, на `QUIRE_H5P_PORT` (8090); вижте „Свързване на H5P доставчик“ |

`--profile full` стартира всички незадължителни услуги освен `backup` и `h5p`.
Стартирайте една услуга с `docker compose -f docker/compose.yaml --profile scan up -d`.
Quire работи и без незадължителна услуга и посочва какво липсва: без скенер качените файлове се съхраняват без сканиране и администраторът получава известие; без Gotenberg файловете се предлагат за изтегляне вместо за визуализация; без transcoder видеото се възпроизвежда като оригинален файл.

Всички външни образи и свързаните с тях лицензионни задължения са изброени в
`docker/third-party-containers.yaml`.

### Свързване на H5P доставчик <!--quire:connecting-an-h5p-provider-->

Quire не вгражда и не доставя среда за изпълнение или придружаваща услуга H5P (ADR 0019). Ако използвате H5P, осигурете собствен хостван абонамент или самостоятелно хоствана H5P инсталация отделно от Quire. Регистрирайте доставчика като външен LTI 1.3 инструмент и добавяйте съдържанието му към курсовете като дейности-инструменти. Quire обменя оценки и напредък по дейностите/оценяването чрез LTI Assignment and Grade Services (AGS).
Ако доставчикът изпраща и xAPI инструкции, настройте това отделно към хранилището за xAPI инструкции на Quire; обменът на оценки/напредък чрез AGS не изпраща xAPI инструкции. При импортиране от Moodle H5P дейностите се отбелязват като изискващи LTI инструмент. Доставчикът отговаря за собствената среда H5P, авторските инструменти, банката със съдържание и историята на опитите.

За самостоятелно хоствана инсталация на този хост задайте `QUIRE_H5P_IMAGE` на нейния образ и стартирайте профила `h5p`. Compose я публикува на `QUIRE_H5P_PORT` (8090) и пази данните ѝ в тома `h5p-data`; образът и свързаните с него задължения остават ваша отговорност.

## Настройки <!--quire:settings-->

Всеки процес чете `docker/.env`. Шаблонът `docker/.env.example` изброява
всяка настройка и стойността ѝ по подразбиране. Групите са:

### Адреси <!--quire:addresses-->

| Настройка | Значение |
| --- | --- |
| `QUIRE_APP_ORIGIN` | Публичният адрес на LMS, например `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | Източникът за съдържание на друг хост |
| `QUIRE_PLATFORM_DOMAINS` | Домейните на организациите, разделени със запетаи |
| `QUIRE_MARKETING_ORIGIN` | Optional. The marketing site, default `https://quirelms.com`. The only origin the waitlist form (`POST /api/waitlist`, `POST /waitlist`) accepts and redirects to. Comma separated; a `www.` variant is allowed only if listed |
| `QUIRE_DEPLOY_TARGET` | Тук `compose`. За `vercel` и `cloudflare` вижте другите ръководства |
| `QUIRE_TRUSTED_PROXY_CIDRS` | Проксита, чиито `X-Forwarded-For` стойности се приемат |

### Тайни <!--quire:secrets-->

| Настройка | Значение |
| --- | --- |
| `QUIRE_SECRET_KEY` | Подписва сесиите и токените. 64 шестнадесетични знака |
| `QUIRE_MASTER_KEY` | Обвива съхранени идентификационни данни, като SSO и уебкуки: 32 байта, base64. Уеб слоят и worker се нуждаят от същата стойност. Ротация: [key-rotation.md](/bg/ops/key-rotation/) |
| `QUIRE_MASTER_KEY_VERSION` | Етикет на версията на главния ключ, по подразбиране `v1`. Увеличете го при ротация |
| `QUIRE_MASTER_KEY_RETIRED` | Предишни главни ключове, още необходими за четене на запечатаните с тях стойности във формат `v1=<base64>`. Премахнете ги, след като ротацията приключи без нерешени стойности |
| `QUIRE_COLLAB_SIGNING_KEY` | Споделят се от web и collab за подписване на токени за редактиране |
| `QUIRE_BACKUP_SIGNING_KEY` | Подписва резервни копия на курсове (незадължително) |

Съхранявайте копие на `QUIRE_MASTER_KEY` другаде, а не на този хост. Възстановена база данни без него не може да декриптира идентификационните данни.

### База данни <!--quire:database-->

| Настройка | Значение |
| --- | --- |
| `POSTGRES_PASSWORD` | Суперпотребителят; използва се от контейнера и архивиращите задачи |
| `QUIRE_DB_APP_PASSWORD`, `QUIRE_DB_MIGRATOR_PASSWORD`, `QUIRE_DB_REPORT_PASSWORD`, `QUIRE_DB_AUDIT_PASSWORD` | Пароли за ролите, зададени при първото стартиране |
| `DATABASE_URL` | Роля на приложението; row-level security се прилага към всяка отправена заявка |
| `DATABASE_MIGRATOR_URL`, `QUIRE_MIGRATION_URL` | Роля за миграции при `migrate` и `init` |
| `QUIRE_SUPERUSER_URL` | Използва се само при първото стартиране |
| `QUIRE_REPORT_DATABASE_URL` | Роля само за четене при отчети и конструктор на отчети |
| `QUIRE_AUDIT_DATABASE_URL` | Роля за конзолата на одит и SIEM експорта |
| `QUIRE_DATABASE_ID` | Произволен UUID, фиксиран за целия живот на инсталацията |

Паролите за ролите се прилагат само при първото създаване на тома на базата. За да смените парола по-късно, използвайте `ALTER ROLE`, а след това обновете съответния URL.

`QUIRE_REPORT_DATABASE_URL` се използва за физическата база, настроена чрез
`DATABASE_URL`. За всяка друга регистрирана физическа база задайте собствен URL за връзка `quire_report` в средата на web и worker, после укажете името на променливата в полето **Reporting environment variable** на тази база във формат `env:NAME`. Препратката трябва да води към същата база като връзката приложения, в идеалния случай към реплика само за четене. Всяка повърхност за отчети следва клиента до връзката за отчети в неговата база: конструкторът и запазените отчети, планираните доставки, експортирането на отчети, аналитиката, журналът за одит, ресурсите на REST одит и търсенето на одит от асистента. Нито една от тях не използва URL за отчети от друга база. Когато липсва връзка за отчети, обикновените отчети се изпълняват чрез собствената връзка на приложението към тази база, а аналитиката и всички четения на одит отказват и го посочват, тъй като ролята на приложението не може да чете одитната следа.

### Драйвери <!--quire:drivers-->

| Настройка | Стойности в тази версия | Забележки |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (по подразбиране), `s3` или `azure` | `local` пази файловете в тома `files`. `s3` обхваща AWS S3, съвместимост с R2 и GCS, както и други S3 съвместими хранилища, с възможност за продължаване на съставното качване |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (по подразбиране), `sse`, `centrifugo` или `durable_objects` | `inprocess` е подходящ за един web контейнер; използвайте `centrifugo` или `sse` при повече от един |
| `QUIRE_CACHE_DRIVER` | `memory` (по подразбиране), `postgres` или `valkey` | `memory` важи за един процес; използвайте `valkey` или `postgres`, за да се споделят лимитите между контейнерите |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (по подразбиране) или `progressive_mp4` | Или хостван доставчик: Cloudflare Stream, Mux или Bunny чрез съответните ключове |
| `QUIRE_IMAGE_DRIVER` | `noop` (по подразбиране), `imgproxy` или `cloudflare` | `noop` обслужва изображенията в оригиналния размер. `imgproxy` изисква профил `images` и описаните по-долу настройки; `cloudflare` използва Cloudflare Images |
| `QUIRE_MEETING_PROVIDER` | `bbb`, `zoom`, `teams`, `meet`, `jitsi` или `in_process` | Стандартен доставчик на платформата за онлайн сесии. Ако не е зададен, онлайн сесиите съобщават, че не са настроени, докато организацията не свърже собствен акаунт в Integrations, Live session provider. Собственият акаунт на организацията винаги е с приоритет. Настройките на всеки доставчик (`BBB_URL` и `BBB_SECRET`, `ZOOM_*`, `TEAMS_*`, `GOOGLE_MEET_*` и `JITSI_*`) се четат само за избрания тук доставчик |
| `QUIRE_MEETING_REGIONS` | Списък от `eu`, `uk`, `us`, разделени със запетаи | Къде обработва срещите стандартният доставчик на платформата. Ако не е зададен, съвместимостта му с регион на фиксирана организация не се проверява, както и досега. Регионите на собствен акаунт се показват на страницата му |

Стойност на драйвер, която не е включена в тази версия, се отхвърля при стартиране на уеб слоя и се посочва настройката, вместо да бъде заменена тихомълком със стандартната.

### Изображения <!--quire:images-->

Страниците заявяват изображения в четири фиксирани размера чрез
`/api/files/{id}/image/{size}`; маршрутът проверява същия достъп като до самия файл и после пренасочва към услугата за изображения. Всяка организация може да заяви до `QUIRE_IMAGE_SPECS_PER_HOUR` (по подразбиране 2000) нови двойки изображение-размер на час; вече генерираните през този час размери не се броят. При повече от един уеб контейнер използвайте `valkey` или `postgres` за `QUIRE_CACHE_DRIVER`, за да се спазва лимитът между тях.

| Настройка | Драйвер | Забележки |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | Адрес, достъпен за браузърите, например `https://images.example.org`. Профилът `images` го публикува на `QUIRE_IMAGES_PORT` (8082) |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `imgproxy` | Шестнадесетични низове със същите стойности, с които стартира imgproxy. Генерирайте всеки чрез `openssl rand -hex 32`. Quire подписва всички адреси на изображения с тях, затова imgproxy рендира само заявеното от Quire |
| `QUIRE_IMAGE_SOURCE_ORIGIN` | `imgproxy` с локално хранилище | Адрес, откъдето imgproxy извлича оригиналите. Compose задава `http://web:3000`. При `s3` или `azure` imgproxy ги взема от кофата и тази настройка не се използва |
| `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_IMAGES_TOKEN`, `CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | API токен с право за редактиране на Images и account hash от Images, Developer resources. Включете гъвкавите варианти за акаунта |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | Незадължително. Когато е зададен, изображенията са частни, всеки адрес е подписан и изтича. Без него изображенията са публични на адреси, получени от `QUIRE_SECRET_KEY`, които никой не може да отгатне |

Cloudflare Images пази собствено копие на всеки обслужван оригинал. При изтриване на файл worker изтрива копието му преди оригинала.

### Опашка <!--quire:queue-->

Фоновите задачи използват pg-boss в същата база Postgres, затова не е нужно да стартирате или конфигурирате услуга за опашки. Задачите се добавят в същата транзакция като промяната, която ги е породила, така че при срив задача не може да се изгуби или изпрати два пъти. Тук `QUIRE_QUEUE_DRIVER` е `pgboss` — стойността по подразбиране; `vercel` и `cloudflare` прехвърлят само леките доставки на известия и уебкуки към собствената опашка на платформата, описана в ръководствата за Vercel и Cloudflare, заедно с начина, по който уеб слоевете ги поставят в опашката.

### Имейл <!--quire:email-->

Задайте едно от следните:

- `QUIRE_EMAIL_PROVIDER_CONFIG`: JSON обект с име на HTTP доставчик и идентификационни данни, например `{"provider":"postmark","token":"..."}`. Поддържат се Postmark, Amazon SES, Mailgun, SendGrid и Resend.
- `QUIRE_SMTP_URL`: `smtp://user:password@host:587`. Само тази цел поддържа SMTP; безсървърните цели го блокират.

`QUIRE_MAIL_FROM` е адресът на подателя. За пробно използване на Quire стартирайте профила `devmail`, задайте `QUIRE_SMTP_URL=smtp://mailpit:1025` и прочетете пощата на `http://localhost:8025`.

### Незадължителни услуги <!--quire:optional-services-->

| Настройка | С профил |
| --- | --- |
| `CLAMAV_URL=tcp://clamav:3310` | `scan` |
| `GOTENBERG_URL=http://gotenberg:3000` | `preview` |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `images` |
| `VALKEY_URL=redis://valkey:6379` | `cache` |
| `QUIRE_OPENSEARCH_URL` или `QUIRE_MEILISEARCH_URL` | Външно търсене; в противен случай пълнотекстово търсене в Postgres |
| `QUIRE_BREACH_CHECK_PROVIDER=off`, `QUIRE_BREACH_CHECK_URL` | Проверка за компрометирана парола. По подразбиране включена чрез `api.pwnedpasswords.com` (изпраща се само първият сегмент от пет знака на хеша); `off` я изключва, а URL сочи към хостван от вас API диапазон |

### Наблюдаемост <!--quire:observability-->

`OTEL_EXPORTER_OTLP_ENDPOINT` задава колектора, към който всеки процес изпраща
следи и метрики; при профил `observability` това е
`http://otelcol:4318`, а `docker/otel-collector.yaml` е файлът, в който добавяте
експорт към своята система. Когато е зададена настройката, уеб слоят, worker, scheduler, content и collab
изнасят span-ове през OTLP/HTTP (заявки, транзакции към бази на клиенти,
задачи и изходящи повиквания) и на всяка минута изпращат метрики към същата крайна точка (`OTEL_METRICS_EXPORTER=none` ги изключва). `OTEL_TRACES_SAMPLER_ARG` задава дела запазени следи. Журналите се изпращат към стандартния изход на ниво `LOG_LEVEL`, а Compose ги ротира. Следите никога не съдържат лични данни.

### Регионален изходящ трафик (местонахождение на данните в ЕС) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` задава, че стекът обслужва организации от Европейския съюз.
Worker ограничава всеки изходяща заявка, изпратена от организация, фиксирана към ЕС, чрез списък с разрешения (раздел 8.1 на 21-compliance.md). Списъкът съдържа хостове, обявени от настроените услуги за региона (крайната точка на хранилището, доставчикът на поща, хостван доставчик на видео, собствените цели за съхранение на организацията, доставчиците на AI и пощенския акаунт), хостове на услуги с активно изключение и хостове в `QUIRE_EGRESS_ALLOW_HOSTS`. Заявка към друг публичен хост се отказва преди изпращане, отказът се записва в одитната следа на организацията като `privacy/egress_refused` и се показва в Compliance, Data residency.

| Настройка | Стойности | Ефект |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | Списък с имена на хостове, разделени със запетаи, или `*.example.org` за всеки поддомейн | Допълнителни хостове, до които може да достигне организация от ЕС. Тук трябва да се добавят крайните точки за webhook, xAPI и SIEM, потоците от блогове и хостовете на Amazon SES, защото са избор на самата организация и никоя услуга не ги декларира. Loopback, частните адреси и едноетажните имена като `web` или `clamav` са част от вашата собствена мрежа и никога не се проверяват |

Организациите от Обединеното кралство и САЩ не ограничават хостовете в списък, но продължават регионалните проверки на услугите. Задайте списъка в worker; административната страница чете настройката от уеб слоя за показване, затова поставете стойността в `docker/.env`, който четат всички услуги.

Проверката на приложението показва ясна грешка и одитен запис, но не е гаранцията: кодът може да е сгрешен. Гаранцията е мрежата, а Compose не я налага вместо вас. За регионален стек поставете услугите `worker` и `web` в мрежа `internal: true`, чийто единствен външен маршрут е прокси за изходящ трафик (например контейнер Squid или tinyproxy), разрешаващо същите хостове като `QUIRE_EGRESS_ALLOW_HOSTS` и хостовете на настроените услуги; задайте `HTTPS_PROXY` за тези услуги. Страницата за местонахождение на данните показва точните хостове, които приложението разрешава, за да могат двата списъка да се сравнят.

## Състояние <!--quire:health-->

| Крайна точка | Значение |
| --- | --- |
| `/healthz` | Активност: процесът отговаря. Compose използва това за проверка на здравето |
| `/readyz` | Готовност: зависимостите са достъпни, а всяка незадължителна услуга е отчетена като настроена или не. Насочете тук балансьора на натоварването |

`docker compose -f docker/compose.yaml ps` показва състоянието на всяка услуга.

## TLS <!--quire:tls-->

Услугата `proxy` (Caddy, Apache-2.0, `docker/caddy/Caddyfile`) е част от
стека по подразбиране. Тя отговаря на портове 80 и 443 и маршрутизира:

| Хост или път | Насочва към |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`, всеки поддомейн на клиент и персонализиран домейн | `web` |
| `/_collab/` на тези хостове | `collab` (websocket, `QUIRE_COLLAB_URL`) |
| `/_realtime/connection/` на тези хостове | WebSocket клиент на `centrifugo`; неговият сървърен API никога не се публикува |
| `/_images/` на тези хостове | `imgproxy` с профил `images` (`IMGPROXY_URL`) |

`init-env.sh` извежда `QUIRE_PROXY_APP_HOST`, `QUIRE_PROXY_CONTENT_HOST`,
`QUIRE_PROXY_HTTPS_PORT`, `QUIRE_COLLAB_URL` и `IMGPROXY_URL` от двата източника, така че настройките не могат да се разминават. Променяйте ги заедно при ръчна смяна на източник.

Сертификатите зависят от `QUIRE_PROXY_TLS`:

- `internal` (по подразбиране): собствен сертифициращ орган на Caddy за
  `localhost`, `*.localhost` и `lvh.me`. Доверете се на главния сертификат веднъж, после изтеглете го:

  ```sh
  docker compose -f docker/compose.yaml cp \
    proxy:/data/caddy/pki/authorities/local/root.crt ./quire-local-ca.crt
  ```

  Добавете `quire-local-ca.crt` към системното или браузърното хранилище на сертификати. За `curl` посочете го чрез `--cacert`.
- Имейл адрес: автоматични ACME сертификати (Let's Encrypt, после ZeroSSL) за реални имена на хостове. DNS и за двата източника, както и за всеки хост на клиент, трябва да сочи насам; портовете 80 и 443 трябва да са достъпни от интернет.

Сертификати за хостове на клиенти се издават при поискване, при първото посещение и само след потвърждение от web, че името принадлежи на тази инсталация (`/tls-allowed`, през мрежата на Compose). Не са нужни wildcard сертификат или приставка за DNS доставчик, а непознат, който насочи име към хоста, не може да предизвика заявка за сертификат. Сертификатите и локалният сертифициращ орган се пазят в тома `caddy-data`; архивирайте го заедно с останалото, ако използвате `internal`.

Web приема `X-Forwarded-For` само от proxy: proxy има фиксиран адрес
(`QUIRE_PROXY_ADDRESS`, по подразбиране `172.29.64.10`) в фиксирана подмрежа
(`QUIRE_COMPOSE_SUBNET`), а `QUIRE_TRUSTED_PROXY_CIDRS` посочва този адрес.
Ако подмрежата съвпада с мрежа на хоста, сменете двете настройки и изпълнете
`docker compose down` преди `up`.

## Зад собствен обратен прокси <!--quire:behind-your-own-reverse-proxy-->

За използване на вече управляван от вас балансьор или прокси изключете `proxy`
(`docker compose up -d --scale proxy=0`) и завършете TLS отпред за `web`
(8080), `content` (8081), `collab` (1234, websocket) и `centrifugo` (8000,
websocket). Задайте публичните адреси в `QUIRE_APP_ORIGIN`,
`QUIRE_CONTENT_ORIGIN` и `QUIRE_COLLAB_URL` (`wss://`), както и адресния диапазон на проксито в `QUIRE_TRUSTED_PROXY_CIDRS`.

## Отстраняване на проблеми <!--quire:troubleshooting-->

- `init` приключва с „QUIRE_DATABASE_ID is not a UUID“: задайте го чрез `uuidgen`.
- `web` се рестартира с „did not start on compose“: журналът изброява всяка настройка, която не може да се поддържа, и посочва какво да използвате вместо нея.
- Смяната на парола за роля в `.env` след първото стартиране няма ефект: скриптът за инициализация се изпълнява еднократно. Използвайте `ALTER ROLE`.
- Качването не минава сканирането, когато е зададен `CLAMAV_URL`: ClamAV изтегля сигнатурите си при първото стартиране; това отнема няколко минути.

Source: https://docs.quirelms.com/bg/ops/install/index.mdx
