Penerapan Jarak Jauh Privat
Pola ini menjalankan Libre WebUI, Ollama, dan Cloudflare Tunnel pada satu host Docker tanpa menerbitkan port aplikasi atau Ollama. Cloudflare Access menjadi batas identitas luar; autentikasi Libre WebUI tetap menjadi batas dalam. Work dan Watchtower adalah pilihan terpisah dengan hak setara root.
Templat ini merupakan topologi solo satu replika: SQLite, blob lokal terenkripsi, vektor tertanam, koordinasi lokal, dan pekerja persisten tertanam berbagi volume data aplikasi. Jangan mengubahnya menjadi penerapan team dengan mengganti pemilih backend di .env. Penerapan team harus memakai docker-compose.team.yml (dan docker-compose.team.work.yml bila Work aktif), yang menyediakan PostgreSQL/PGVector, penyimpanan S3 berversi, Redis, pekerja eksternal, dan gateway sebagai satu topologi terkoordinasi.
Gunakan deploy/private/docker-compose.yml sebagai titik awal. Image bawaannya main:
LIBRE_WEBUI_IMAGE=ghcr.io/libre-webui/libre-webui:main
Tag dev hanya sesuai untuk instans pengembangan yang dipilih secara eksplisit, bukan penerapan klien biasa.
Model Keamanan
- Cloudflare Access melindungi seluruh nama host, termasuk
/api/*dan peningkatan WebSocket. Jangan menambahkan jalur bypass publik. - API aplikasi memerlukan akun Libre WebUI aktif. Operasi siklus hidup model dan Work memerlukan peran basis data administrator.
- Aplikasi, Ollama, SearXNG, dan cloudflared hanya memakai jaringan Compose privat. Host tidak menerbitkan port aplikasi.
- SearXNG terbundel menyediakan pencarian web opsional. Layanan hanya internal dan tidak aktif sampai administrator mengaktifkan pencarian di Settings > Search; tetapkan
SEARXNG_SECRETdalam.envsebelum memulai tumpukan. - Aplikasi berjalan tanpa root, dengan sistem berkas akar hanya-baca, tanpa kapabilitas Linux, no-new-privileges, serta batas CPU, memori, dan PID.
- Work mati sampai salah satu berkas penimpaannya ditambahkan. Kontainer Work mendapat sistem akar hanya-baca, kapabilitas dilepas, batas sumber daya, volume ruang kerja, dan kebijakan jaringan tolak-bawaan.
Tumpukan dasar tidak memasang soket Docker. Saat Work diaktifkan dengan docker-compose.work-proxy.yml, proksi soket di jaringan internal memegang soket dan meneruskan hanya bagian API yang dipakai Work (containers, images, volumes, networks, exec, info). Bagian swarm, secrets, build, dan system ditolak; aplikasi tidak memerlukan pemasangan soket atau keanggotaan grup. Proksi mempersempit permukaan API Docker, bukan dampak operasi yang diteruskan: proses yang dapat membuat kontainer masih dapat memasang jalur host. Perlakukan ini sebagai lapisan penguatan, bukan isolasi multipenyewa.
Alternatif soket mentah tetap menjadi batas kepercayaan terbesar: docker-compose.work.yml dan penimpaan Watchtower memberi kontainer proses yang dapat mengeluarkan panggilan API Docker arbitrer dan mengendalikan host. Pemasangan soket hanya-baca tidak membuat akses API Docker hanya-baca. Pembantu pencadangan terintegrasi menolak mewarisi soket mentah; pindahkan Work ke proksi terfilter sebelum mengandalkan cadangan terjadwal.
Penyiapan Awal
- Buat operator non-root dengan sudo dan verifikasi masuk SSH berbasis kunci sebelum menonaktifkan SSH root.
- Salin
deploy/private/.env.exampleke/opt/libre-webui/.env, tetapkan mode0600, buat rahasia unik, dan ukurBLOB_QUOTA_BYTES_PER_USERuntuk host.BLOB_QUOTA_RESERVATION_TTL_MSmembatasi reservasi unggahan terlantar; bawaannya satu jam. - Jika Work akan aktif, tetapkan
DOCKER_GIDke ID numerik grup pemilik/var/run/docker.sock. - Simpan token Cloudflare Tunnel di
/opt/libre-webui/secrets/tunnel-tokendengan mode0640atau lebih ketat. - Buat aplikasi mandiri Cloudflare Access untuk seluruh nama host, gunakan sesi 24 jam, dan izinkan hanya identitas yang dimaksud. Aktifkan Protect with Access pada rute Tunnel. Jika pemantauan memerlukan pemeriksaan publik, buat aplikasi atau kebijakan terpisah hanya untuk
/health/live. Jangan menambahkan kebijakan Bypass menyeluruh: Bypass yang cocok mengalahkan kebijakan Allow. - Biarkan
ENABLE_SIGNUP=false. Setelah daftar izin Access melindungi nama host, buat administrator lokal pertama; basis data kosong mengizinkan satu akun bootstrap itu. Aktifkan pendaftaran hanya selama jendela yang disengaja. - Konfigurasikan pembatasan nama host Turnstile dan tetapkan
TURNSTILE_EXPECTED_HOSTNAMEke nama publik tepat.
Mulai dan verifikasi:
cd /opt/libre-webui
docker compose config --quiet
docker compose up -d
docker compose ps
Untuk Work, tambahkan penimpaan proksi soket:
docker compose -f docker-compose.yml -f docker-compose.work-proxy.yml up -d
Varian soket mentah (docker-compose.work.yml) tetap tersedia dengan konsekuensi kepercayaan di atas.
Setelah Access aktif, uji baris perintah memerlukan token layanan Cloudflare Access kecuali jalur memiliki bypass sempit. Simpan kredensial di luar riwayat shell dan kirim kedua header:
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
Permintaan tanpa autentikasi ke API terlindungi harus mengembalikan 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
Penguatan Host
Direktori memuat konfigurasi tambahan sshd dan jail fail2ban. Sebelum menerapkan, verifikasi sesi operator non-root dengan sudo di terminal lain. Uji sshd -t sebelum memuat ulang SSH.
Gunakan UFW atau tembok api setara untuk menolak lalu lintas masuk secara bawaan dan hanya mengizinkan SSH terbatas-laju. Docker tidak menerbitkan port layanan dalam templat ini:
ufw default deny incoming
ufw default allow outgoing
ufw limit OpenSSH
ufw enable
Biarkan pembaruan keamanan otomatis aktif. Nonaktifkan penerusan X11, agen, dan TCP kecuali ada kebutuhan terdokumentasi.
Cadangan dan Pemulihan
Sebelum mencadangkan, jalankan inventaris pemulihan hanya-baca di dalam kontainer aktif. Hal ini memakai versi aplikasi, lingkungan, dan volume yang benar-benar diterapkan. Perintah dari checkout host dapat memeriksa basis data atau sumber yang salah.
docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data
Kode 0 berarti tanpa penghalang, 1 berarti laporan JSON berisi penghalang, dan 2 berarti perintah gagal. Laporan hanya memuat sidik kunci enkripsi dan tanda kehadiran rahasia; nilai rahasia tidak dicetak. Simpan inventaris bersama cadangan untuk membandingkan versi, sidik skema, sumber daya Work, dan pengecualian sebelum pemulihan.
Buat kunci enkripsi serta penandatanganan khusus memakai image yang tepat. Simpan direktori di luar volume aplikasi dan salin kunci privat ke lokasi pemulihan terpisah:
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
Pembuatan kunci menolak berkas yang ada. Jangan menimpa set cadangan: kehilangan kunci enkripsi atau identitas tanda tangan membuat bukti pemulihan tidak berguna.
Pasang skrip cadangan/pemulihan dan unit systemd, lalu aktifkan 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 dapat membaca penimpaan pemeliharaan dari /etc/libre-webui/backup.env; .env aplikasi tidak dimuat. Buat sebagai root hanya jika perlu:
install -d -m 0750 /etc/libre-webui
install -m 0600 /dev/null /etc/libre-webui/backup.env
Di sana Anda dapat menetapkan LIBRE_WEBUI_STACK_DIR, LIBRE_WEBUI_BACKUP_RETENTION_DAYS, LIBRE_WEBUI_CONTAINER_NAME, dan LIBRE_WEBUI_BACKUP_KEY_DIR. Berkas harus dimiliki root dan bermode 0600. Direktori kunci khusus harus dapat dibaca root dalam sandbox systemd.
Mengubah LIBRE_WEBUI_BACKUP_DIR juga mengubah batas tulis systemd. Direktori harus ada dan unit memerlukan drop-in yang cocok. Setelah menetapkan LIBRE_WEBUI_BACKUP_DIR=/srv/backups/libre-webui dalam backup.env:
install -d -m 0700 /srv/backups/libre-webui
systemctl edit libre-webui-backup.service
Tambahkan jalur tepat lalu muat ulang unit:
[Service]
ReadWritePaths=/srv/backups/libre-webui
systemctl daemon-reload
systemctl start libre-webui-backup.service
Tanpa ReadWritePaths=, ProtectSystem=strict mencegah penulisan ke lokasi khusus.
Layanan mengizinkan hingga enam jam untuk arsip besar. Pembantu mengambil kunci host, menghentikan aplikasi hanya bila berjalan, dan membuat arsip dari volume tenang memakai image tepat. Arsip memuat manifest bertanda tangan dan payload terenkripsi operator, termasuk data, runtime, dan konfigurasi rahasia. Arsip diverifikasi penuh sebelum laporan metadata dipublikasikan secara atomik. Kontainer pemeliharaan hanya-baca mendapat tmpfs /tmp privat untuk pemeriksaan; teks biasa sementara tidak dipersistenkan. Salin berkas dan kunci ke luar host.
Saat Work memakai docker-compose.work-proxy.yml, pemulihan juga harus membuktikan setiap volume Work. Pembantu membaca DOCKER_HOST, menemukan socket-proxy pada proyek Compose aktif, dan menemukan satu jaringan internal bersama dari lampiran Docker nyata. Jangan menebak nama jaringan karena Compose memberi awalan proyek. Hanya kontainer pembuat arsip yang bergabung dan mencapai proksi; tidak mendapat soket mentah. Verifikasi independen memakai --network none. Proksi hilang, endpoint tak terduga, jaringan luar/ambigu, atau soket mentah gagal sebelum aplikasi dihentikan dan arsip diterbitkan.
Uji pemulihan ke volume baru:
LIBRE_WEBUI_RESTORE_IMAGE="$image_ref" \
libre-webui-restore \
/var/backups/libre-webui/libre-webui-integrated-YYYYMMDDTHHMMSSZ.lwb \
libre-webui-restore-drill
Pembantu menolak volume atau target konfigurasi yang ada, memverifikasi arsip dan inventaris dalam penyimpanan sekali pakai, lalu menyalin data ke volume baru serta menulis runtime.json dan secrets.json dengan izin privat. Ia tidak mengubah atau memulai tumpukan aktif. Periksa konfigurasi dan uji dengan tumpukan terisolasi.
Model Ollama dapat diunduh ulang. Volume Docker Work, PVC Kubernetes Work, dan folder Work host berada di luar direktori aplikasi sehingga memerlukan cuplikan dan retensi sendiri.
Pembaruan
Libre WebUI memiliki status walau tag image dapat berubah. Compose dasar selalu mengecualikan aplikasi dari Watchtower. Perbarui hanya sebagai tindakan operator terkoordinasi:
- Catat ID image aktif dan digest pengganti tetap yang ditinjau.
- Jalankan
libre-webui recovery-check, mulai cadangan, dan wajibkan arsip/laporan baru. - Tetapkan
LIBRE_WEBUI_IMAGEke digest, tarik, dan buat ulang hanyalibre-webui; jangan hapus volume data. - Wajibkan
/health/ready, masuk, sesi/riwayat, dokumen, dan uji Work. Jika gagal, kembalikan digest dan simpan status gagal serta cadangan.
Urutan host sengaja manual. Periksa pasangan .lwb/.json terbaru sebelum menarik:
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}}'
Penimpaan Watchtower bersoket hanya untuk sidecar yang diberi label:
docker compose \
-f docker-compose.yml \
-f docker-compose.watchtower.yml \
up -d
Watchtower memeriksa Ollama dan SearXNG setiap 30 menit. Data model Ollama tetap di volume bernama dan konfigurasi SearXNG di pemasangan host. Watchtower tidak memperbarui Libre WebUI, cloudflared, proksi soket Work, atau sandbox Work. Penerapan klien mengikuti main; instans eksperimental dapat memilih :dev, tetapi aplikasi tetap memerlukan pembaruan manual yang diwajibkan melalui cadangan terverifikasi. Jangan hubungkan tumpukan privat solo ini ke layanan persistensi team; terapkan topologi team lengkap.