---
title: "Installér Quire med Docker Compose"
description: "Installér 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/da/llms.txt
> Use this file to discover all available pages before exploring further.

# Installér Quire med Docker Compose

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

Dette er det fulde produkt på én vært: LMS'et, dets baggrundsarbejde, tjenesterne til
realtid og fælles redigering samt alle valgfrie tjenester bag profiler.
Designet er beskrevet i afsnit 2 i `docs/architecture/23-ops.md`.

Andre mål: [Vercel](/da/ops/vercel/) og [Cloudflare Workers](/da/ops/cloudflare/) kører kun weblaget. Opgraderinger beskrives i [upgrade.md](/da/ops/upgrade/), og backup samt gendannelsesøvelsen i [backup-restore.md](/da/ops/backup-restore/).

## Krav <!--quire:what-you-need-->

- Docker Engine 27 eller nyere med Compose-plugin 2.30 eller nyere.
- 4 CPU-kerner og 8 GB hukommelse til standardstacken; 8 kerner og 16 GB
  med `--profile full` (ClamAV alene bruger omkring 1,5 GB til signaturer).
- Et DNS-navn til weblaget og et andet til ikke-betroet indhold. De
  skal være forskellige værter: SCORM-pakker og uploadet HTML kører på indholdets
  origin, så de aldrig kan læse LMS-cookies.
- Til lokal afprøvning peger `lvh.me` og `*.localhost` på 127.0.0.1, hvilket
  er det, `docker/.env.example` bruger. Stackens egen tjeneste `proxy` leverer
  begge via https med en lokal certifikatudsteder, så intet andet
  skal installeres (se "TLS").
- Port 80 og 443 skal være ledige på værten (`QUIRE_PROXY_HTTP_PORT` og
  `QUIRE_PROXY_HTTPS_PORT` flytter dem).

## Første opstart <!--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` opretter `docker/.env` ud fra `docker/.env.example`
og genererer alle hemmeligheder (databaseadgangskoder, signerings- og hovednøgler
samt nøgleparret til start af indhold) og auditkontrolpunktets signeringsnøgle i
`docker/secrets/audit-signing-key.pem`, som Compose monterer i workers som en hemmelighed. Den kræver kun `sh`, `awk` og `openssl` og nægter at
overskrive en eksisterende `docker/.env`. Kopiér begge filer væk fra værten: Uden
`QUIRE_MASTER_KEY` kan en gendannet database ikke dekryptere de legitimationsoplysninger, den indeholder.
Hvis du hellere vil udfylde filen manuelt, skal du køre `cp docker/.env.example docker/.env`; filen forklarer, hvordan hver hemmelighed genereres.

Begge origins skal være `https`: indholdstjenesten afviser almindelig http i produktion, og de må
ikke dele et registrerbart domæne. Tjenesten `proxy` afslutter TLS for begge (se "TLS"); `init-env.sh` afviser en origin med `http://`.

Stacken starter i en fast rækkefølge, og hvert trin venter på det foregående:

1. `postgres` bliver sund. Ved første opstart indstiller dets init-script
   (`docker/postgres/init/90-passwords.sh`) adgangskoderne for de fire roller.
2. `migrate` anvender alle migreringer og starter jobkøen i kontroldatabasen og i hver dedikeret lejerdatabase, kontrollerer, at de er enige, og afslutter derefter (se docs/ops/upgrade.md).
   Migreringer køres ved hver opstart og er idempotente, så en opgradering består af et nyt image og en genstart.
3. `init` (`apps/web/src/first-run.ts`) registrerer applikationsdatabasen under
   `QUIRE_DATABASE_ID` og opretter, når `QUIRE_SETUP_ADMIN_EMAIL` er angivet, den første organisation og dens administrator. Loginadressen og en genereret adgangskode vises én gang i loggen fra `docker compose logs init`.
4. `web`, `content`, `worker`, `scheduler`, `collab` og `centrifugo` starter.
5. `proxy` starter, når `web` og `content` er sunde.

Åbn `https://demo.` efterfulgt af dit applikationsdomæne (loggen fra `init`
viser den nøjagtige loginadresse), og log ind. På en lokal installation skal du først have tillid til
proxyens certifikatudsteder (se "TLS"). Skift den genererede adgangskode på `/account/security`.

En proces, der startes uden en påkrævet hemmelighed, nægter at starte og angiver
den manglende indstilling i loggen. Intet starter med en delvis konfiguration.

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

