---
title: "Installere Quire med Docker Compose"
description: "Installer Quire på din egen infrastruktur med Docker Compose."
image: "https://docs.quirelms.com/og.png"
---

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

# Installere Quire med Docker Compose

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

Dette er hele produktet på én vert: LMS-et, bakgrunnsarbeidet dens, sanntids- og samredigeringstjenestene, og alle valgfrie tjenester bak en profil. Utformingen er `docs/architecture/23-ops.md` seksjon 2.

Andre mål: [Vercel](/nb/ops/vercel/) og [Cloudflare Workers](/nb/ops/cloudflare/) kjører kun webnivået. Oppgraderinger er i [upgrade.md](/nb/ops/upgrade/), og sikkerhetskopier og gjenopprettingsøvelsen i [backup-restore.md](/nb/ops/backup-restore/).

## Hva du trenger <!--quire:what-you-need-->

- Docker Engine 27 eller nyere med Compose-programtillegget 2.30 eller nyere.
- 4 CPU-kjerner og 8 GB minne for standardstabelen; 8 kjerner og 16 GB med `--profile full` (ClamAV alene holder omtrent 1,5 GB signaturer).
- Et DNS-navn for webnivået og et andre for ikke-betrodd innhold. De må være ulike verter: SCORM-pakker og opplastet HTML kjører på innholdsopprinnelsen slik at de aldri kan lese LMS-ets informasjonskapsler.
- For en lokal test peker `lvh.me` og `*.localhost` til 127.0.0.1, som er det `docker/.env.example` bruker. Stabelens egen `proxy`-tjeneste tjener begge over https med en lokal sertifikatutsteder, så ingenting annet installeres (se «TLS»).
- Port 80 og 443 ledige på verten (`QUIRE_PROXY_HTTP_PORT` og `QUIRE_PROXY_HTTPS_PORT` flytter dem).

## Første kjøring <!--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` skriver `docker/.env` fra `docker/.env.example` med alle hemmeligheter generert (databasepassord, signerings- og hovednøklene, innholdsstartnøkkelparet) og revisjonssjekkpunktets signeringsnøkkel i `docker/secrets/audit-signing-key.pem`, som Compose monterer inn i arbeiderne som en hemmelighet. Den trenger bare `sh`, `awk` og `openssl`, og den nekter å overskrive en eksisterende `docker/.env`. Kopier begge filer av verten: uten `QUIRE_MASTER_KEY` kan ikke en gjenopprettet database dekryptere sine lagrede legitimasjoner. For å fylle ut filen for hånd i stedet, `cp docker/.env.example docker/.env`; filen sier hvordan hver hemmelighet genereres.

Begge opprinnelser må være `https`: innholdstjenesten nekter ren http i produksjon, og de må ikke dele et registrerbart domene. `proxy`-tjenesten terminerer TLS for begge (se «TLS»); `init-env.sh` nekter en `http://`-opprinnelse.

Stabelen starter i en fast rekkefølge, og hvert steg venter på det før det:

1. `postgres` blir sunn. På aller første start setter init-skriptet dens (`docker/postgres/init/90-passwords.sh`) de fire rollepassordene.
2. `migrate` bruker alle migreringer og starter opp jobbkøen i kontrolldatabasen og i alle dedikerte tenantdatabaser, sjekker at alle er enige, og avslutter deretter (docs/ops/upgrade.md). Migreringer kjøres på hver start og er idempotente, så en oppgradering er et nytt bilde og en omstart.
3. `init` (`apps/web/src/first-run.ts`) registrerer applikasjonsdatabasen under `QUIRE_DATABASE_ID` og, når `QUIRE_SETUP_ADMIN_EMAIL` er satt, oppretter den første organisasjonen og administratoren dens. Påloggingsadressen og et generert passord skrives ut én gang, i `docker compose logs init`.
4. `web`, `content`, `worker`, `scheduler`, `collab` og `centrifugo` starter.
5. `proxy` starter når `web` og `content` er sunne.

Åpne `https://demo.` etterfulgt av applikasjonsdomenet ditt (`init`-loggen skriver ut den eksakte påloggingsadressen), og logg på. På en lokal installasjon, stol på proxyens sertifikatutsteder først (se «TLS»). Bytt det genererte passordet på `/account/security`.

En prosess startet uten en påkrevd hemmelighet nekter å starte og navngir den manglende innstillingen i loggen sin. Ingenting starter halvkonfigurert.

## Tjenester og profiler <!--quire:services-and-profiles-->

