Към съдържанието

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

Инсталирайте Quire на собствена инфраструктура чрез Docker Compose.

Преглед като Markdown

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

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

Необходими ресурси

  • 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_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.

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

Услуги и профили

Услуга Профил Предназначение
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 не вгражда и не доставя среда за изпълнение или придружаваща услуга 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; образът и свързаните с него задължения остават ваша отговорност.

Настройки

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

Адреси

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

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

База данни

Настройка Значение
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_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, разделени със запетаи Къде обработва срещите стандартният доставчик на платформата. Ако не е зададен, съвместимостта му с регион на фиксирана организация не се проверява, както и досега. Регионите на собствен акаунт се показват на страницата му

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

Изображения

Страниците заявяват изображения в четири фиксирани размера чрез /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 изтрива копието му преди оригинала.

Опашка

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

Имейл

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

  • 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.

Незадължителни услуги

Настройка С профил
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 диапазон

Наблюдаемост

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_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 за тези услуги. Страницата за местонахождение на данните показва точните хостове, които приложението разрешава, за да могат двата списъка да се сравнят.

Състояние

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

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

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. Доверете се на главния сертификат веднъж, после изтеглете го:

    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.

Зад собствен обратен прокси

За използване на вече управляван от вас балансьор или прокси изключете 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.

Отстраняване на проблеми

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

Въведете текст за търсене…

↑↓ навигация↵ избериEsc затвори