| Tjeneste | Profil | Funktion |
| --- | --- | --- |
| postgres | altid | Databasen (PostgreSQL 18 med pgvector, bygget fra `docker/postgres.Dockerfile`), hvor WAL arkiveres fra første opstart |
| migrate, init | altid | Engangskørsel: migreringer og derefter første opstart |
| web | altid | LMS'et på `QUIRE_HTTP_PORT` (8080) |
| content | altid | Origin til ikke-betroet indhold på `QUIRE_CONTENT_PORT` (8081) |
| worker | altid | Baggrundsjob: e-mail, rapporter, filbehandling, webhooks |
| scheduler | altid | Gentagne job: registrerer de 64 kørselstidsplaner og giver dem til worker; én leder ad gangen |
| collab | altid | Websocket til fælles redigering på `QUIRE_COLLAB_HTTP_PORT` (1234) |
| centrifugo | altid | Realtidsdistribution på `QUIRE_REALTIME_PORT` (8000) |
| proxy | altid | Caddy, TLS-indgangen på port 80 og 443 (se "TLS") |
| valkey | `cache` | Cache og hastighedsgrænser |
| clamav | `scan` | Virusscanning af uploads |
| gotenberg | `preview` | Office-til-PDF-forhåndsvisninger og certifikatgengivelse |
| imgproxy | `images` | Tilpassede og konverterede billeder |
| transcoder | `video` | Worker-image med LGPL-only ffmpeg til videogengivelser |
| seaweedfs | `storage` | S3-kompatibel objektlagring på denne vært |
| otelcol | `observability` | En OpenTelemetry-collector |
| mailpit | `devmail` | Fanger al udgående e-mail, når du afprøver Quire |
| backup | `backup` | Engangsgrundbackup; se backup-restore.md |
| backup-scheduler, backup-offsite | `backup` | Grundbackup hver `QUIRE_BACKUP_INTERVAL_HOURS` og krypterede kopier væk fra værten med en ugentlig kontroløvelse |
| h5p | `h5p` | H5P LTI 1.3-værktøjsimage, du leverer i `QUIRE_H5P_IMAGE`, på `QUIRE_H5P_PORT` (8090); se "Tilslut en H5P-udbyder" |

`--profile full` starter alle valgfrie tjenester bortset fra `backup` og `h5p`.
Start én tjeneste med `docker compose -f docker/compose.yaml --profile scan up -d`.
Quire fungerer stadig uden en valgfri tjeneste og fortæller, hvad der mangler: Uden
scanner gemmes uploads uden scanning, og administratoren får besked; uden
Gotenberg kan filer hentes, men ikke forhåndsvises; uden transcoder afspilles video som den oprindelige fil.

Alle tredjepartsimages og deres licensforpligtelser står i
`docker/third-party-containers.yaml`.

### Tilslut en H5P-udbyder <!--quire:connecting-an-h5p-provider-->

Quire indlejrer eller leverer ikke en H5P-runtime eller sidecar (ADR 0019). Hvis du bruger
H5P, skal du selv levere et hostet abonnement eller drive din egen selvhostede H5P-instans separat fra Quire. Registrér udbyderen som et eksternt LTI 1.3-værktøj, og føj indholdet til kurser som værktøjsaktiviteter. Quire udveksler karakterer og aktivitetens og bedømmelsens fremgang gennem LTI Assignment and Grade Services (AGS). Hvis udbyderen også sender xAPI-udsagn, skal du konfigurere det særskilt til Quires lager for xAPI-udsagn; udveksling af karakterer og fremgang via AGS sender ikke xAPI-udsagn. Moodle-importer angiver, at H5P-aktiviteter kræver en LTI-værktøjsforbindelse. Udbyderen har fortsat ansvaret for H5P-runtime, redigering, indholdsbibliotek og historik over forsøg.

Hvis du vil køre din egen selvhostede instans på denne vært, skal du angive dens
image i `QUIRE_H5P_IMAGE` og starte profilen `h5p`. Compose offentliggør den på `QUIRE_H5P_PORT`
(8090) og gemmer dens data i volumen `h5p-data`; imaget og dets tilhørende forpligtelser forbliver dit ansvar.

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

Alle processer læser `docker/.env`. Skabelonen `docker/.env.example` viser
hver indstilling med standardværdien. Grupperne:

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