| Tjeneste | Profil | Hva den gjør |
| --- | --- | --- |
| postgres | alltid | Databasen (PostgreSQL 18 med pgvector, bygget fra `docker/postgres.Dockerfile`), med WAL arkivert fra første oppstart |
| migrate, init | alltid | Engangs: migreringer, deretter første kjøring |
| web | alltid | LMS-et, på `QUIRE_HTTP_PORT` (8080) |
| content | alltid | Opprinnelsen for ikke-betrodd innhold, på `QUIRE_CONTENT_PORT` (8081) |
| worker | alltid | Bakgrunnsjobber: e-post, rapporter, filbehandling, webhooks |
| scheduler | alltid | Gjentakende jobber: registrerer de 64 kjøretidsplanene og gir dem til arbeideren; én leder om gangen |
| collab | alltid | Samredigeringswebsocket, på `QUIRE_COLLAB_HTTP_PORT` (1234) |
| centrifugo | alltid | Sanntidsutvifting, på `QUIRE_REALTIME_PORT` (8000) |
| proxy | alltid | Caddy, TLS-inngangen på port 80 og 443 (se "TLS") |
| valkey | `cache` | Mellomlager og hastighetsgrenser |
| clamav | `scan` | Skadeligvareskanning av opplastinger |
| gotenberg | `preview` | Office-til-PDF-forhåndsvisninger, vitnemålrendring |
| imgproxy | `images` | Skalerte og konverterte bilder |
| transcoder | `video` | Arbeiderbildet med en LGPL-kun ffmpeg, for videoversjoner |
| seaweedfs | `storage` | S3-kompatibel objektlagring på denne verten |
| otelcol | `observability` | En OpenTelemetry-samler |
| mailpit | `devmail` | Fanger all utgående e-post, for å prøve ut Quire |
| backup | `backup` | Engangsbasesikkerhetskopi; se backup-restore.md |
| backup-scheduler, backup-offsite | `backup` | En basesikkerhetskopi hver `QUIRE_BACKUP_INTERVAL_HOURS`, og krypterte kopier utenfor verten med en ukentlig verifiseringsøvelse |
| h5p | `h5p` | H5P LTI 1.3-verktøybildet du leverer i `QUIRE_H5P_IMAGE`, på `QUIRE_H5P_PORT` (8090); se "Connecting an H5P provider" |

`--profile full` starter alle valgfrie tjenester unntatt `backup` og `h5p`. Start en med `docker compose -f docker/compose.yaml --profile scan up -d`. Uten en valgfri tjeneste virker Quire fortsatt og sier hva som mangler: ingen skanner betyr at opplastinger lagres uskannet og administratoren får beskjed; ingen Gotenberg betyr at filer tilbyr nedlasting i stedet for forhåndsvisning; ingen transkoder betyr at video spilles som originalfilen.

Alle tredjepartsbilder og lisensforpliktelsene deres listes i `docker/third-party-containers.yaml`.

### Koble til en H5P-leverandør <!--quire:connecting-an-h5p-provider-->

Quire bygger ikke inn eller leverer en H5P-kjøretid eller sidevogn (ADR 0019). Hvis du bruker H5P, skaff ditt eget driftede abonnement eller drift din egen selvdrevne H5P-instans separat fra Quire. Registrer den leverandøren som et LTI 1.3 eksternt verktøy og legg innholdet dens til kurs som verktøyaktiviteter. Quire utveksler karakterer og aktivitets-/vurderingsfremdrift gjennom LTI Assignment and Grade Services (AGS). Hvis leverandøren også sender xAPI-erklæringer, konfigurer det separat for Quires xAPI-erklæringslager; AGS-karakter-/fremdriftsutveksling sender ikke xAPI-erklæringer. Moodle-importer rapporterer H5P-aktiviteter som at de trenger en LTI-verktøytilkobling. Leverandøren forblir ansvarlig for sin H5P-kjøretid, redigering, innholdsbank og forsøkshistorikk.

For å kjøre din egen selvdrevne instans på denne verten, sett `QUIRE_H5P_IMAGE` til bildet dens og start `h5p`-profilen. Compose publiserer den på `QUIRE_H5P_PORT` (8090) og beholder dataene dens i `h5p-data`-volumet; bildet, og forpliktelsene som følger med det, forblir dine.

## Innstillinger <!--quire:settings-->

Hver prosess leser `docker/.env`. Malen, `docker/.env.example`, viser hver innstilling med standarden dens. Gruppene:

