---
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/mk/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-от, неговата позадинска работа, сервисите за реално време и за соработувачко уредување и секоја изборна услуга зад профил. Дизајнот е `docs/architecture/23-ops.md` оддел 2.

Други цели: [Vercel](/mk/ops/vercel/) и [Cloudflare Workers](/mk/ops/cloudflare/) извршуваат само веб-слој. Надградбите се во [upgrade.md](/mk/ops/upgrade/), а резервните копии и вежбата за враќање во [backup-restore.md](/mk/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 го монтира во работниците како тајна. Бара само `sh`, `awk` и `openssl` и одбива да презапише постоечка `docker/.env`. Копирајте ги двете датотеки надвор од домаќинот: без `QUIRE_MASTER_KEY` вратената база не може да ги дешифрира нејзините зачувани потврди. За да ја пополните датотеката рачно наместо тоа, `cp docker/.env.example docker/.env`; датотката наведува како се генерира секоја тајна.

Двата извори мора да бидат `https`: сервисот за содржина одбива обичен 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` ја отпечатува точната адреса за најавување) и најавете се. На локална инсталација, прво поверете го сертификатниот орган на прокси (видете „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-те распореди за извршување и им ги предава на работникот; еден водач истовремено |
| 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` | Сликата на работникот со ffmpeg што е само LGPL, за видео-претворања |
| 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 значи дека датотеките нудат преземање наместо преглед; без транскодер значи дека видеото се репродуцира како оригиналната датотека.

Секоја слика од трето лице и нејзините лиценциски обврски се наведени во `docker/third-party-containers.yaml`.

### Поврзување H5P-давател <!--quire:connecting-an-h5p-provider-->

Quire не вградува ниту испорачува H5P-извршување или sidecar (ADR 0019). Ако користите H5P, обезбедете сопствена хостирана претплата или водете сопствена самодржена H5P-инстанца одделно од Quire. Регистрирајте го тој давател како надворешна LTI 1.3-алатка и додајте ја неговата содржина во курсевите како активности на алатката. Quire разменува оценки и напредок во активноста/оценувањето преку LTI Assignment and Grade Services (AGS). Ако давателот исто така испраќа 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. Веб-слојот и работникот бараат иста вредност. Ротација: [key-rotation.md](/mk/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` | Улогата на апликацијата. Безбедноста на ниво на ред се применува на секој нејзин прашање |
| `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`. За било која друга регистрирана физичка база, поставете нејзино сопствено `quire_report`-врска за податоци во веб- и работничката средина, па ставете го името на променливата во полето **Reporting environment variable** на таа база како `env:NAME`. Референцата мора да укажува на истата база како нејзината app-врска, по можност нејзината реплика за читање. Секоја површина за извештаи го следи закупецот до врската за извештаи на неговата сопствена база: градачот на извештаи и зачуваните извештаи, закажаните испораки, извозите на извештаи, аналитиката, дневникот за ревизија, ресурсите за ревизија на REST и пребарувањето за ревизија на асистентот. Ниту еден од нив не позајмува URL за извештаи од друга база. Кога базата нема врска за извештаи, обичните извештаи работат на сопствената апликациска врска на таа база, додека аналитиката и секое читање за ревизија одбиваат и го наведуваат тоа, бидејќи улогата на апликацијата не може да чита траг на ревизија.

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

| Поставка | Ова издание | Забелешки |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (по стандард), `s3` или `azure` | `local` ги чува датотеките во волумот `files`. `s3` го покрива AWS S3, R2, GCS interoperability и други складишта компатибилни со S3, со подновливи multipart-прикачувања |
| `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` | Стандардот на платформата за живи сесии. Кога не е поставено, живите сесии велат дека не се конфигурирани, сè додека организацијата не ја поврзе сопствената сметка под Интеграции, Давател за живи сесии. Сопствената сметка на организацијата секогаш победува над оваа вредност. Сопствените поставки на секој давател (`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` со повеќе од еден web-контејнер, за лимитот да важи низ нив.

| Поставка | Драјвер | Забелешки |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | Адресата до која прелистувачите стигнуваат до 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 зема од bucket-от и ова не се користи |
| `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_IMAGES_TOKEN`, `CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | API-токен со дозвола за уредување на Images и хешот на сметката од Images, ресурси за програмери. Вклучете флексибилни варијанти за сметката |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | Изборно. Кога е поставено, сликите се приватни и секоја адреса е потпишана и истекува. Без него, сликите се јавни на адреси изведени од `QUIRE_SECRET_KEY` што никој не може да ги погоди |

Cloudflare Images чува своја копија на секој оригинал што го служи. Кога датотека се брише, работникот ја брише таа копија пред оригиналот.

### Редица <!--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` е местото каде го додавате извозникот за вашиот заден систем. Веб-слојот, работникот, распоредувачот, содржината и collab-процесите извезуваат span-ови преку OTLP/HTTP (web-побарувања, трансакции на база на закупец, работи на работникот и излезни повици) кога е поставено, и мерки на истата адреса на секоја минута (`OTEL_METRICS_EXPORTER=none` ги исклучува). `OTEL_TRACES_SAMPLER_ARG` ја поставува застапеноста на задржаните траги. Дневниците одат на стандарден излез на `LOG_LEVEL`, а Compose ги ротира. Трагите никогаш не носат лични податоци.

### Регионален излез (престој на податоци во ЕУ) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` кажува дека стекот опслужува организации од Европската Унија. Работникот потоа ги задржува сите излезни побарувања направени за организација врзана за ЕУ на бела листа (21-compliance.md оддел 8.1). Белата листа се домаќините што конфигурираните услуги ги декларираат за регионот (адресата на складирање, давателот за е-пошта, хостиран давател за видео, сопствените цели за складирање на организацијата, давателите за вештачка интелигенција и сметката за е-пошта), домаќините на било која услуга под активно одобрување и домаќините што ги наведувате во `QUIRE_EGRESS_ALLOW_HOSTS`. Барање до било кој друг јавен домаќин е одбиено пред да се испрати, одбивањето се запишува во трагот на ревизија на организацијата како `privacy/egress_refused` и се наведува под Усогласеност, Престој на податоци.

| Поставка | Вредности | Ефект |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | Список со запирки од имиња на домаќини или `*.example.org` за секој поддомен | Дополнителни домаќини што ЕУ-организација може да ги достигне. Крајни точки за веб-куки, xAPI и SIEM, текови на блог и домаќини на Amazon SES припаѓаат овде, бидејќи тие се сопствен избор на организацијата и ниту една услуга ги не декларира. Повратни, приватни адреси и имиња со еден ознака како `web` или `clamav` се ваша сопствена мрежа и никогаш не се проверуваат |

Организациите од Велика Британија и САД не се држат до список со домаќини; тие ги задржуваат проверките за регион на услугата. Поставете го списокот на работникот; административната страница го чита на веб-слојот за да ја прикаже белата листа, затоа ставете го во `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` само од обратниот прокси: тој има фиксна адреса (`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/mk/ops/install/index.mdx