| Indstilling | Betydning |
| --- | --- |
| `QUIRE_APP_ORIGIN` | LMS'ets offentlige adresse, f.eks. `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | Indholdsorigin på en anden vært |
| `QUIRE_PLATFORM_DOMAINS` | Domæner, som organisationer ligger under, kommasepareret |
| `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 vejledninger for `vercel` og `cloudflare` |
| `QUIRE_TRUSTED_PROXY_CIDRS` | Proxies, hvis `X-Forwarded-For` betragtes som troværdig |

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

| Indstilling | Betydning |
| --- | --- |
| `QUIRE_SECRET_KEY` | Signerer sessioner og tokens. 64 hextegn |
| `QUIRE_MASTER_KEY` | Indpakker gemte legitimationsoplysninger, f.eks. SSO- og webhook-hemmeligheder. 32 byte, base64. Weblaget og worker skal bruge samme værdi. Rotation: [key-rotation.md](/da/ops/key-rotation/) |
| `QUIRE_MASTER_KEY_VERSION` | Hovednøglens versionsetiket, `v1` hvis ikke angivet. Forøg den ved rotation |
| `QUIRE_MASTER_KEY_RETIRED` | Tidligere hovednøgler, der stadig skal bruges til at læse det, de forseglede, som `v1=<base64>`. Fjern den, når rotationen er færdig, og intet er uløst |
| `QUIRE_COLLAB_SIGNING_KEY` | Delt af web og collab til signering af redigeringstokens |
| `QUIRE_BACKUP_SIGNING_KEY` | Signerer kursusbackups (valgfri) |

Opbevar en kopi af `QUIRE_MASTER_KEY` et andet sted end på denne vært. En database, der gendannes uden den, kan ikke dekryptere de legitimationsoplysninger, den indeholder.

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

| Indstilling | Betydning |
| --- | --- |
| `POSTGRES_PASSWORD` | Superbrugeren, som containeren og backupprocesserne bruger |
| `QUIRE_DB_APP_PASSWORD`, `QUIRE_DB_MIGRATOR_PASSWORD`, `QUIRE_DB_REPORT_PASSWORD`, `QUIRE_DB_AUDIT_PASSWORD` | Adgangskoder for rollerne, indstillet ved første opstart |
| `DATABASE_URL` | Applikationsrollen. Row-level security gælder for alle forespørgsler, den foretager |
| `DATABASE_MIGRATOR_URL`, `QUIRE_MIGRATION_URL` | Migratorrollen til `migrate` og `init` |
| `QUIRE_SUPERUSER_URL` | Bruges kun ved første opstart |
| `QUIRE_REPORT_DATABASE_URL` | Den skrivebeskyttede rapportrolle til rapporter og rapportværktøjet |
| `QUIRE_AUDIT_DATABASE_URL` | Auditrollen til auditkonsollen og SIEM-eksport |
| `QUIRE_DATABASE_ID` | Vilkårligt UUID, fastlagt for installationens levetid |

Adgangskoderne for rollerne anvendes kun, når databasen først oprettes.
Hvis du senere vil ændre en adgangskode, skal du bruge `ALTER ROLE` og derefter opdatere den matchende URL.

`QUIRE_REPORT_DATABASE_URL` bruges til den fysiske database, der er konfigureret via `DATABASE_URL`. For enhver anden registreret fysisk database skal du angive dens egen `quire_report`-forbindelses-URL i web- og workermiljøerne og derefter angive variabelnavnet i databasens felt **Miljøvariabel til rapportering** som `env:NAME`. Referencen skal pege på den samme database som dens applikationsforbindelse, helst dens læsereplika. Alle rapportfunktioner følger lejeren til rapportforbindelsen for dens egen database: rapportværktøjet og gemte rapporter, planlagte leverancer, rapporteksport, analyse, auditloggen, REST-auditressourcerne og assistentens auditsøgning. Ingen af dem bruger nogensinde rapport-URL'en fra en anden database. Hvis en database ikke har rapportforbindelse, køres almindelige rapporter på databasens egen applikationsforbindelse, mens analyse og alle auditlæsninger afvises med en forklaring, fordi applikationsrollen ikke kan læse auditsporet.

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

| Indstilling | Denne udgivelse | Noter |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (standard), `s3` eller `azure` | `local` gemmer filer i volumen `files`. `s3` dækker AWS S3, R2, GCS-kompatibilitet og andre S3-kompatible lagre med genoptagelige multipart-uploads |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (standard), `sse`, `centrifugo` eller `durable_objects` | `inprocess` passer til én webcontainer; brug `centrifugo` eller `sse`, når der er flere |
| `QUIRE_CACHE_DRIVER` | `memory` (standard), `postgres` eller `valkey` | `memory` gælder pr. proces; brug `valkey` eller `postgres`, så hastighedsgrænser gælder på tværs af containere |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (standard) eller `progressive_mp4` | Eller en hostet udbyder: Cloudflare Stream, Mux eller Bunny via deres nøgler |
| `QUIRE_IMAGE_DRIVER` | `noop` (standard), `imgproxy` eller `cloudflare` | `noop` leverer alle billeder i deres oprindelige størrelse. `imgproxy` kræver profilen `images` og indstillingerne nedenfor; `cloudflare` bruger Cloudflare Images |
| `QUIRE_MEETING_PROVIDER` | `bbb`, `zoom`, `teams`, `meet`, `jitsi` eller `in_process` | Platformens standardudbyder til live-sessioner. Hvis den ikke angives, vises det, at live-sessioner ikke er konfigureret, indtil en organisation forbinder sin egen konto under Integrationer, Udbyder af live-sessioner. En organisations egen konto har altid forrang. Hver udbyders egne indstillinger (`BBB_URL` og `BBB_SECRET`, variablerne `ZOOM_*`, `TEAMS_*`, `GOOGLE_MEET_*` og `JITSI_*`) læses kun for udbyderen, der er angivet her |
| `QUIRE_MEETING_REGIONS` | En kommasepareret liste med `eu`, `uk`, `us` | Hvor platformens standardudbyder behandler møder. Hvis den ikke angives, kontrolleres den ikke mod en organisation, der er fastlåst til en region, som hidtil. En organisations egen konto viser sine regioner på sin side |

En driver-værdi, som ikke indgår i denne udgivelse, afvises, når weblaget
starter, og indstillingen nævnes i stedet for at blive erstattet stiltiende med
standardværdien.

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

Sider anmoder om billeder i fire faste størrelser via
`/api/files/{id}/image/{size}`, som kontrollerer samme adgang som selve filen
og derefter omdirigerer til billedtjenesten. Hver organisation kan anmode om
`QUIRE_IMAGE_SPECS_PER_HOUR` (standard 2000) nye kombinationer af billede og størrelse pr.
time; størrelser, der allerede er genereret den time, tæller ikke med. Brug `valkey` eller
`postgres` til `QUIRE_CACHE_DRIVER`, hvis der er mere end én webcontainer, så grænsen gælder på tværs af dem.

| Indstilling | Driver | Noter |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | Adressen, hvor browsere når imgproxy, f.eks. `https://images.example.org`. Profilen `images` offentliggør den på `QUIRE_IMAGES_PORT` (8082) |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `imgproxy` | Hexstrenge med de samme værdier, som imgproxy startes med. Generér hver med `openssl rand -hex 32`. Quire signerer alle billedadresser med dem, så imgproxy kun gengiver det, Quire har bedt om |
| `QUIRE_IMAGE_SOURCE_ORIGIN` | `imgproxy` med lokal lagring | Hvor imgproxy henter originalerne fra. Compose angiver `http://web:3000`. Med `s3`- eller `azure`-lagring henter imgproxy fra bucketten, og denne indstilling bruges ikke |
| `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_IMAGES_TOKEN`, `CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | Et API-token med tilladelse til at redigere Images og kontoens hash fra Images, Developer resources. Aktivér fleksible varianter for kontoen |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | Valgfri. Når den er angivet, er billeder private, og hver adresse signeres og udløber. Uden den er billeder offentlige på adresser afledt af `QUIRE_SECRET_KEY`, som ingen kan gætte |

Cloudflare Images opbevarer sin egen kopi af hver original, den leverer. Når en
fil slettes, sletter worker denne kopi før originalen.

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

Baggrundsjob bruger pg-boss i den samme Postgres-database, så der er ingen
køtjeneste, der skal køres, og intet, der skal konfigureres. Job lægges i kø i den samme
transaktion som den ændring, der udløste dem, så et nedbrud hverken kan miste et job eller
sende det to gange. `QUIRE_QUEUE_DRIVER` er her standardværdien `pgboss`; `vercel`
og `cloudflare` flytter kun lette notifikations- og webhookleverancer til
platformens egen kø. Vejledningerne til Vercel og Cloudflare beskriver dem
og hvordan deres weblag føjer job til køen.

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

Angiv én af følgende:

- `QUIRE_EMAIL_PROVIDER_CONFIG`: Et JSON-objekt med navnet på en HTTP-udbyder og
  dens legitimationsoplysninger, f.eks. `{"provider":"postmark","token":"..."}`. Postmark,
  Amazon SES, Mailgun, SendGrid og Resend understøttes.
- `QUIRE_SMTP_URL`: `smtp://user:password@host:587`. Kun dette mål; de
  serverløse mål blokerer SMTP.