### Adresser <!--quire:addresses-->

| Innstilling | Betydning |
| --- | --- |
| `QUIRE_APP_ORIGIN` | LMS-ets offentlige adresse, som `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | Innholdsopprinnelsen, en annen vert |
| `QUIRE_PLATFORM_DOMAINS` | Domener organisasjoner bor under, kommaseparert |
| `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` her. Se de andre veiledningene for `vercel` og `cloudflare` |
| `QUIRE_TRUSTED_PROXY_CIDRS` | Proxyer hvis `X-Forwarded-For` stoles på |

### Hemmeligheter <!--quire:secrets-->

| Innstilling | Betydning |
| --- | --- |
| `QUIRE_SECRET_KEY` | Signerer økter og tokens. 64 heksadesimale tegn |
| `QUIRE_MASTER_KEY` | Pakker inn lagrede legitimasjoner som SSO- og webhook-hemmeligheter. 32 bytes, base64. Webnivået og arbeideren trenger samme verdi. Rotering: [key-rotation.md](/nb/ops/key-rotation/) |
| `QUIRE_MASTER_KEY_VERSION` | Hovednøkkelens versjonsmerkelapp, `v1` når usatt. Hev den når du roterer |
| `QUIRE_MASTER_KEY_RETIRED` | Tidligere hovednøkler fortsatt trengt for å lese det de forseglet, som `v1=<base64>`. Fjern etter at en rotering fullføres uten noe uløst |
| `QUIRE_COLLAB_SIGNING_KEY` | Delt av web og collab for å signere redigeringstokens |
| `QUIRE_BACKUP_SIGNING_KEY` | Signerer kurssikkerhetskopier (valgfri) |

Behold en kopi av `QUIRE_MASTER_KEY` et annet sted enn denne verten. En database gjenopprettet uten den kan ikke dekryptere legitimasjonen den holder.

### Database <!--quire:database-->

| Innstilling | Betydning |
| --- | --- |
| `POSTGRES_PASSWORD` | Superbrukeren, brukt av containeren og sikkerhetskopier |
| `QUIRE_DB_APP_PASSWORD`, `QUIRE_DB_MIGRATOR_PASSWORD`, `QUIRE_DB_REPORT_PASSWORD`, `QUIRE_DB_AUDIT_PASSWORD` | Rollepassord, satt på første start |
| `DATABASE_URL` | Applikasjonsrollen. Sikkerhet på radnivå gjelder alle spørringer den gjør |
| `DATABASE_MIGRATOR_URL`, `QUIRE_MIGRATION_URL` | Migratorrollen, for `migrate` og `init` |
| `QUIRE_SUPERUSER_URL` | Brukes bare av første kjøring |
| `QUIRE_REPORT_DATABASE_URL` | Den skrivebeskyttede rapportrollen, for rapporter og rapportbyggeren |
| `QUIRE_AUDIT_DATABASE_URL` | Revisjonsrollen, for revisjonskonsollen og SIEM-eksport |
| `QUIRE_DATABASE_ID` | En UUID, fast for installasjonens levetid |

Rollepassord brukes bare når databasevolumet først opprettes. For å endre et senere, bruk `ALTER ROLE` og oppdater deretter den samsvarende URL-en.

`QUIRE_REPORT_DATABASE_URL` brukes for den fysiske databasen konfigurert av `DATABASE_URL`. For enhver annen registrert fysisk database, sett dens egen `quire_report`-tilkoblings-URL i web- og arbeidermiljøene, og legg deretter variabelnavnet i den databasens **Rapporteringsmiljøvariabel**-felt som `env:NAME`. Referansen må peke til samme database som app-tilkoblingen dens, ideelt lesereplikaen dens. Alle rapportflater følger tenanten til sin egen databases rapporttilkobling: rapportbyggeren og lagrede rapporter, planlagte leveringer, rapporteksporter, analyse, revisjonsloggen, REST-revisjonsressursene og assistentens revisjonssøk. Ingen av dem låner noen gang en annen databases rapport-URL. Når en database ikke har noen rapporttilkobling, kjører ordinære rapporter på den databasens egen applikasjonstilkobling, mens analyse og alle revisjonslesinger nekter og sier fra, fordi applikasjonsrollen ikke kan lese revisjonssporet.

### Drivere <!--quire:drivers-->

| Innstilling | Denne utgivelsen | Merknader |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (standard), `s3` eller `azure` | `local` beholder filer i `files`-volumet. `s3` dekker AWS S3, R2, GCS-samvirke og andre S3-kompatible lagre, med gjenopptakbare flerdeltsopplastinger |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (standard), `sse`, `centrifugo` eller `durable_objects` | `inprocess` er riktig for én webcontainer; bruk `centrifugo` eller `sse` når det er flere |
| `QUIRE_CACHE_DRIVER` | `memory` (standard), `postgres` eller `valkey` | `memory` er per prosess; bruk `valkey` eller `postgres` slik at hastighetsgrenser holder på tvers av containere |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (standard) eller `progressive_mp4` | Eller en driftet leverandør: Cloudflare Stream, Mux eller Bunny, etter nøklene deres |
| `QUIRE_IMAGE_DRIVER` | `noop` (standard), `imgproxy` eller `cloudflare` | `noop` tjener alle bilder i originalstørrelse. `imgproxy` trenger `images`-profilen og innstillingene nedenfor; `cloudflare` bruker Cloudflare Images |
| `QUIRE_MEETING_PROVIDER` | `bbb`, `zoom`, `teams`, `meet`, `jitsi` eller `in_process` | Plattformstandarden for direktesendinger. Usatt sier direktesendinger at de ikke er konfigurert, til en organisasjon kobler til sin egen konto under Integrasjoner, leverandør for direktesendinger. En organisasjons egen konto vinner alltid over denne verdien. Hver leverandørs egne innstillinger (`BBB_URL` og `BBB_SECRET`, `ZOOM_*`-, `TEAMS_*`-, `GOOGLE_MEET_*`- og `JITSI_*`-variablene) leses bare for leverandøren navngitt her |
| `QUIRE_MEETING_REGIONS` | En kommaliste med `eu`, `uk`, `us` | Hvor plattformstandardleverandøren behandler møter. Usatt sjekkes den ikke mot en organisasjon festet til en region, som før. En organisasjons egen konto oppgir regionene sine på siden sin |

En driververdi denne utgivelsen ikke inkluderer avvises når webnivået starter, med innstillingen navngitt, i stedet for stilltiende å erstattes av standarden.

### Bilder <!--quire:images-->

Sider ber om bilder i fire faste størrelser gjennom `/api/files/{id}/image/{size}`, som sjekker samme tilgang som filen selv og deretter omdirigerer til bildetjenesten. Hver organisasjon kan be om `QUIRE_IMAGE_SPECS_PER_HOUR` (standard 2000) nye bilde- og størrelsespar i timen; størrelser allerede produsert den timen teller ikke. Bruk `valkey` eller `postgres` for `QUIRE_CACHE_DRIVER` med mer enn én webcontainer, slik at grensen holder på tvers av dem.

| Innstilling | Driver | Merknader |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | Adressen nettlesere når imgproxy på, for eksempel `https://images.example.org`. `images`-profilen publiserer den på `QUIRE_IMAGES_PORT` (8082) |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `imgproxy` | Heksadesimale strenger, samme verdier imgproxy startes med. Generer hver med `openssl rand -hex 32`. Quire signerer alle bildeadresser med dem, slik at imgproxy rendrer ingenting Quire ikke ba om |
| `QUIRE_IMAGE_SOURCE_ORIGIN` | `imgproxy` med lokal lagring | Hvor imgproxy henter originaler fra. Compose setter `http://web:3000`. Med `s3`- eller `azure`-lagring henter imgproxy fra bøtten og denne brukes ikke |
| `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_IMAGES_TOKEN`, `CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | Et API-token med Images-redigeringstillatelse, og kontohashen fra Images, utviklerressurser. Slå på fleksible varianter for kontoen |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | Valgfri. Når satt er bilder private og alle adresser signeres og utløper. Uten den er bilder offentlige på adresser utledet fra `QUIRE_SECRET_KEY` som ingen kan gjette |

Cloudflare Images beholder sin egen kopi av hver original den tjener. Når en fil slettes, sletter arbeideren den kopien før originalen.

### Kø <!--quire:queue-->

Bakgrunnsjobber bruker pg-boss i samme Postgres-database, så det finnes ingen køtjeneste å kjøre og ingenting å konfigurere. Jobber køes i samme transaksjon som endringen som forårsaket dem, slik at en krasj verken kan miste en eller sende en to ganger. `QUIRE_QUEUE_DRIVER` er `pgboss` her, standarden dens; `vercel` og `cloudflare` flytter bare de lette varslings- og webhook-leveringene til plattformens egen kø, og Vercel- og Cloudflare-veiledningene beskriver dem og hvordan webnivåene deres køer.

### E-post <!--quire:email-->

Sett én av:

- `QUIRE_EMAIL_PROVIDER_CONFIG`: et JSON-objekt som navngir en HTTP-leverandør og legitimasjonen dens, som `{"provider":"postmark","token":"..."}`. Postmark, Amazon SES, Mailgun, SendGrid og Resend støttes.
- `QUIRE_SMTP_URL`: `smtp://user:password@host:587`. Kun dette målet; de tjenerløse målene blokkerer SMTP.

