Μετάβαση στο κύριο περιεχόμενο

Ιδιωτική απομακρυσμένη εγκατάσταση

Το μοτίβο εκτελεί Libre WebUI, Ollama και Cloudflare Tunnel σε έναν Docker host χωρίς δημοσίευση ports. Το Cloudflare Access είναι εξωτερικό identity boundary και το auth Libre εσωτερικό. Work και Watchtower είναι ξεχωριστά root-equivalent opt-ins.

Είναι solo μίας replica: SQLite, τοπικά encrypted blobs, embedded vectors, local coordination και embedded worker μοιράζονται data volume. Μην το μετατρέψετε σε team αλλάζοντας selectors στο .env. Team απαιτεί docker-compose.team.yml και docker-compose.team.work.yml, που παρέχουν PostgreSQL/PGVector, versioned S3, Redis, external worker και gateway ως μία τοπολογία.

Ξεκινήστε από deploy/private/docker-compose.yml, με default image main:

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

Το dev είναι για ρητό development opt-in, όχι client default.

Μοντέλο ασφάλειας

  • Cloudflare Access προστατεύει όλο το hostname, /api/* και WebSocket upgrades. Χωρίς public bypass.
  • Τα API απαιτούν current account, model lifecycle και Work απαιτούν admin database role.
  • App, Ollama, SearXNG, cloudflared χρησιμοποιούν private Compose network χωρίς published ports.
  • Το SearXNG παρέχει προαιρετικό web search, internal και ανενεργό μέχρι ενεργοποίηση admin. Ορίστε SEARXNG_SECRET στο .env.
  • Η app τρέχει non-root, read-only rootfs, χωρίς capabilities, no-new-privileges και limits.
  • Work είναι off χωρίς override. Όταν on, containers έχουν δικό τους read-only root, dropped capabilities, limits, volume και default-deny network.

Η base stack δεν mountάρει Docker socket. Με docker-compose.work-proxy.yml, filtered proxy σε internal network κρατά socket και επιτρέπει μόνο containers, images, volumes, networks, exec, info. Swarm, secrets, build, system απαγορεύονται και app δεν χρειάζεται socket/group. Η proxy μειώνει API surface, όχι blast radius: δημιουργός container μπορεί να bind-mount host paths. Είναι hardening, όχι multi-tenant isolation.

Τα raw-socket docker-compose.work.yml και Watchtower δίνουν arbitrary Docker API και έλεγχο host. Read-only mount δεν κάνει το API read-only. Ο backup helper αρνείται raw socket· μεταφέρετε Work στη filtered proxy πριν scheduled integrated backups.

Bootstrap

  1. Δημιουργήστε non-root sudo operator και επιβεβαιώστε SSH key login πριν απενεργοποιήσετε root SSH.
  2. Αντιγράψτε deploy/private/.env.example σε /opt/libre-webui/.env, mode 0600, δημιουργήστε secrets και ορίστε BLOB_QUOTA_BYTES_PER_USER. Το BLOB_QUOTA_RESERVATION_TTL_MS λήγει εγκαταλειμμένες reservations, default μία ώρα.
  3. Για Work, ορίστε DOCKER_GID στην αριθμητική ομάδα /var/run/docker.sock.
  4. Αποθηκεύστε tunnel token σε /opt/libre-webui/secrets/tunnel-token mode 0640 ή αυστηρότερο.
  5. Δημιουργήστε Cloudflare Access app για πλήρες hostname, session 24 ώρες και μόνο επιθυμητές identities. Enable Protect with Access. Για public health, ξεχωριστή path policy μόνο /health/live. Ποτέ blanket Bypass στην κύρια app.
  6. Κρατήστε ENABLE_SIGNUP=false. Με προστατευμένο hostname δημιουργήστε πρώτο local admin· κενή βάση επιτρέπει αυτό το bootstrap account. Registration μόνο σε σκόπιμο παράθυρο.
  7. Ρυθμίστε Turnstile hostname και TURNSTILE_EXPECTED_HOSTNAME ακριβώς.

Έναρξη:

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

Work με proxy:

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

Το raw docker-compose.work.yml παραμένει με τις συνέπειες εμπιστοσύνης.

Με Access, CLI tests χρειάζονται service token εκτός shell history και δύο headers:

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

Μη πιστοποιημένο protected API πρέπει 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

Σκλήρυνση host

Υπάρχουν sshd drop-in και fail2ban jail. Πριν εφαρμογή, επιβεβαιώστε άλλη sudo συνεδρία και sshd -t πριν reload. Με UFW default deny inbound και rate-limited SSH:

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

Κρατήστε unattended security upgrades. Απενεργοποιήστε X11, agent και TCP forwarding εκτός τεκμηριωμένης ανάγκης.

Backup και επαναφορά

Πριν backup, εκτελέστε read-only recovery inventory μέσα στο running deployment container, ώστε να χρησιμοποιεί ακριβή έκδοση, env και volume. Host checkout μπορεί να δει λάθος βάση ή διαφορετικό source.

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

Exit 0 χωρίς blockers, 1 blockers στο JSON, 2 αδυναμία εκτέλεσης. Η αναφορά έχει μόνο fingerprint key και secret-presence flags, ποτέ values. Κρατήστε την με backup για version, schema, Work resources και exclusions.

Δημιουργήστε dedicated encryption/signing keys με το ακριβές image, εκτός application volume, και αντιγράψτε τα σε ξεχωριστή protected recovery θέση:

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

Η δημιουργία αρνείται υπάρχοντα outputs. Μην αντικαταστήσετε keys: απώλεια encryption ή signing identity ακυρώνει recovery proof.

Εγκαταστήστε scripts/systemd και 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 προαιρετικά διαβάζει /etc/libre-webui/backup.env, όχι application .env:

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, LIBRE_WEBUI_BACKUP_KEY_DIR. Owner root, mode 0600.

Αλλαγή LIBRE_WEBUI_BACKUP_DIR αλλάζει systemd write boundary. Ο κατάλογος πρέπει να υπάρχει και χρειάζεται matching drop-in. Αφού ορίσετε LIBRE_WEBUI_BACKUP_DIR=/srv/backups/libre-webui στο backup.env:

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

Προσθέστε:

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

Χωρίς ReadWritePaths=, το ProtectSystem=strict σωστά εμποδίζει custom write.

Η υπηρεσία επιτρέπει έξι ώρες. Ο helper αποκτά host lock, σταματά app μόνο αν έτρεχε και δημιουργεί archive από quiesced volume με exact image. Περιέχει signed manifest και operator-encrypted payload με data, runtime και secrets. Επαληθεύει ανεξάρτητα πριν atomic metadata. Read-only maintenance containers έχουν private writable /tmp tmpfs χωρίς persisted plaintext. Αντιγράψτε αρχεία και keys off-host.

Με docker-compose.work-proxy.yml, recovery πρέπει να αποδείξει όλα τα referenced Work volumes. Διαβάζει DOCKER_HOST, βρίσκει proxy στο ίδιο live Compose project και το μοναδικό κοινό internal network από actual attachments. Επειδή Compose βάζει prefix, μη hardcodeάρετε όνομα. Μόνο archive container συνδέεται στη filtered proxy χωρίς raw socket· verification μένει --network none. Missing proxy, unexpected endpoint, external/ambiguous network ή raw socket αποτυγχάνει πριν stop/publish.

Δοκιμή σε νέο volume:

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

Ο restore helper αρνείται existing volume/config target, επαληθεύει archive/inventory σε disposable storage, αντιγράφει data και γράφει runtime.json/secrets.json με private permissions. Δεν επανασυνδέει ούτε εκκινεί live stack. Ελέγξτε config και δοκιμάστε isolated stack.

Ollama models κατεβαίνουν ξανά. Docker Work volumes, Kubernetes PVCs και host folders είναι εκτός data directory και χρειάζονται δικά τους coordinated snapshots/retention.

Ενημερώσεις

Το Libre είναι stateful ακόμη με mutable tag. Η base Compose το εξαιρεί από Watchtower. Upgrade μόνο συντονισμένα:

  1. Καταγράψτε running image ID και επιλύστε reviewed replacement σε immutable digest.
  2. Εκτελέστε libre-webui recovery-check, backup service και απαιτήστε νέο verified archive/report.
  3. Ορίστε LIBRE_WEBUI_IMAGE στο digest, pull και recreate μόνο libre-webui, ποτέ data volume.
  4. Απαιτήστε /health/ready, sign-in, session/history, document retrieval και Work smoke tests. Αλλιώς rollback στο digest και διατηρήστε failed state και backup.

Η host sequence είναι σκόπιμα manual. Ελέγξτε νεότερο .lwb/.json πριν pull:

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

Watchtower override μόνο για labeled sidecars:

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

Ελέγχει Ollama/SearXNG κάθε 30 λεπτά. Data/config μένουν στα volumes/mounts. Δεν ενημερώνει Libre, cloudflared, proxy ή sandboxes. Client ακολουθεί main, experimental μπορεί :dev, αλλά ίδια manual backup-gated αναβάθμιση. Μην συνδέετε solo stack σε team persistence· αναπτύξτε πλήρη team topology.