`QUIRE_MAIL_FROM` er afsenderen. Hvis du vil afprøve Quire, skal du starte profilen `devmail`,
angive `QUIRE_SMTP_URL=smtp://mailpit:1025` og læse e-mail på
`http://localhost:8025`.

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

| Indstilling | 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` | Ekstern søgning; ellers bruges fuldtekstsøgning i Postgres |
| `QUIRE_BREACH_CHECK_PROVIDER=off`, `QUIRE_BREACH_CHECK_URL` | Kontrol af, om adgangskoder er blevet kompromitteret. Som standard aktiv mod `api.pwnedpasswords.com` (kun et hashpræfiks på fem tegn sendes); `off` deaktiverer kontrollen, og URL'en peger på en range-API, du selv driver |

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

`OTEL_EXPORTER_OTLP_ENDPOINT` angiver den collector, som hver proces sender
spor og metrikker til. Med profilen `observability` er den
`http://otelcol:4318`, og `docker/otel-collector.yaml` er stedet, hvor du tilføjer
eksportøren til dit backend. Weblaget, worker, scheduler, content og collab
eksporterer spans via OTLP/HTTP (webforespørgsler, lejerdatabasetransaktioner,
worker-job og udgående kald), når den er angivet, samt metrikker til samme endpoint hvert minut
(`OTEL_METRICS_EXPORTER=none` slår dem fra). `OTEL_TRACES_SAMPLER_ARG` angiver andelen af spor, der bevares. Logfiler sendes til standardoutput på `LOG_LEVEL`, og Compose roterer dem. Spor indeholder aldrig personoplysninger.