`QUIRE_MAIL_FROM` er avsenderen. For å prøve ut Quire, start `devmail`-profilen, sett `QUIRE_SMTP_URL=smtp://mailpit:1025`, og les e-post på `http://localhost:8025`.

### Valgfrie tjenester <!--quire:optional-services-->

| Innstilling | Med profil |
| --- | --- |
| `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` eller `QUIRE_MEILISEARCH_URL` | Eksternt søk; Postgres fulltekst ellers |
| `QUIRE_BREACH_CHECK_PROVIDER=off`, `QUIRE_BREACH_CHECK_URL` | Sjekk av passordlekkasje. På som standard mot `api.pwnedpasswords.com` (bare et femtegns hashprefiks sendes); `off` slår den av, og URL-en peker på et område-API du drifter |

### Observerbarhet <!--quire:observability-->

`OTEL_EXPORTER_OTLP_ENDPOINT` navngir samleren alle prosesser sender spor og metrikker til; med `observability`-profilen er den `http://otelcol:4318`, og `docker/otel-collector.yaml` er der du legger til eksportøren for backend-en din. Webnivå-, arbeider-, planlegger-, innholds- og samredigeringsprosessene eksporterer spann over OTLP/HTTP (webforespørsler, tenantdatabasetransaksjoner, arbeiderjobber og utgående kall) når den er satt, og metrikker til samme endepunkt hvert minutt (`OTEL_METRICS_EXPORTER=none` slår dem av). `OTEL_TRACES_SAMPLER_ARG` setter andelen spor som beholdes. Logger går til standardutdata på `LOG_LEVEL`, og Compose roterer dem. Spor bærer aldri personopplysninger.

