Prywatne wdrożenie zdalne
Ten wzorzec uruchamia Libre WebUI, Ollama i Cloudflare Tunnel na jednym hoście Docker bez publikowania portów aplikacji ani Ollama. Cloudflare Access jest zewnętrzną granicą tożsamości, uwierzytelnianie Libre WebUI — wewnętrzną. Work i Watchtower są osobnymi, równoważnymi rootowi opcjami.
Szablon to topologia solo z jedną repliką: SQLite, lokalne szyfrowane bloby, wbudowane wektory, lokalna koordynacja i worker współdzielą wolumin danych. Nie twórz zespołu przez zmianę selektorów w .env. Wdrożenia team muszą używać docker-compose.team.yml (i docker-compose.team.work.yml dla Work), które razem dostarczają PostgreSQL/PGVector, wersjonowane S3, Redis, zewnętrznego workera i bramę.
Zacznij od deploy/private/docker-compose.yml. Domyślna jest image main:
LIBRE_WEBUI_IMAGE=ghcr.io/libre-webui/libre-webui:main
Tag dev nadaje się do jawnie wybranej instancji programistycznej, nie klienta.
Model bezpieczeństwa
- Cloudflare Access chroni całą nazwę hosta, w tym
/api/*i WebSocket. Nie dodawaj publicznych obejść. - Libre WebUI wymaga bieżącego konta dla API; cykl modeli i Work wymagają roli administratora w bazie.
- Aplikacja, Ollama, SearXNG i cloudflared używają prywatnej sieci Compose; host nie publikuje portów.
- Dołączony SearXNG obsługuje opcjonalne wyszukiwanie, jest tylko wewnętrzny i bezczynny do włączenia w Ustawienia > Wyszukiwanie; ustaw
SEARXNG_SECRETw.envprzed startem. - Aplikacja działa bez roota, z tylko do odczytu rootfs, bez capabilities, z no-new-privileges oraz limitami CPU, pamięci i PID.
- Work jest wyłączony bez nadpisania. Po włączeniu kontenery mają własny tylko-do-odczytu rootfs, usunięte capabilities, limity, wolumin i domyślnie blokowaną sieć.
Stos bazowy nie montuje socketu. docker-compose.work-proxy.yml zachowuje to: proxy na sieci wewnętrznej trzyma socket i przekazuje tylko sekcje używane przez Work (containers, images, volumes, networks, exec, info); swarm, secrets, build i system są blokowane, a aplikacja nie potrzebuje montowania ani grupy. Proxy zmniejsza powierzchnię, nie skutki — tworzący kontenery nadal może bind-mountować hosta. To wzmocnienie, nie izolacja multi-tenant.
Surowe alternatywy pozostają największą granicą zaufania: docker-compose.work.yml i Watchtower dają procesowi dowolne API Docker i kontrolę hosta. Tylko-do-odczytu mount nie czyni API tylko do odczytu. Pomocnik kopii odmawia surowego socketu; migruj na proxy przed harmonogramem kopii.
Uruchomienie początkowe
- Utwórz operatora sudo bez roota i sprawdź SSH kluczem przed wyłączeniem roota.
- Skopiuj
deploy/private/.env.exampledo/opt/libre-webui/.env, ustaw0600, unikatowe sekrety i dopasujBLOB_QUOTA_BYTES_PER_USER.BLOB_QUOTA_RESERVATION_TTL_MSwygasza porzucone rezerwacje; domyślnie godzina. - Dla Work ustaw
DOCKER_GIDna numeryczną grupę/var/run/docker.sock. - Zapisz token tunelu w
/opt/libre-webui/secrets/tunnel-tokenz0640lub ostrzej. - Utwórz aplikację Cloudflare Access dla całej nazwy, sesję 24 godziny i tylko właściwe tożsamości. Włącz Protect with Access. Dla publicznego monitoringu utwórz osobną politykę tylko
/health/live. Nigdy ogólnego Bypass — pasujący Bypass pokonuje Allow. - Zostaw
ENABLE_SIGNUP=false. Po ochronie hosta utwórz pierwszego lokalnego administratora; pusta baza dopuszcza jedno konto bootstrap. Rejestrację włączaj tylko w zamierzonym oknie. - Ogranicz hosty Turnstile i ustaw dokładne
TURNSTILE_EXPECTED_HOSTNAME.
Uruchom i sprawdź:
cd /opt/libre-webui
docker compose config --quiet
docker compose up -d
docker compose ps
Work przez proxy:
docker compose -f docker-compose.yml -f docker-compose.work-proxy.yml up -d
Wariant surowy (docker-compose.work.yml) pozostaje z opisanymi konsekwencjami.
Po aktywacji Access testy CLI wymagają tokenu usługi, chyba że ścieżka ma wąskie obejście. Trzymaj poświadczenia poza historią i wysyłaj oba nagłówki:
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
Nieuwierzytelnione żądanie chronionego API musi zwrócić 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
Wzmacnianie hosta
Katalog zawiera drop-in sshd i jail fail2ban. Przed wdrożeniem sprawdź osobną sesję sudo i sshd -t przed przeładowaniem SSH.
Użyj UFW lub odpowiednika do domyślnego blokowania wejścia i limitowanego SSH. Docker nie publikuje portów:
ufw default deny incoming
ufw default allow outgoing
ufw limit OpenSSH
ufw enable
Zachowaj automatyczne poprawki bezpieczeństwa. Wyłącz przekazywanie X11, agenta i TCP bez udokumentowanej potrzeby.
Kopie zapasowe i odzyskiwanie
Przed kopią uruchom tylko-do-odczytu inwentaryzację w działającym kontenerze. Używa dokładnej wersji, środowiska i woluminu. Polecenie z checkoutu hosta może sprawdzić złą bazę lub inny kod.
docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data
Kod 0 oznacza brak blokad, 1 blokady w JSON, 2 brak wykonania. Raport ma tylko odcisk klucza i flagi obecności sekretów; nigdy wartości. Zachowaj go z kopią, aby porównać wersję, schemat, oczekiwane zasoby Work i wykluczenia.
Utwórz osobne klucze szyfrowania i podpisu dokładną image. Katalog poza woluminem; skopiuj klucz i prywatny podpis do oddzielnego bezpiecznego miejsca:
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
Generowanie odmawia istniejących plików. Nie nadpisuj zestawu: utrata klucza szyfrowania lub tożsamości podpisu unieważnia dowód.
Zainstaluj skrypty i unity systemd, włącz timer:
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
Unit opcjonalnie czyta tylko-konserwacyjne /etc/libre-webui/backup.env, nie .env aplikacji. Utwórz jako root tylko dla nadpisania:
install -d -m 0750 /etc/libre-webui
install -m 0600 /dev/null /etc/libre-webui/backup.env
Można ustawić LIBRE_WEBUI_STACK_DIR, LIBRE_WEBUI_BACKUP_RETENTION_DAYS, LIBRE_WEBUI_CONTAINER_NAME, LIBRE_WEBUI_BACKUP_KEY_DIR. Plik root 0600; niestandardowy katalog kluczy czytelny przez root w sandboxie systemd.
Zmiana LIBRE_WEBUI_BACKUP_DIR zmienia granicę zapisu systemd. Katalog musi istnieć i wymaga drop-in. Po ustawieniu LIBRE_WEBUI_BACKUP_DIR=/srv/backups/libre-webui w backup.env:
install -d -m 0700 /srv/backups/libre-webui
systemctl edit libre-webui-backup.service
Dodaj dokładną ścieżkę i przeładuj:
[Service]
ReadWritePaths=/srv/backups/libre-webui
systemctl daemon-reload
systemctl start libre-webui-backup.service
Bez ReadWritePaths= ProtectSystem=strict prawidłowo blokuje zapis.
Usługa ma do sześciu godzin. Pomocnik blokuje hosta, zatrzymuje aplikację tylko jeśli działała i tworzy archiwum nieaktywnego woluminu dokładną image. Archiwum ma podpisany manifest i szyfrowany ładunek z katalogiem danych, runtime i sekretami. Następnie niezależnie je weryfikuje i atomowo publikuje raport. Kontenery tylko-do-odczytu mają prywatny zapisywalny /tmp tmpfs; jawny tekst nie pozostaje w warstwie. Kopiuj oba pliki i klucze poza hosta.
Przy docker-compose.work-proxy.yml odzyskiwanie dowodzi istnienia każdego woluminu Work. Pomocnik czyta DOCKER_HOST, znajduje proxy w tym samym aktywnym projekcie i wykrywa jedną wspólną sieć z rzeczywistych przyłączeń. Compose prefiksuje ją nazwą projektu, więc nie zgaduj. Tylko kontener tworzenia archiwum dołącza i nie dostaje surowego socketu; weryfikacja używa --network none. Brak proxy, zły punkt, zewnętrzna/niejednoznaczna sieć lub surowy mount kończy się przed zatrzymaniem i publikacją.
Testuj odzyskanie do nowego woluminu:
LIBRE_WEBUI_RESTORE_IMAGE="$image_ref" \
libre-webui-restore \
/var/backups/libre-webui/libre-webui-integrated-YYYYMMDDTHHMMSSZ.lwb \
libre-webui-restore-drill
Pomocnik odmawia istniejącego celu, weryfikuje w pamięci jednorazowej, kopiuje dane i zapisuje runtime.json i secrets.json prywatnie. Nigdy nie przełącza ani nie uruchamia aktywnego stosu. Sprawdź konfigurację, świadomie zmień wartości wdrożenia i testuj izolowany stos.
Modele Ollama można pobrać ponownie. Woluminy Docker Work, PVC Kubernetes i foldery hosta są poza katalogiem danych i wymagają własnych skoordynowanych snapshotów i retencji.
Aktualizacje
Libre WebUI jest stanowe nawet przy zmiennym tagu. Compose trwale wyklucza aplikację z Watchtower. Aktualizuj tylko jako skoordynowane działanie:
- Zapisz ID działającej image i wybierz sprawdzony niezmienny digest.
- Uruchom
libre-webui recovery-check, usługę kopii i wymagaj nowego archiwum z raportem. - Ustaw
LIBRE_WEBUI_IMAGEna digest, pobierz i odtwórz tylkolibre-webui. Nie usuwaj woluminu. - Wymagaj
/health/ready, logowania, sesji/historii, dokumentów i testów Work. Przy błędzie wróć do digestu i zachowaj stan z kopią.
Sekwencja hosta jest ręczna. Zmień digest po przeglądzie i sprawdź najnowszą parę .lwb/.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}}'
Opcjonalne Watchtower z socketem tylko dla oznaczonych sidecarów:
docker compose \
-f docker-compose.yml \
-f docker-compose.watchtower.yml \
up -d
Watchtower sprawdza Ollama i SearXNG co 30 minut. Dane Ollama pozostają w woluminie, konfiguracja SearXNG w bind mount. Nie aktualizuje Libre WebUI, cloudflared, proxy Work ani sandboxów. Klient śledzi main, eksperyment może :dev, ale nadal wymaga ręcznej aktualizacji po kopii. Nigdy nie łącz prywatnego solo z usługami trwałości team; wdrażaj pełną topologię.