### Regional udgående trafik (EU-datalagring) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` betyder, at stacken betjener organisationer i EU. Worker
begrænser derefter alle udgående anmodninger på vegne af en organisation, der er fastlåst til
EU, til en tilladelsesliste (21-compliance.md afsnit 8.1). Listen består af værtsnavnene, som de konfigurerede tjenester angiver for regionen (lagerendepunktet, e-mailudbyderen, en hostet videoudbyder, organisationens egne lagermål, AI-udbydere og e-mailkontoen), værtsnavnene på tjenester under en aktiv undtagelse samt værtsnavnene, du angiver i
`QUIRE_EGRESS_ALLOW_HOSTS`. En anmodning til en anden offentlig vært afvises,
før den sendes; afvisningen skrives til organisationens auditspor som
`privacy/egress_refused` og vises under Overholdelse, Datalagring.

| Indstilling | Værdier | Effekt |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | En kommasepareret liste over værtsnavne eller `*.example.org` for alle underdomæner | Ekstra værter, en EU-organisation må kontakte. Webhook-, xAPI- og SIEM-endpoints, blogfeeds og Amazon SES-værter skal stå her, fordi de vælges af organisationen, og ingen tjeneste erklærer dem. Loopback, private adresser og værtsnavne med kun ét led, såsom `web` eller `clamav`, tilhører dit eget netværk og kontrolleres aldrig |

Organisationer i Storbritannien og USA er ikke begrænset af en værtsliste; kontrollen af tjenesternes regioner gælder fortsat. Angiv listen på worker; administratorsiden læser den på
weblaget for at vise tilladelseslisten, så den skal stå i `docker/.env`, som alle tjenester læser.

Applikationskontrollen giver en tydelig fejl og en auditpost, men det er ikke
garantien: Kode kan være forkert. Garantien ligger i netværket. Compose håndhæver den ikke for dig. I en regional stack skal du placere tjenesterne `worker` og `web` på et netværk med `internal: true`, hvor den eneste udgående rute går via en proxy til udgående trafik (f.eks. Squid eller en tinyproxy-container), der tillader de samme værter som `QUIRE_EGRESS_ALLOW_HOSTS` samt værterne for dine konfigurerede tjenester, og angive `HTTPS_PROXY` for disse tjenester. Datalagringssiden viser præcis de værter, applikationen tillader, så listerne kan sammenlignes.

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

