---
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/fa/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، کارهای پس‌زمینه‌اش، سرویس‌های بلادرنگ و ویرایش گروهی و همهٔ سرویس‌های اختیاری پشت یک profile. طرح در بخش ۲ از `docs/architecture/23-ops.md` آمده است.

مقصدهای دیگر: [Vercel](/fa/ops/vercel/) و [Cloudflare Workers](/fa/ops/cloudflare/) فقط web tier را اجرا می‌کنند. ارتقاها در [upgrade.md](/fa/ops/upgrade/) و پشتیبان‌گیری و تمرین بازیابی در [backup-restore.md](/fa/ops/backup-restore/) آمده‌اند.

## چیزهای لازم <!--quire:what-you-need-->

- Docker Engine نسخهٔ ۲۷ یا بالاتر و افزونهٔ Compose نسخهٔ ۲٫۳۰ یا بالاتر.
- برای stack پیش‌فرض ۴ هستهٔ CPU و ۸ GB حافظه؛ با `--profile full` هشت هسته و ۱۶ GB (ClamAV به‌تنهایی حدود ۱٫۵ GB امضای ویروس نگه می‌دارد).
- یک نام DNS برای web tier و نامی دیگر برای محتوای غیرقابل‌اعتماد. باید میزبان‌های متفاوتی باشند: بسته‌های SCORM و HTML بارگذاری‌شده روی origin محتوا اجرا می‌شوند تا هرگز نتوانند کوکی‌های LMS را بخوانند.
- برای آزمون محلی، `lvh.me` و `*.localhost` به 127.0.0.1 اشاره می‌کنند و `docker/.env.example` هم همین را به کار می‌برد. سرویس `proxy` خود stack هر دو را با https و مرجع گواهی محلی ارائه می‌کند؛ پس چیز دیگری نصب نمی‌شود (بخش «TLS» را ببینید).
- پورت‌های ۸۰ و ۴۴۳ روی میزبان آزاد باشند (`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` می‌سازد (گذرواژه‌های پایگاه داده، کلیدهای امضا و اصلی و جفت‌کلید راه‌اندازی محتوا) و کلید امضای checkpoint حسابرسی را در `docker/secrets/audit-signing-key.pem` می‌گذارد که Compose آن را به‌صورت secret در workerها mount می‌کند. فقط `sh`، `awk` و `openssl` لازم دارد و نمی‌گذارد `docker/.env` موجود بازنویسی شود. هر دو فایل را از میزبان بیرون کپی کنید: بدون `QUIRE_MASTER_KEY` پایگاه بازیابی‌شده نمی‌تواند اعتبارنامه‌های ذخیره‌شده را رمزگشایی کند. برای پر کردن دستی فایل، `cp docker/.env.example docker/.env` را اجرا کنید؛ فایل شیوهٔ ساخت هر راز را می‌گوید.

هر دو origin باید `https` باشند: سرویس content در محیط عملیاتی http ساده را رد می‌کند و دو origin نباید دامنهٔ ثبت‌پذیر مشترک داشته باشند. سرویس `proxy` برای هر دو TLS را پایان می‌دهد (بخش «TLS» را ببینید)؛ `init-env.sh` originای با `http://` را رد می‌کند.

Stack با ترتیب ثابتی آغاز می‌شود و هر گام برای پایان قبلی منتظر می‌ماند:

1. `postgres` سالم می‌شود. در نخستین راه‌اندازی، اسکریپت آغازش (`docker/postgres/init/90-passwords.sh`) گذرواژهٔ چهار نقش را تنظیم می‌کند.
2. `migrate` همهٔ migrationها را اجرا و صف job را در پایگاه کنترل و هر پایگاه tenant اختصاصی آماده می‌کند؛ بررسی می‌کند همگی یکسان باشند و سپس خارج می‌شود (docs/ops/upgrade.md). Migration در هر آغاز اجرا می‌شوند و تکرارپذیرند، پس ارتقا یعنی image تازه و راه‌اندازی مجدد.
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` عوض کنید.

فرایندی که بدون راز لازم آغاز شود، از کار سر باز می‌زند و تنظیم گمشده را در گزارش نام می‌برد. هیچ‌چیز نیمه‌پیکربندی‌شده آغاز نمی‌شود.

## سرویس‌ها و profileها <!--quire:services-and-profiles-->

| سرویس | Profile | کارکرد |
| --- | --- | --- |
| postgres | همیشه | پایگاه داده (PostgreSQL 18 با pgvector، ساخته‌شده از `docker/postgres.Dockerfile`) و بایگانی WAL از آغاز کار |
| migrate, init | همیشه | یک‌باره: migrationها و سپس اجرای نخست |
| web | همیشه | LMS روی `QUIRE_HTTP_PORT` (8080) |
| content | همیشه | origin محتوای غیرقابل‌اعتماد روی `QUIRE_CONTENT_PORT` (8081) |
| worker | همیشه | کارهای پس‌زمینه: ایمیل، گزارش، پردازش فایل و وب‌هوک |
| scheduler | همیشه | کارهای دوره‌ای: ۶۴ زمان‌بندی زمان‌اجرا را ثبت و به worker می‌دهد؛ هم‌زمان فقط یک رهبر |
| collab | همیشه | websocket ویرایش گروهی روی `QUIRE_COLLAB_HTTP_PORT` (1234) |
| centrifugo | همیشه | پخش بلادرنگ روی `QUIRE_REALTIME_PORT` (8000) |
| proxy | همیشه | Caddy، درگاه TLS در پورت‌های ۸۰ و ۴۴۳ (بخش «TLS» را ببینید) |
| valkey | `cache` | cache و محدودیت نرخ |
| clamav | `scan` | بررسی بدافزار در بارگذاری‌ها |
| gotenberg | `preview` | پیش‌نمایش Office به PDF و رندر گواهی |
| imgproxy | `images` | تغییر اندازه و تبدیل تصویر |
| transcoder | `video` | image مربوط به worker با ffmpeg تنها با مجوز LGPL برای rendition ویدیو |
| 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` | image ابزار H5P LTI 1.3 که در `QUIRE_H5P_IMAGE` می‌دهید، روی `QUIRE_H5P_PORT` (8090)؛ بخش «Connecting an H5P provider» را ببینید |

`--profile full` همهٔ سرویس‌های اختیاری جز `backup` و `h5p` را آغاز می‌کند. برای نمونه `docker compose -f docker/compose.yaml --profile scan up -d` را اجرا کنید. Quire بدون سرویس اختیاری هم کار می‌کند و کمبود را می‌گوید: اگر scanner نباشد، بارگذاری‌ها بدون scan ذخیره می‌شوند و مدیر باخبر می‌شود؛ اگر Gotenberg نباشد، فایل‌ها به‌جای پیش‌نمایش امکان بارگیری می‌دهند؛ اگر transcoder نباشد، ویدیو به‌صورت فایل اصلی پخش می‌شود.

همهٔ imageهای شخص ثالث و تعهدهای مجوزشان در `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 statement هم می‌فرستد، آن را جداگانه برای مخزن xAPI statement در Quire پیکربندی کنید؛ مبادلهٔ نمره و پیشرفت AGS، xAPI statement نمی‌فرستد. ورودهای Moodle گزارش می‌دهند که فعالیت H5P به اتصال ابزار LTI نیاز دارد. زمان‌اجرا، ساخت محتوا، بانک محتوا و تاریخچهٔ تلاش‌های H5P در مسئولیت ارائه‌دهنده می‌مانند.

برای اجرای نمونهٔ خودمیزبانی در این میزبان، `QUIRE_H5P_IMAGE` را روی image آن بگذارید و profile `h5p` را آغاز کنید. Compose آن را روی `QUIRE_H5P_PORT` (8090) منتشر می‌کند و داده‌هایش را در volume `h5p-data` نگه می‌دارد؛ image و تعهدهای همراهش از آنِ شما می‌مانند.

## تنظیم‌ها <!--quire:settings-->

هر فرایند `docker/.env` را می‌خواند. الگوی `docker/.env.example` همهٔ تنظیم‌ها و مقدارهای پیش‌فرضشان را فهرست می‌کند. گروه‌ها:

### نشانی‌ها <!--quire:addresses-->

| تنظیم | معنا |
| --- | --- |
| `QUIRE_APP_ORIGIN` | نشانی عمومی LMS، مانند `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | 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` | proxyهایی که `X-Forwarded-For` ارسالی‌شان پذیرفته می‌شود |

### رازها <!--quire:secrets-->

| تنظیم | معنا |
| --- | --- |
| `QUIRE_SECRET_KEY` | نشست‌ها و tokenها را امضا می‌کند؛ ۶۴ نویسهٔ hex |
| `QUIRE_MASTER_KEY` | اعتبارنامه‌های ذخیره‌شده مانند راز SSO و وب‌هوک را می‌پوشاند؛ ۳۲ بایت base64. web tier و worker باید مقدار یکسان داشته باشند. چرخش: [key-rotation.md](/fa/ops/key-rotation/) |
| `QUIRE_MASTER_KEY_VERSION` | برچسب نسخهٔ کلید اصلی، اگر تنظیم نشود `v1`؛ هنگام چرخش آن را بالا ببرید |
| `QUIRE_MASTER_KEY_RETIRED` | کلیدهای اصلی قدیمی که هنوز برای خواندن رازهای پوشانده‌شده لازم‌اند، به‌شکل `v1=<base64>`. پس از پایان چرخش و حل شدن همه‌چیز، حذف کنید |
| `QUIRE_COLLAB_SIGNING_KEY` | web و collab برای امضای token ویرایش به‌طور مشترک از آن استفاده می‌کنند |
| `QUIRE_BACKUP_SIGNING_KEY` | پشتیبان دوره را امضا می‌کند (اختیاری) |

از `QUIRE_MASTER_KEY` نسخه‌ای جایی بیرون از این میزبان نگه دارید. اگر پایگاه داده بدون آن بازیابی شود، اعتبارنامه‌های داخلش رمزگشایی نمی‌شوند.

### پایگاه داده <!--quire:database-->

| تنظیم | معنا |
| --- | --- |
| `POSTGRES_PASSWORD` | superuser که container و پشتیبان‌ها استفاده می‌کنند |
| `QUIRE_DB_APP_PASSWORD`، `QUIRE_DB_MIGRATOR_PASSWORD`، `QUIRE_DB_REPORT_PASSWORD`، `QUIRE_DB_AUDIT_PASSWORD` | گذرواژه‌های نقش‌ها که در راه‌اندازی نخست تنظیم می‌شوند |
| `DATABASE_URL` | نقش برنامه؛ امنیت سطح سطر بر هر query آن اعمال می‌شود |
| `DATABASE_MIGRATOR_URL`، `QUIRE_MIGRATION_URL` | نقش migrator برای `migrate` و `init` |
| `QUIRE_SUPERUSER_URL` | فقط اجرای نخست به کار می‌برد |
| `QUIRE_REPORT_DATABASE_URL` | نقش گزارش فقط‌خواندنی برای گزارش‌ها و سازندهٔ گزارش |
| `QUIRE_AUDIT_DATABASE_URL` | نقش حسابرسی برای کنسول حسابرسی و SIEM export |
| `QUIRE_DATABASE_ID` | هر UUIDای؛ در تمام عمر نصب ثابت |

گذرواژهٔ نقش‌ها فقط هنگام نخستین ساخت volume پایگاه داده اعمال می‌شوند. برای تغییر بعدی، `ALTER ROLE` را اجرا و URL متناظر را به‌روز کنید.

`QUIRE_REPORT_DATABASE_URL` برای پایگاه فیزیکی‌ای است که با `DATABASE_URL` تنظیم شده است. برای هر پایگاه فیزیکی ثبت‌شدهٔ دیگر، URL اتصال `quire_report` خودش را در محیط‌های web و worker تنظیم کنید و سپس نام متغیر را در فیلد **Reporting environment variable** آن پایگاه به‌شکل `env:NAME` بگذارید. ارجاع باید به همان پایگاهی برود که اتصال برنامه می‌رود، بهتر آنکه read replicaاش باشد. هر سطح گزارش با tenant به اتصال گزارش همان پایگاه می‌رود: سازنده و گزارش‌های ذخیره‌شده، تحویل‌های زمان‌بندی‌شده، خروجی گزارش، analytics، گزارش حسابرسی، منبع‌های حسابرسی REST و جست‌وجوی حسابرسی دستیار. هیچ‌کدام از URL گزارش پایگاه دیگری قرض نمی‌گیرند. اگر پایگاهی اتصال گزارش نداشته باشد، گزارش‌های عادی از اتصال برنامهٔ همان پایگاه اجرا می‌شوند؛ اما analytics و هر خواندن حسابرسی رد می‌شوند و علت را می‌گویند، چون نقش برنامه نمی‌تواند گزارش حسابرسی را بخواند.

### Driverها <!--quire:drivers-->

| تنظیم | در این نسخه | توضیح |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (پیش‌فرض)، `s3` یا `azure` | `local` فایل‌ها را در volume `files` نگه می‌دارد. `s3` با AWS S3، R2، سازگاری با GCS و دیگر مخزن‌های سازگار با S3 کار می‌کند و بارگذاری چندبخشیِ قابل ادامه دارد |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (پیش‌فرض)، `sse`، `centrifugo` یا `durable_objects` | `inprocess` برای یک web container مناسب است؛ اگر چندتا دارید `centrifugo` یا `sse` به کار ببرید |
| `QUIRE_CACHE_DRIVER` | `memory` (پیش‌فرض)، `postgres` یا `valkey` | `memory` برای هر فرایند جداست؛ برای اینکه محدودیت نرخ در همهٔ containerها برقرار بماند `valkey` یا `postgres` به کار ببرید |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (پیش‌فرض) یا `progressive_mp4` | یا ارائه‌دهندهٔ میزبانی‌شدهٔ Cloudflare Stream، Mux یا Bunny را با کلیدهایش به کار ببرید |
| `QUIRE_IMAGE_DRIVER` | `noop` (پیش‌فرض)، `imgproxy` یا `cloudflare` | `noop` همهٔ تصویرها را در اندازهٔ اصلی ارائه می‌کند. `imgproxy` به profile `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` | منطقه‌ای که ارائه‌دهندهٔ پیش‌فرض پلتفرم نشست‌ها را در آن پردازش می‌کند. اگر تنظیم نشود، مانند گذشته با سازمان سنجاق‌شده به منطقه سنجیده نمی‌شود. حساب خود سازمان منطقه‌هایش را در صفحه‌اش مشخص می‌کند |

مقدار driverای که این نسخه ندارد هنگام آغاز web tier رد می‌شود و تنظیم را نام می‌برد؛ بی‌صدا با مقدار پیش‌فرض جایگزین نمی‌شود.

### تصویرها <!--quire:images-->

صفحه‌ها از راه `/api/files/{id}/image/{size}` در چهار اندازهٔ ثابت تصویر می‌خواهند؛ این endpoint دسترسی همان فایل را بررسی می‌کند و سپس به سرویس تصویر تغییرمسیر می‌دهد. هر سازمان می‌تواند در هر ساعت برای `QUIRE_IMAGE_SPECS_PER_HOUR` (پیش‌فرض ۲۰۰۰) جفت تازهٔ تصویر و اندازه درخواست کند؛ اندازه‌هایی که همان ساعت ساخته شده‌اند در شمار نمی‌آیند. اگر بیش از یک web container دارید، برای یکسان نگه داشتن سقف `valkey` یا `postgres` را برای `QUIRE_CACHE_DRIVER` برگزینید.

| تنظیم | Driver | توضیح |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | نشانی‌ای که مرورگرها از آن به imgproxy می‌رسند، مانند `https://images.example.org`. profile `images` آن را روی `QUIRE_IMAGES_PORT` (8082) منتشر می‌کند |
| `IMGPROXY_KEY`، `IMGPROXY_SALT` | `imgproxy` | رشته‌های hex و همان مقدارهایی که 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` | token API با اجازهٔ ویرایش Images و hash حساب از Images، Developer resources. variantهای انعطاف‌پذیر حساب را فعال کنید |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | اختیاری. با تنظیمش تصویرها خصوصی می‌شوند و همهٔ نشانی‌ها امضا و منقضی می‌شوند. بدون آن تصویرها عمومی‌اند و نشانی‌هایشان از `QUIRE_SECRET_KEY` به‌دست می‌آیند؛ کسی نمی‌تواند حدسشان بزند |

Cloudflare Images نسخه‌ای از هر تصویر اصلی را که ارائه می‌کند نگه می‌دارد. هنگام حذف فایل، worker آن نسخه را پیش از تصویر اصلی پاک می‌کند.

### صف <!--quire:queue-->

کارهای پس‌زمینه از pg-boss در همان پایگاه Postgres استفاده می‌کنند، پس نه سرویس صفی لازم است اجرا کنید و نه چیزی پیکربندی کنید. jobها در همان transaction تغییرِ سبب‌ساز صف می‌شوند تا crash نتواند آن‌ها را گم کند یا دوبار بفرستد. اینجا `QUIRE_QUEUE_DRIVER` مقدار پیش‌فرض `pgboss` دارد؛ `vercel` و `cloudflare` فقط تحویل سبک اعلان و وب‌هوک را به صف خود پلتفرم می‌برند. راهنماهای Vercel و Cloudflare آن‌ها و شیوهٔ صف‌بندی web tier را توضیح می‌دهند.

### ایمیل <!--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`. فقط این مقصد؛ مقصدهای serverless، SMTP را مسدود می‌کنند.

`QUIRE_MAIL_FROM` نشانی فرستنده است. برای آزمودن Quire، profile `devmail` را آغاز، `QUIRE_SMTP_URL=smtp://mailpit:1025` را تنظیم و ایمیل را در `http://localhost:8025` بخوانید.

### سرویس‌های اختیاری <!--quire:optional-services-->

| تنظیم | با profile |
| --- | --- |
| `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` روشن است و تنها پیشوند پنج‌نویسه‌ای hash فرستاده می‌شود؛ `off` خاموشش می‌کند و URL به API بازه‌ای اشاره می‌کند که خودتان میزبانی می‌کنید |

### مشاهده‌پذیری <!--quire:observability-->

`OTEL_EXPORTER_OTLP_ENDPOINT` نام گردآورنده‌ای را مشخص می‌کند که هر فرایند trace و metric به آن می‌فرستد؛ با profile `observability` مقدارش `http://otelcol:4318` است و `docker/otel-collector.yaml` جایی است که exporter مربوط به backend خودتان را می‌افزایید. web tier، worker، scheduler، content و collab اگر این مقدار تنظیم شود spanها را از راه OTLP/HTTP می‌فرستند (درخواست‌های وب، transactionهای پایگاه tenant، jobهای worker و فراخوانی‌های خروجی) و هر دقیقه metric هم به همان endpoint می‌فرستند (`OTEL_METRICS_EXPORTER=none` آن‌ها را خاموش می‌کند). `OTEL_TRACES_SAMPLER_ARG` سهم traceهایی را که نگه داشته می‌شوند تعیین می‌کند. گزارش‌ها با `LOG_LEVEL` به خروجی استاندارد می‌روند و Compose آن‌ها را چرخش می‌دهد. traceها هرگز دادهٔ شخصی ندارند.

### خروجی منطقه‌ای (اقامت داده در EU) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` می‌گوید stack به سازمان‌های اتحادیهٔ اروپا خدمت می‌دهد. آن‌گاه worker هر درخواست خروجی‌ای را که برای سازمان سنجاق‌شده به EU انجام می‌شود به allowlist محدود می‌کند (21-compliance.md، بخش 8.1). allowlist شامل میزبان‌هایی است که سرویس‌های پیکربندی‌شده برای منطقه اعلام می‌کنند (نقطهٔ پایانی ذخیره‌سازی، ارائه‌دهندهٔ ایمیل، ارائه‌دهندهٔ ویدیوی میزبانی‌شده، مقصدهای ذخیره‌سازی خود سازمان، ارائه‌دهندگان هوش مصنوعی و حساب ایمیل)، میزبان‌های هر سرویسی زیر derogation فعال و میزبان‌هایی که در `QUIRE_EGRESS_ALLOW_HOSTS` می‌نویسید. درخواست به هر میزبان عمومی دیگر پیش از فرستادن رد می‌شود؛ ردشدن در گزارش حسابرسی سازمان با `privacy/egress_refused` نوشته و در Compliance، Data residency فهرست می‌شود.

| تنظیم | مقادیر | اثر |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | فهرست hostnameهای جداشده با ویرگول یا `*.example.org` برای همهٔ زیردامنه‌ها | میزبان‌های افزوده‌ای که سازمان EU می‌تواند به آن‌ها دسترسی یابد. endpoint وب‌هوک، xAPI و SIEM، خوراک وبلاگ و میزبان‌های Amazon SES را اینجا بگذارید، چون انتخاب خود سازمان‌اند و هیچ سرویسی اعلامشان نمی‌کند. Loopback، نشانی خصوصی و نام تک‌برچسبی مانند `web` یا `clamav` شبکهٔ خودتان است و هرگز بررسی نمی‌شود |

سازمان‌های UK و US به فهرست میزبان محدود نیستند و بررسی منطقهٔ سرویس برایشان برقرار می‌ماند. فهرست را روی worker تنظیم کنید؛ صفحهٔ مدیریت برای نمایش allowlist آن را از web tier می‌خواند، پس در `docker/.env` بگذارید که همهٔ سرویس‌ها می‌خوانند.

بررسی برنامه خطا و ورودی حسابرسی روشنی می‌دهد، اما تضمین نیست: کد ممکن است اشتباه کند. تضمین را شبکه فراهم می‌کند. Compose خودش آن را اجرا نمی‌کند. برای stack منطقه‌ای، سرویس‌های `worker` و `web` را در شبکهٔ `internal: true` بگذارید که تنها مسیر خروجش egress proxy باشد (برای نمونه container مربوط به Squid یا tinyproxy)؛ proxy باید همان میزبان‌های `QUIRE_EGRESS_ALLOW_HOSTS` و میزبان سرویس‌های پیکربندی‌شده را مجاز کند و برای سرویس‌ها `HTTPS_PROXY` بگذارید. صفحهٔ اقامت داده میزبان‌هایی را که برنامه مجاز می‌داند دقیقاً فهرست می‌کند تا دو فهرست را مقایسه کنید.

## سلامت <!--quire:health-->

| Endpoint | معنا |
| --- | --- |
| `/healthz` | زنده‌بودن: فرایند پاسخ می‌دهد. بررسی سلامت Compose همین را به کار می‌برد |
| `/readyz` | آمادگی: وابستگی‌ها دسترس‌پذیرند و وضعیت تنظیم هر سرویس اختیاری گزارش می‌شود. load balancer را به این نشانی بفرستید |

`docker compose -f docker/compose.yaml ps` سلامت هر سرویس را نشان می‌دهد.

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

سرویس `proxy` (Caddy، Apache-2.0، `docker/caddy/Caddyfile`) بخشی از stack پیش‌فرض است. به پورت‌های ۸۰ و ۴۴۳ پاسخ می‌دهد و چنین مسیریابی می‌کند:

| میزبان یا مسیر | مقصد |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`، همهٔ زیردامنه‌های tenant و دامنه‌های سفارشی | `web` |
| `/_collab/` در آن میزبان‌ها | `collab` (websocket، `QUIRE_COLLAB_URL`) |
| `/_realtime/connection/` در آن میزبان‌ها | websocket مشتری `centrifugo`؛ API سرورش هیچ‌وقت افشا نمی‌شود |
| `/_images/` در آن میزبان‌ها | `imgproxy` با profile `images` (`IMGPROXY_URL`) |

`init-env.sh` از دو origin، `QUIRE_PROXY_APP_HOST`، `QUIRE_PROXY_CONTENT_HOST`، `QUIRE_PROXY_HTTPS_PORT`، `QUIRE_COLLAB_URL` و `IMGPROXY_URL` را به‌دست می‌آورد تا از هم دور نشوند. اگر originای را دستی تغییر می‌دهید، همه را با هم ویرایش کنید.

گواهی‌ها تابع `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) برای hostnameهای واقعی. DNS هر دو origin و هر میزبان tenant باید به اینجا برسد و پورت‌های ۸۰ و ۴۴۳ از اینترنت در دسترس باشند.

