Hoppa till huvudinnehåll

Privat fjärrdistribution

Det här mönstret kör Libre WebUI, Ollama och Cloudflare Tunnel på en Docker-värd utan att publicera programmets eller Ollamas portar. Cloudflare Access är den yttre identitetsgränsen och Libre WebUI-autentisering den inre. Work och Watchtower är separata, frivilliga funktioner med root-likvärdig behörighet.

Mallen använder solo-topologin med en replik: SQLite, lokala krypterade blobbar, inbäddade vektorer, lokal samordning och en inbäddad jobbworker delar programmets datavolym. Gör inte om den till en teaminstallation genom att ändra backendväljare i .env. Teaminstallationer måste använda arkivets docker-compose.team.yml (och docker-compose.team.work.yml när Work är aktiverat), som etablerar PostgreSQL/PGVector, versionshanterad S3-lagring, Redis, en extern worker och gatewayen som en samordnad topologi.

Använd deploy/private/docker-compose.yml som utgångspunkt. Den använder avbildningen main som standard:

LIBRE_WEBUI_IMAGE=ghcr.io/libre-webui/libre-webui:main

Taggen dev passar en utvecklingsinstans som uttryckligen valts, inte klientens standard.

Säkerhetsmodell

  • Cloudflare Access skyddar hela värdnamnet, inklusive /api/* och WebSocket-uppgraderingar. Lägg inte till publika undantagssökvägar.
  • Libre WebUI kräver ett aktuellt konto för programmets API:er. Modelllivscykel och Work-åtgärder kräver att den aktuella databasrollen är administratör.
  • Programmet, Ollama, SearXNG och cloudflared använder endast ett privat Compose-nätverk. Värden publicerar inga programportar.
  • Den medföljande SearXNG-tjänsten driver valfri webbsökning. Den är endast intern och inaktiv tills en administratör aktiverar sökning i Settings > Search. Ange SEARXNG_SECRET i .env innan stacken startas.
  • Appen körs utan root med skrivskyddat rotfilsystem, utan Linux-funktioner, med no-new-privileges och gränser för CPU, minne och PID.
  • Work är inaktiverat om ingen av dess åsidosättningar inkluderas. När det aktiveras får containrarna ett eget skrivskyddat rotfilsystem, borttagna funktioner, resursgränser, arbetsytevolym och en nätverkspolicy som nekar som standard.

Basstacken monterar ingen Docker-socket. Om Work aktiveras med docker-compose.work-proxy.yml förblir det så: en socketproxy på ett internt nätverk håller socketen och vidarebefordrar endast de API-delar som Work använder (containrar, avbildningar, volymer, nätverk, exec och info). Swarm-, secrets-, build- och systemslutpunkter nekas i proxyn, och programmet behöver varken socketmontering eller medlemskap i socketgruppen. Proxyn minskar Docker API-ytan, inte verkansradien för det som vidarebefordras — den som kan skapa containrar kan fortfarande bind-montera värdsökvägar. Behandla den som ett verkligt härdningslager, inte fleranvändarisolering.

Alternativen med rå socket förblir den största tillitsgränsen: åsidosättningarna docker-compose.work.yml och Watchtower ger en container en process som kan göra godtyckliga Docker API-anrop och styra värden. En skrivskyddad socketmontering gör inte Docker API-åtkomst skrivskyddad. Den integrerade säkerhetskopieringshjälpen vägrar att ärva en rå Docker-socket. Migrera Work till den filtrerade proxyn innan schemalagda integrerade säkerhetskopior används.

Grundkonfiguration

  1. Skapa en operatör utan root med sudo och verifiera nyckelbaserad SSH-inloggning innan root-SSH inaktiveras.
  2. Kopiera deploy/private/.env.example till /opt/libre-webui/.env, ställ in läget 0600, generera unika hemligheter och dimensionera BLOB_QUOTA_BYTES_PER_USER för värden. BLOB_QUOTA_RESERVATION_TTL_MS låter övergivna uppladdningsreservationer löpa ut; standardvärdet är en timme.
  3. Om Work ska aktiveras ställer du DOCKER_GID till den numeriska grupp som äger /var/run/docker.sock.
  4. Lagra Cloudflare-tunneltoken i /opt/libre-webui/secrets/tunnel-token med läget 0640 eller striktare.
  5. Skapa ett självhostat Cloudflare Access-program för hela värdnamnet, använd en 24-timmarssession och tillåt endast avsedda identiteter. Aktivera Protect with Access på tunnelrutten. Om övervakning kräver en publik hälsokontroll skapar du ett separat, sökvägsavgränsat program eller policy endast för /health/live. Lägg aldrig till en generell Bypass-policy i huvudprogrammet: matchande Bypass-policyer upphäver Allow-policyn.
  6. Låt ENABLE_SIGNUP=false. När Access-tillåtelselistan skyddar värdnamnet skapar du den första lokala administratören. En tom databas tillåter automatiskt detta enda bootstrap-konto. Aktivera registrering endast under ett avsiktligt senare tidsfönster.
  7. Konfigurera Turnstile-begränsningar för värdnamn och ställ TURNSTILE_EXPECTED_HOSTNAME till exakt det publika värdnamnet.

Starta och verifiera:

cd /opt/libre-webui
docker compose config --quiet
docker compose up -d
docker compose ps

För att aktivera Work inkluderar du medvetet åsidosättningen för socketproxyn:

docker compose -f docker-compose.yml -f docker-compose.work-proxy.yml up -d

Varianten med rå socket (docker-compose.work.yml) finns kvar för installationer som behöver den, med tillitskonsekvenserna ovan.

När Access är aktivt behöver kommandoradstester en Cloudflare Access-tjänstetoken om inte den exakta sökvägen har ett smalt undantag. Lagra uppgifterna utanför skalhistoriken och skicka båda rubrikerna:

curl --fail --silent --show-error \
-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
https://your-hostname.example/api/auth/system-info

En oautentiserad förfrågan till ett skyddat program-API måste returnera 401:

curl --output /dev/null --write-out '%{http_code}\n' \
-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
https://your-hostname.example/api/work/tasks

Härda värden

Katalogen innehåller ett sshd-tillägg och ett fail2ban-fängelse. Innan sshd-tillägget tillämpas ska du verifiera en separat sudo-session utan root i en annan terminal. Testa konfigurationen med sshd -t innan SSH läses in igen.

Använd UFW (eller en motsvarande brandvägg) för att neka inkommande trafik som standard och endast tillåta hastighetsbegränsad SSH. Docker publicerar inga tjänsteportar i mallen:

ufw default deny incoming
ufw default allow outgoing
ufw limit OpenSSH
ufw enable

Behåll obevakade säkerhetsuppdateringar aktiverade. Inaktivera vidarebefordran av X11, agent och TCP om installationen inte har ett dokumenterat behov av dem.

Säkerhetskopiering och återställning

Kör den skrivskyddade återställningsinventeringen i den aktiva distributionscontainern före säkerhetskopiering. Då används exakt den distribuerade programversionen, miljön och monterade datavolymen. Ett kommando från en utcheckning på värden kan granska fel databas eller köra källkod som skiljer sig från den distribuerade avbildningen.

docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data

Slutstatus 0 betyder att inga hinder för återställningsberedskap hittades, 1 att JSON-rapporten innehåller hinder och 2 att kommandot inte kunde köras. Rapporten innehåller endast ett fingeravtryck för krypteringsnyckeln och flaggor om hemligheter. Den skriver aldrig ut en nyckel eller annat hemligt värde. Behåll inventeringen med motsvarande säkerhetskopia så att operatörer kan jämföra programversion, schemafingeravtryck, förväntade Work-resurser och undantag före återställning.

Skapa särskilda krypterings- och signeringsnycklar för säkerhetskopiering med exakt den distribuerade avbildningen. Håll katalogen utanför programvolymen och kopiera krypteringsnyckeln och den privata signeringsnyckeln till en separat skyddad återställningsplats:

install -d -m 0700 /etc/libre-webui/backup-keys
image_ref=$(docker inspect libre-webui --format '{{.Image}}')
docker run --rm --user 0:0 --read-only --network none --cap-drop ALL \
--security-opt no-new-privileges \
--mount type=bind,src=/etc/libre-webui/backup-keys,dst=/backup-keys \
--entrypoint /usr/local/bin/libre-webui "$image_ref" \
backup keygen \
--directory /backup-keys

Nyckelgenereringen vägrar att skriva över befintliga utdatafiler. Generera aldrig nya nycklar över en befintlig säkerhetskopieuppsättning. Om arkivets krypteringsnyckel eller signeringsidentitet förloras blir motsvarande återställningsbevis oanvändbart.

Installera de medföljande skripten och systemd-enheterna för säkerhetskopiering och återställning och aktivera sedan timern:

install -d -m 0700 /var/backups/libre-webui
install -m 0750 deploy/private/libre-webui-backup \
/usr/local/sbin/libre-webui-backup
install -m 0750 deploy/private/libre-webui-restore \
/usr/local/sbin/libre-webui-restore
install -m 0644 deploy/private/libre-webui-backup.{service,timer} \
/etc/systemd/system/
systemctl daemon-reload
systemctl enable --now libre-webui-backup.timer

Enheten kan läsa underhållsspecifika åsidosättningar från /etc/libre-webui/backup.env. Den läser inte programmets .env. Skapa endast filen som root när ett åsidosättande behövs:

install -d -m 0750 /etc/libre-webui
install -m 0600 /dev/null /etc/libre-webui/backup.env

LIBRE_WEBUI_STACK_DIR, LIBRE_WEBUI_BACKUP_RETENTION_DAYS, LIBRE_WEBUI_CONTAINER_NAME och LIBRE_WEBUI_BACKUP_KEY_DIR kan anges direkt där. Behåll root som ägare och läget 0600. En anpassad nyckelkatalog måste förbli läsbar för root i systemd-sandlådan.

Om LIBRE_WEBUI_BACKUP_DIR ändras, ändras också systemd:s skrivgräns. Katalogen måste finnas innan tjänsten startar och enheten behöver ett motsvarande tillägg. Efter att LIBRE_WEBUI_BACKUP_DIR=/srv/backups/libre-webui har angetts i backup.env:

install -d -m 0700 /srv/backups/libre-webui
systemctl edit libre-webui-backup.service

Lägg till exakt denna sökväg i redigeraren och läs sedan in enheten igen:

[Service]
ReadWritePaths=/srv/backups/libre-webui
systemctl daemon-reload
systemctl start libre-webui-backup.service

Utan motsvarande ReadWritePaths=-post förhindrar ProtectSystem=strict korrekt att timern skriver till en anpassad plats.

Säkerhetskopieringstjänsten tillåter upp till sex timmar för stora arkiv. Hjälpen tar ett lås på värden, stoppar endast programmet om det redan kördes och skapar arkivet från den vilande volymen med exakt den distribuerade avbildningen. Arkivet har ett signerat manifest och en operatörskrypterad nyttolast. Det innehåller datakatalogen samt den körtids- och hemlighetskonfiguration som krävs för att öppna tillståndet. Hjälpen verifierar därefter hela arkivet oberoende innan metadatarapporten publiceras atomärt. Dess skrivskyddade underhållscontainrar får en privat skrivbar /tmp tmpfs för SQLite-granskning och autentiserad arkivverifiering. Ingen tillfällig klartext lagras i containerlagret. Kopiera båda filerna och de separat skyddade återställningsnycklarna utanför värden.

När Work använder docker-compose.work-proxy.yml måste återställning också bevisa att varje Work-volym som databasen refererar till finns kvar. Hjälpen läser det distribuerade programmets DOCKER_HOST, hittar socketproxytjänsten i samma aktiva Compose-projekt och upptäcker deras enda gemensamma interna nätverk från Dockers faktiska nätverksanslutningar. Compose lägger till projektnamnet före nätverksnamnet, så konfigurera eller hårdkoda inte ett gissat namn. Endast containern som skapar arkivet ansluter till det interna nätverket och kan nå den filtrerade proxyn; den får ingen rå socket. Oberoende arkivverifiering fortsätter med --network none. En saknad proxy, oväntad slutpunkt, ett externt eller tvetydigt gemensamt nätverk eller en rå socketmontering orsakar fel innan programmet stoppas och innan ett arkiv publiceras.

Testa återställning till en ny volym utan att ersätta den aktiva volymen:

LIBRE_WEBUI_RESTORE_IMAGE="$image_ref" \
libre-webui-restore \
/var/backups/libre-webui/libre-webui-integrated-YYYYMMDDTHHMMSSZ.lwb \
libre-webui-restore-drill

Återställningshjälpen vägrar en befintlig volym eller ett konfigurationsmål, verifierar arkivet och dess interna återställningsinventering i tillfällig lagring och kopierar sedan data till den nya volymen samt skriver återställda runtime.json och secrets.json med privata behörigheter. Den kopplar aldrig om eller startar den aktiva stacken. Granska den återställda konfigurationen, uppdatera distributionsspecifika värden medvetet och testa den återställda volymen med en isolerad stack.

Ollama-modeller kan hämtas igen. Docker Work-volymer, Kubernetes Work-PVC:er och värdbundna Work-mappar ligger utanför programmets datakatalog och kräver egna samordnade ögonblicksbilder och lagringspolicyer.

Uppdateringar

Libre WebUI är tillståndsbevarande även när avbildningstaggen är föränderlig. Basfilen för Compose märker permanent programmet som undantaget från Watchtower. Uppgradera endast som en samordnad operatörsåtgärd:

  1. Registrera ID:t för den aktiva avbildningen och lös den granskade ersättaren till en oföränderlig digest.
  2. Kör libre-webui recovery-check, starta säkerhetskopieringstjänsten och kräv ett nyskapat arkiv och en verifieringsrapport innan du fortsätter.
  3. Ställ LIBRE_WEBUI_IMAGE till den granskade digesten, hämta den och återskapa endast libre-webui med Docker Compose. Ta inte bort eller återskapa dess datavolym.
  4. Kräv att /health/ready, inloggning, session/historik, dokumenthämtning och Work-tester godkänns. Återgå till den registrerade avbildningsdigesten om de misslyckas och bevara både det misslyckade tillståndet och den verifierade säkerhetskopian för diagnos.

Sekvensen på värdsidan är avsiktligt manuell. Ersätt digesten först efter granskning och kontrollera det senaste paret .lwb och .json före hämtning:

docker inspect libre-webui --format '{{.Config.Image}} {{.Image}}'
docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data
systemctl start libre-webui-backup.service
systemctl --no-pager --full status libre-webui-backup.service
ls -lt /var/backups/libre-webui/libre-webui-integrated-* | head

# Set LIBRE_WEBUI_IMAGE=ghcr.io/libre-webui/libre-webui@sha256:REVIEWED_DIGEST
# in the root-owned .env, then recreate only the application.
docker compose pull libre-webui
docker compose up -d --no-deps libre-webui
docker inspect libre-webui --format '{{.State.Health.Status}} {{.Image}}'

Den valfria socketbärande Watchtower-åsidosättningen finns kvar endast för de sidecars som uttryckligen märkts i basfilen:

docker compose \
-f docker-compose.yml \
-f docker-compose.watchtower.yml \
up -d

Watchtower kontrollerar Ollama och SearXNG var 30:e minut. Ollama-modelldata ligger kvar i den namngivna volymen och SearXNG-konfigurationen i sin bind-montering. Den uppdaterar inte Libre WebUI, cloudflared, Work-socketproxyn eller Work-sandlådor. En klientinstallation följer main. En experimentell instans kan välja :dev, men programmet kräver fortfarande samma säkerhetskopieringsspärrade manuella uppgradering. Anslut aldrig denna privata solo-stack till teambeständighetstjänster. Distribuera hela teamtopologin i stället.