| Endpoint | Betydning |
| --- | --- |
| `/healthz` | Liveness: processen svarer. Compose-sundhedskontroller bruger dette |
| `/readyz` | Klarhed: afhængigheder kan nås, og hver valgfri tjeneste angives som konfigureret eller ej. Peg din load balancer hertil |

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

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

Tjenesten `proxy` (Caddy, Apache-2.0, `docker/caddy/Caddyfile`) indgår i
standardstacken. Den svarer på port 80 og 443 og dirigerer:

| Vært eller sti | Sendes til |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`, alle lejerunderdomæner og tilpassede domæner | `web` |
| `/_collab/` på disse værter | `collab` (websocket, `QUIRE_COLLAB_URL`) |
| `/_realtime/connection/` på disse værter | klientens websocket i `centrifugo`; serverens API offentliggøres aldrig |
| `/_images/` på disse værter | `imgproxy` med profilen `images` (`IMGPROXY_URL`) |

`init-env.sh` udleder `QUIRE_PROXY_APP_HOST`, `QUIRE_PROXY_CONTENT_HOST`,
`QUIRE_PROXY_HTTPS_PORT`, `QUIRE_COLLAB_URL` og `IMGPROXY_URL` fra de to
origins, så de ikke kan komme ud af trit. Redigér dem sammen, hvis du ændrer en
origin manuelt.

Certifikater følger `QUIRE_PROXY_TLS`:

- `internal` (standard): Caddys egen certifikatudsteder til
  `localhost`, `*.localhost` og `lvh.me`. Stol på dens rodcertifikat én gang, og åbn derefter:

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

  Føj `quire-local-ca.crt` til systemets eller browserens certifikatlager. `curl`
  bruger det med `--cacert`.
- En e-mailadresse: automatiske ACME-certifikater (Let's Encrypt og derefter
  ZeroSSL) til rigtige værtsnavne. DNS for begge origins og alle lejerværter
  skal pege hertil, og port 80 og 443 skal være tilgængelige fra internettet.

Certifikater til lejerværter udstedes efter behov ved første besøg, og kun hvis web
bekræfter, at navnet tilhører denne installation (`/tls-allowed`, forespurgt på
Compose-netværket). Intet wildcard-certifikat eller DNS-udbyderplugin er nødvendigt,
og en uvedkommende, der peger et navn på værten, kan ikke få den til at anmode om
certifikater. Certifikater og den lokale certifikatudsteder ligger i
`caddy-data`-volumen; tag backup af den sammen med resten, hvis du bruger `internal`.

Weblaget stoler kun på proxyens `X-Forwarded-For`: Proxyen har en fast adresse
(`QUIRE_PROXY_ADDRESS`, standard `172.29.64.10`) på et fast undernet
(`QUIRE_COMPOSE_SUBNET`), og `QUIRE_TRUSTED_PROXY_CIDRS` angiver den adresse.
Hvis undernettet kolliderer med et netværk på værten, skal du ændre begge dele og køre
`docker compose down` før `up`.

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

Hvis du i stedet vil bruge en load balancer eller proxy, du allerede kører, skal du udelade
`proxy` (`docker compose up -d --scale proxy=0`) og afslutte TLS foran `web`
(8080), `content` (8081), `collab` (1234, websocket) og `centrifugo` (8000,
websocket). Angiv de offentlige adresser i `QUIRE_APP_ORIGIN`,
`QUIRE_CONTENT_ORIGIN` og `QUIRE_COLLAB_URL` (`wss://`) samt proxyens
adresseområde i `QUIRE_TRUSTED_PROXY_CIDRS`.

## Fejlfinding <!--quire:troubleshooting-->

- `init` afsluttes med "QUIRE_DATABASE_ID is not a UUID": angiv værdien med `uuidgen`.
- `web` genstarter med "did not start on compose": loggen viser hver indstilling,
  den ikke kan bruge, og hvad du skal sætte i stedet.
- Ændring af en adgangskode i `.env` efter første opstart gør intet: init-scriptet
  kører kun én gang. Brug `ALTER ROLE`.
- Uploads fejler med en scanningsfejl, mens `CLAMAV_URL` er angivet: ClamAV henter
  signaturer ved første opstart, og det tager nogle minutter.

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