Přeskočit na hlavní obsah

Soukromá vzdálená instalace

Tento vzor provozuje Libre WebUI, Ollama a Cloudflare Tunnel na jednom hostiteli Docker, aniž zveřejní porty aplikace nebo Ollama. Cloudflare Access tvoří vnější hranici identity, ověřování Libre WebUI vnitřní. Work a Watchtower jsou samostatné volitelné funkce s oprávněním ekvivalentním rootu.

Šablona používá topologii solo s jedinou replikou: SQLite, místní šifrované bloby, vestavěné vektory, místní koordinace a vestavěný worker sdílejí datový svazek aplikace. Nedělejte z ní týmovou instalaci změnou backendů v .env. Tým musí použít docker-compose.team.yml (a docker-compose.team.work.yml se zapnutým Work), které společně zřídí PostgreSQL/PGVector, verzované S3, Redis, externí worker a bránu.

Začněte souborem deploy/private/docker-compose.yml. Ve výchozím nastavení používá image main:

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

Tag dev patří výslovně zvolené vývojové instanci, ne klientské výchozí hodnotě.

Model zabezpečení

  • Cloudflare Access chrání celý název hostitele včetně /api/* a upgradu WebSocket. Nepřidávejte veřejné obcházející cesty.
  • Libre WebUI vyžaduje aktuální účet pro API. Operace životního cyklu modelů a Work vyžadují aktuální roli správce v databázi.
  • Aplikace, Ollama, SearXNG a cloudflared používají pouze soukromou síť Compose. Hostitel nepublikuje žádné aplikační porty.
  • Vestavěná SearXNG poskytuje volitelné vyhledávání. Je pouze interní a neaktivní, dokud správce hledání nezapne v Settings > Search. Před spuštěním nastavte SEARXNG_SECRET v .env.
  • Aplikace běží bez rootu, se souborovým systémem kořene jen pro čtení, bez capability Linuxu, s no-new-privileges a limity CPU, paměti a PID.
  • Work je vypnuté bez zahrnutí některého přepsání. Po zapnutí mají jeho kontejnery vlastní kořen jen pro čtení, odebrané capability, limity, svazek a výchozí zákaz sítě.

Základní stack nepřipojuje socket Docker. Při zapnutí Work přes docker-compose.work-proxy.yml to platí dál: socket drží proxy v interní síti a přeposílá jen části API, které Work používá (containers, images, volumes, networks, exec, info). Swarm, secrets, build a system proxy odmítá a aplikace nepotřebuje socket ani členství v jeho skupině. Proxy zmenšuje plochu Docker API, ne dopad povolených operací — kdo může vytvářet kontejnery, může připojit cesty hostitele. Berte ji jako skutečné zpevnění, ne izolaci více nájemců.

Alternativy se surovým socketem zůstávají největší hranicí důvěry: docker-compose.work.yml a přepsání Watchtower dávají kontejneru proces s libovolnými voláními Docker API a kontrolou hostitele. Připojení socketu jen pro čtení nedělá API jen pro čtení. Integrovaná záloha odmítá surový socket; před plánovanými zálohami přesuňte Work na filtrovanou proxy.

Počáteční nastavení

  1. Vytvořte operátora sudo bez rootu a ověřte přihlášení SSH klíčem před vypnutím root SSH.
  2. Zkopírujte deploy/private/.env.example do /opt/libre-webui/.env, nastavte režim 0600, vytvořte jedinečná tajemství a zvolte BLOB_QUOTA_BYTES_PER_USER pro hostitele. BLOB_QUOTA_RESERVATION_TTL_MS ukončuje opuštěné rezervace; výchozí je hodina.
  3. Při zapnutí Work nastavte DOCKER_GID na číselnou skupinu vlastnící /var/run/docker.sock.
  4. Uložte token tunelu do /opt/libre-webui/secrets/tunnel-token s režimem 0640 nebo přísnějším.
  5. Vytvořte self-hosted aplikaci Cloudflare Access pro celý název, použijte relaci 24 hodin a povolte jen zamýšlené identity. Na trase tunelu zapněte Protect with Access. Pro veřejnou kontrolu zdraví vytvořte samostatnou zásadu jen pro /health/live. Nikdy nedávejte hlavní aplikaci obecný Bypass, který by porazil Allow.
  6. Zachovejte ENABLE_SIGNUP=false. Jakmile seznam Access chrání název, vytvořte prvního místního správce; prázdná databáze dovolí tento jediný bootstrap účet. Registraci zapněte jen v úmyslném pozdějším okně.
  7. Nastavte omezení hostitele Turnstile a TURNSTILE_EXPECTED_HOSTNAME na přesný veřejný název.

Spuštění a ověření:

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

Pro Work záměrně zahrňte přepsání socket proxy:

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

Varianta se surovým socketem (docker-compose.work.yml) zůstává dostupná pro instalace, které ji potřebují, s výše popsanými důsledky.

Po aktivaci Access potřebují testy příkazového řádku token služby, pokud přesná cesta nemá úzkou výjimku. Údaje držte mimo historii shellu a odešlete obě hlavičky:

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

Neověřený požadavek chráněného API musí vrátit 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

Zpevnění hostitele

Adresář obsahuje doplněk sshd a jail fail2ban. Před použitím doplňku ověřte v jiném terminálu samostatnou relaci sudo bez rootu. Před novým načtením SSH otestujte sshd -t.

Pomocí UFW nebo obdobného firewallu výchozím způsobem zakažte příchozí provoz a povolte jen omezené SSH. Docker v této šabloně nepublikuje porty:

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

Nechte zapnuté automatické bezpečnostní aktualizace. Vypněte přeposílání X11, agenta a TCP, pokud instalace nemá zdokumentovanou potřebu.

Zálohy a obnovení

Před zálohou spusťte inventuru připravenosti jen pro čtení v běžícím kontejneru. Použije přesnou nasazenou verzi, prostředí a svazek. Příkaz z checkoutu hostitele by mohl kontrolovat jinou databázi nebo kód než nasazený image.

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

Stav 0 znamená bez blokátorů, 1 blokátory v JSON a 2 nemožnost spuštění. Zpráva obsahuje jen otisk šifrovacího klíče a příznaky přítomnosti tajemství, nikdy hodnoty. Uchovávejte ji se zálohou pro porovnání verze, schématu, prostředků Work a výjimek.

Vytvořte vyhrazené šifrovací a podpisové klíče přesným nasazeným imagem. Adresář držte mimo aplikační svazek a klíče zkopírujte do samostatného chráněného místa obnovy:

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

Generování odmítne existující výstupy. Nikdy nevytvářejte nové klíče přes existující sadu; ztráta šifrovacího nebo podpisového klíče znehodnotí důkaz obnovy.

Nainstalujte skripty a jednotky systemd a zapněte časovač:

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

Jednotka může číst údržbová přepsání z /etc/libre-webui/backup.env, nenačítá aplikační .env. Soubor vytvořte jako root jen při potřebě přepsání:

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

Lze v něm nastavit LIBRE_WEBUI_STACK_DIR, LIBRE_WEBUI_BACKUP_RETENTION_DAYS, LIBRE_WEBUI_CONTAINER_NAME, LIBRE_WEBUI_BACKUP_KEY_DIR. Zachovejte vlastníka root a režim 0600; vlastní adresář klíčů musí být čitelný v sandboxu systemd.

Změna LIBRE_WEBUI_BACKUP_DIR mění hranici zápisu systemd. Adresář musí před spuštěním existovat a jednotka potřebuje odpovídající doplněk. Po nastavení LIBRE_WEBUI_BACKUP_DIR=/srv/backups/libre-webui v backup.env:

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

Do editoru přidejte přesnou cestu a načtěte jednotku:

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

Bez ReadWritePaths= ProtectSystem=strict správně brání zápisu na vlastní místo.

Služba dovoluje u velkých archivů šest hodin. Pomocník získá zámek hostitele, zastaví aplikaci jen pokud běžela a vytvoří archiv z klidového svazku přesným imagem. Archiv má podepsaný manifest a operátorem šifrovaný obsah; zahrnuje data i konfiguraci potřebnou k otevření. Poté nezávisle ověří celý archiv a atomicky zveřejní metadata. Kontejnery údržby jen pro čtení dostanou soukromý zapisovatelný /tmp tmpfs pro SQLite a ověření, žádný otevřený text se neuloží ve vrstvě. Oba soubory a klíče kopírujte mimo hostitele.

Když Work používá docker-compose.work-proxy.yml, musí obnova také prokázat existenci všech svazků Work z databáze. Pomocník přečte DOCKER_HOST, najde službu proxy ve stejném živém projektu Compose a zjistí jejich jedinou sdílenou interní síť ze skutečných připojení Docker. Compose přidává předponu projektu, proto název nehádejte. Jen kontejner vytvářející archiv se připojí k síti a dosáhne filtrovanou proxy; surový socket nedostane. Nezávislé ověření pokračuje s --network none. Chybějící proxy, neočekávaný bod, externí či nejednoznačná síť nebo surový socket selžou před zastavením aplikace a publikací.

Obnovu otestujte do nového svazku bez nahrazení živého:

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

Pomocník odmítne existující svazek či cíl, ověří archiv a inventuru v dočasném úložišti, zkopíruje data a zapíše runtime.json a secrets.json se soukromými oprávněními. Nikdy nepřepojí ani nespustí živý stack. Zkontrolujte konfiguraci, vědomě změňte hodnoty instalace a otestujte obnovený svazek v izolovaném stacku.

Modely Ollama lze stáhnout znovu. Svazky Docker Work, PVC Kubernetes a složky hostitele jsou mimo datový adresář a vyžadují vlastní koordinované snímky a dobu uchování.

Aktualizace

Libre WebUI je stavové i s proměnlivým tagem image. Základní Compose aplikaci trvale vylučuje z Watchtower. Upgradujte jen jako koordinovanou akci:

  1. Zaznamenejte ID běžícího image a přeložte prověřenou náhradu na neměnný digest.
  2. Spusťte libre-webui recovery-check, zálohovací službu a před pokračováním vyžadujte nový ověřený archiv.
  3. Nastavte LIBRE_WEBUI_IMAGE na digest, stáhněte a obnovte pouze libre-webui. Neodstraňujte ani nevytvářejte datový svazek.
  4. Vyžadujte úspěch /health/ready, přihlášení, relace, historie, dokumentů a testu Work. Jinak vraťte zaznamenaný digest a zachovejte selhaný stav i zálohu pro diagnostiku.

Posloupnost na hostiteli je záměrně ruční. Digest nahraďte až po kontrole a před stažením zkontrolujte nejnovější pár .lwb a .json:

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}}'

Volitelné přepsání Watchtower se socketem zůstává jen pro výslovně označené sidecary:

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

Watchtower kontroluje Ollama a SearXNG každých 30 minut. Data Ollama zůstávají ve svazku, konfigurace SearXNG v bind mountu. Neaktualizuje Libre WebUI, cloudflared, socket proxy Work ani sandboxy. Klientská instalace sleduje main; experiment může zvolit :dev, ale stále vyžaduje ruční upgrade podmíněný zálohou. Tento soukromý solo stack nikdy nepřipojujte k týmovým službám perzistence; nasazujte úplnou týmovou topologii.