### Regional utgående trafikk (EUs databosted) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` sier at stabelen betjener EU-organisasjoner. Arbeideren holder da alle utgående forespørsler gjort for en organisasjon festet til EU til en tillatelsesliste (21-compliance.md seksjon 8.1). Tillatelseslisten er vertene de konfigurerte tjenestene erklærer for regionen (lagringsendepunktet, e-postleverandøren, en driftet videoleverandør, organisasjonens egne lagringsmål, AI-leverandører og e-postkonto), vertene til enhver tjeneste under et aktivt unntak, og vertene du viser i `QUIRE_EGRESS_ALLOW_HOSTS`. En forespørsel til enhver annen offentlig vert nektes før den sendes, nektelsen skrives til organisasjonens revisjonsspor som `privacy/egress_refused`, og den listes under Samsvar, databosted.

| Innstilling | Verdier | Effekt |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | En kommaliste med vertsnavn, eller `*.example.org` for alle subdomener | Ekstra verter en EU-organisasjon kan nå. Webhook-, xAPI- og SIEM-endepunkter, bloggfeeder og Amazon SES-verter hører hjemme her, fordi de er en organisasjons eget valg og ingen tjeneste erklærer dem. Tilbakekobling, private adresser og enkeltmerkelappnavn som `web` eller `clamav` er ditt eget nettverk og sjekkes aldri |

Storbritannia- og USA-organisasjoner holdes ikke til en vertsliste; de beholder tjenesteregionsjekkene. Sett listen på arbeideren; adminsiden leser den på webnivået for å vise tillatelseslisten, så legg den i `docker/.env`, som alle tjenester leser.

Applikasjonssjekken gir en tydelig feil og en revisjonsoppføring, og den er ikke garantien: kode kan ta feil. Garantien er nettverket. Compose håndhever det ikke for deg. For en regional stabel, legg `worker`- og `web`-tjenestene på et `internal: true`-nettverk hvis eneste rute ut er en utgående proxy (for eksempel en Squid- eller tinyproxy-container) som tillater de samme vertene som `QUIRE_EGRESS_ALLOW_HOSTS` pluss vertene til dine konfigurerte tjenester, og sett `HTTPS_PROXY` for disse tjenestene. Bostedssiden viser de eksakte vertene applikasjonen tillater, slik at de to listene kan sammenlignes.