گواهی میزبان tenant هنگام نخستین بازدید و فقط وقتی صادر می‌شود که web تأیید کند نام به همین نصب تعلق دارد (`/tls-allowed` که در شبکهٔ Compose پرسیده می‌شود). گواهی wildcard یا افزونهٔ DNS provider لازم نیست و غریبه‌ای که نامی را به میزبان اشاره دهد نمی‌تواند باعث درخواست گواهی شود. گواهی‌ها و مرجع محلی در volume `caddy-data` هستند؛ اگر از `internal` استفاده می‌کنید همراه بقیه پشتیبان بگیرید.

Web فقط `X-Forwarded-For` را از proxy باور می‌کند: proxy نشانی ثابت (`QUIRE_PROXY_ADDRESS`، پیش‌فرض `172.29.64.10`) در subnet ثابتی (`QUIRE_COMPOSE_SUBNET`) دارد و `QUIRE_TRUSTED_PROXY_CIDRS` همان نشانی را مشخص می‌کند. اگر subnet با شبکه‌ای در میزبان تداخل داشت، هر دو را عوض کنید، ابتدا `docker compose down` را اجرا کنید و پس از آن `up` را.

## پشت reverse proxy خودتان <!--quire:behind-your-own-reverse-proxy-->

برای استفاده از load balancer یا 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://`) و بازهٔ نشانی proxy را در `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/fa/ops/install/index.mdx