## Helse <!--quire:health-->

| Endepunkt | Betydning |
| --- | --- |
| `/healthz` | Livlighet: prosessen svarer. Compose-helsesjekker bruker dette |
| `/readyz` | Beredskap: avhengigheter nåbare, og hver valgfri tjeneste rapportert som konfigurert eller ikke. Pek lastbalansereren din hit |

`docker compose -f docker/compose.yaml ps` viser hver tjenestes helse.

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

`proxy`-tjenesten (Caddy, Apache-2.0, `docker/caddy/Caddyfile`) er en del av standardstabelen. Den svarer på port 80 og 443 og ruter:

| Vert eller sti | Går til |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`, alle tenant-subdomener og egne domener | `web` |
| `/_collab/` på disse vertene | `collab` (websocket, `QUIRE_COLLAB_URL`) |
| `/_realtime/connection/` på disse vertene | `centrifugo`s klientwebsocket; tjener-API-et dens eksponeres aldri |
| `/_images/` på disse vertene | `imgproxy`, med `images`-profilen (`IMGPROXY_URL`) |

`init-env.sh` utleder `QUIRE_PROXY_APP_HOST`, `QUIRE_PROXY_CONTENT_HOST`, `QUIRE_PROXY_HTTPS_PORT`, `QUIRE_COLLAB_URL` og `IMGPROXY_URL` fra de to opprinnelsene, slik at de ikke kan drive fra hverandre. Rediger dem sammen hvis du endrer en opprinnelse for hånd.

Sertifikater følger `QUIRE_PROXY_TLS`:

- `internal` (standarden): Caddys egen sertifikatutsteder, for `localhost`, `*.localhost` og `lvh.me`. Stol på roten dens én gang, og bla deretter:

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

  Legg `quire-local-ca.crt` til systemets eller nettleserens tillitslager. `curl` tar den med `--cacert`.
- En e-postadresse: automatiske ACME-sertifikater (Let's Encrypt, deretter ZeroSSL) for virkelige vertsnavn. DNS for begge opprinnelser og alle tenantverter må peke hit, og port 80 og 443 må være nåbare fra internett.

Tenantverter utstedes ved behov, ved første besøk, og bare når web bekrefter at navnet tilhører denne installasjonen (`/tls-allowed`, spurt på Compose-nettverket). Intet jokertegnsertifikat eller DNS-leverandørprogramtillegg trengs, og en fremmed som peker et navn mot verten kan ikke få den til å be om sertifikater. Sertifikater og den lokale utstederen ligger i `caddy-data`-volumet; sikkerhetskopier det med resten hvis du bruker `internal`.

Web stoler på `X-Forwarded-For` kun fra proxyen: proxyen har en fast adresse (`QUIRE_PROXY_ADDRESS`, standard `172.29.64.10`) på et fast subnett (`QUIRE_COMPOSE_SUBNET`), og `QUIRE_TRUSTED_PROXY_CIDRS` navngir den adressen. Hvis subnettet kolliderer med et nettverk på verten, endre begge og kjør `docker compose down` før `up`.

## Bak din egen omvendte proxy <!--quire:behind-your-own-reverse-proxy-->

For å bruke en lastbalanserer eller proxy du allerede drifter i stedet, utelat `proxy` (`docker compose up -d --scale proxy=0`) og terminer TLS foran `web` (8080), `content` (8081), `collab` (1234, websocket) og `centrifugo` (8000, websocket). Sett de offentlige adressene i `QUIRE_APP_ORIGIN`, `QUIRE_CONTENT_ORIGIN` og `QUIRE_COLLAB_URL` (`wss://`), og proxyens adresserekke i `QUIRE_TRUSTED_PROXY_CIDRS`.

## Feilsøking <!--quire:troubleshooting-->

- `init` avslutter med «QUIRE_DATABASE_ID is not a UUID»: sett den med `uuidgen`.
- `web` starter på nytt med «did not start on compose»: loggen viser hver innstilling den ikke kan innfri og hva den skal bruke i stedet.
- Endring av et rollepassord i `.env` etter første start gjør ingenting: init-skriptet kjører én gang. Bruk `ALTER ROLE`.
- Opplastinger feiler med en skannefeil mens `CLAMAV_URL` er satt: ClamAV laster ned signaturene sine på første start, noe som tar noen minutter.

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