Deploy Ollama and Open WebUI securely
Run authenticated local AI behind TLS with private Ollama networking, persistent storage, controlled models, staged updates and tested backup/restore.
Provide a reproducible local AI service whose network, identity, model, storage, update and recovery boundaries are verified.
- Ubuntu Server 24.04 LTS
- Docker Engine current supported
- Ollama reviewed pinned release
- Open WebUI reviewed pinned release
- Host and recovery Supported Ubuntu host, sudo, console recovery, synchronized clock and sufficient disk/RAM/VRAM.
Run baseline step. - DNS and TLS plan Reviewed hostname and public or internal certificate path exist.
Resolve {{hostName}}. - Protected backup storage Separate encrypted/restricted destination meets RPO/RTO.
Verify {{backupRoot}} capacity. - Model review License, size, digest, task quality and human-control boundary are approved.
Review {{modelName}} manifest.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A single-host local inference service with Ollama and Open WebUI on Ubuntu Server. Ollama is reachable only on a private container network, model artifacts live on a dedicated persistent volume, Open WebUI keeps its database and uploads on a separate persistent volume, and the public entry point is an HTTPS reverse proxy.
- A controlled model lifecycle. Operators select a model that fits measured RAM or VRAM, pull it by reviewed tag, record its digest and license metadata, run a deterministic smoke, observe loaded models, stop or remove retired artifacts and preserve the exact approved manifest for rollback.
- A production operations path with first-admin bootstrap, authentication enabled, a persistent WEBUI_SECRET_KEY, TLS and WebSocket proxying, restrictive firewall, backup verification, staged image and database updates, health and capacity monitoring, and a documented restore that never overwrites the only good backup.
- Port 11434 is not reachable from untrusted networks. Open WebUI is accessible only through the intended HTTPS hostname, WebSocket upgrades work, HTTP redirects to HTTPS and authentication protects every private conversation and administrative surface.
- Container images, configuration and model selections are versioned. Rolling tags are not promoted without resolving and recording a reviewed digest, and development volumes never share production data.
- Backups include Open WebUI's persistent data, Ollama model inventory and reviewed configuration. A restore drill proves chats/settings and the approved model respond before the backup is considered usable.
- Updates follow backup, staging migration, smoke, canary access and rollback. Operators can identify image digests, Open WebUI health, Ollama version, model storage, memory pressure, queueing and recent errors without exposing prompts or secrets.
Architecture
How the parts fit together
Docker Compose runs Ollama and Open WebUI on an internal network. Ollama has no host-published port; Open WebUI reaches it at http://ollama:11434 and binds its own port only to loopback for the reverse proxy. Caddy or an equivalent reviewed proxy terminates TLS, redirects HTTP, forwards WebSocket upgrades and applies network controls. Persistent named volumes separate Ollama models from Open WebUI application data. A root-owned environment file supplies one stable WEBUI_SECRET_KEY and public URL settings. Backups are written to a separate filesystem and verified before updates. The release manifest pins Compose configuration, container image digests, model names/digests and proxy configuration.
- Define users, privacy boundary, hardware capacity, hostname, recovery objective and whether the host is allowed any public exposure.
- Install a supported container runtime, create storage and secret files, and validate available disk, RAM/VRAM and DNS before pulling large artifacts.
- Deploy pinned Ollama and Open WebUI images on a private network with persistent volumes and no public Ollama port.
- Pull one reviewed model, record its digest and metadata, run local API inference and observe memory and queue behavior.
- Create the first Open WebUI administrator through the protected local or HTTPS path, keep authentication enabled and verify the stable secret key.
- Place the application behind TLS, test redirects, certificate, WebSocket transport and blocked direct ports from an external host.
- Back up and verify persistent data and release metadata; stage every image/model update against a copy before production migration.
- Monitor service health, storage, model residency, latency and errors; restore the previous images/data/model manifest when acceptance checks fail.
Assumptions
- The host runs supported Ubuntu Server and Docker Engine/Compose or an equivalent reviewed container runtime. The operator has sudo and independent console access.
- A DNS name points to the intended reverse proxy and TCP 80/443 reachability is available if public certificate issuance is used. Private-only deployments use an approved internal PKI or access network.
- The selected model's license and use are acceptable and the host has sufficient storage and RAM/VRAM. A local model does not automatically make every workload private if plugins, web search or external providers remain enabled.
- Open WebUI authentication remains enabled for multi-user use. The first-account bootstrap happens through a protected path and the stable WEBUI_SECRET_KEY is backed up separately from public configuration.
- Backups are stored outside the live volume and protected according to the sensitivity of conversations, uploaded files and configuration. Restore tests may use an isolated host.
- The organization can tolerate a maintenance window or has an upstream availability design; this guide covers a durable single-host deployment, not multi-replica HA.
Key concepts
- Model manifest
- Reviewed list of model name/tag, digest, size, license note, purpose, smoke result and lifecycle state used by the deployment.
- Private inference network
- Container or host network where Ollama is reachable by Open WebUI but not published to untrusted clients.
- WEBUI_SECRET_KEY
- Persistent secret used by Open WebUI for session signing and related cryptographic behavior; changing it invalidates sessions and replicas must share it.
- Persistent data volume
- Storage mounted at /app/backend/data so database, chats, settings and uploads survive container replacement.
- Rolling tag
- An image tag such as main whose digest can move. Production releases record an immutable reviewed digest for reproduction and rollback.
- Restore drill
- Isolated recovery that proves backup extraction, application startup, authentication, model availability and sample inference.
Before you copy
Values used in this guide
{{hostName}}HTTPS DNS name used by operators.
Example: ai.example.net{{openWebuiImage}}Reviewed Open WebUI image pinned to an immutable digest.
Example: ghcr.io/open-webui/open-webui:main@sha256:REVIEWED_DIGEST{{ollamaImage}}Reviewed Ollama image pinned to an immutable digest.
Example: ollama/ollama:latest@sha256:REVIEWED_DIGEST{{modelName}}Reviewed Ollama model tag from the approved manifest.
Example: gemma3:4b{{backupRoot}}Separate protected filesystem for backups.
Example: /srv/backups/local-ai{{releaseId}}Complete deployment release identifier.
Example: local-ai/2026-07-28.1Security and production boundaries
- Do not publish Ollama's API directly to the Internet. It has access to model operations and may expose inference without the user controls provided by the application boundary.
- Keep Open WebUI authentication enabled for shared or network-accessible deployments. The no-login single-user option is only appropriate for a genuinely isolated single-user environment and cannot be casually toggled after initialization.
- Use a stable high-entropy WEBUI_SECRET_KEY stored with restrictive permissions. Never commit it to Compose, screenshots or support logs; changing it invalidates sessions.
- Terminate TLS at a maintained reverse proxy and permit only the intended hostname and networks. Test WebSocket forwarding and direct-port blocking from outside the host.
- Treat uploaded documents, chats, generated content and backups as sensitive. Encrypt backup transport/storage as required, restrict access and verify deletion/retention policy.
- Local models can still generate harmful or incorrect output. Keep human review and application authorization for consequential decisions and never connect model text directly to privileged execution.
Stop before continuing if
- Stop if console recovery, tested backup destination, sufficient disk/memory or a reviewed model license is unavailable.
- Stop if Ollama port 11434 or Open WebUI's direct application port is reachable from an untrusted external host.
- Stop if authentication is disabled on a shared/network service, the first administrator can be claimed through an unprotected route or WEBUI_SECRET_KEY is not persistent.
- Stop an update when backup verification, staging migration, pinned rollback image/model or external HTTPS/WebSocket smoke fails.
- Stop restore if the target volume or backup archive is ambiguous; never erase the live volume before preserving and verifying the current state.
instruction
Define users, exposure, data and recovery boundaries
Document who may use the service, whether it is private or Internet-reachable, what data is allowed, which optional integrations remain disabled, hardware capacity, DNS/TLS path, backup objective and human review for consequential output.
Why this step matters
A local stack still has network, identity, storage and model risks. Defining the boundary prevents a convenient demo from becoming an unauthenticated data repository.
What to understand
Classify chats, uploads and backups.
Decide public, VPN or loopback access.
Measure RAM/VRAM and disk before model selection.
Name RPO/RTO and console recovery owner.
System changes
- Creates an architecture and data policy.
- Changes no host.
Syntax explained
VPN+HTTPS- Private access network plus encrypted application transport.
RPO- Maximum acceptable data-loss interval.
RTO- Target recovery duration.
deployment=single-host users=operations-team access=VPN+HTTPS ollama_public=false openwebui_auth=true allowed_data=internal-low-sensitivity RPO=24h RTO=4h console_recovery=verified consequential_actions=human_only
Checkpoint: Approve operating boundary
Continue whenOwner can state access, data, capacity, recovery and human-control rules.
Stop whenStop if exposure, backup or data policy is undefined.
If this step fails
The team assumes local means no egress.
Likely causeIntegrations were not inventoried.
Review providers/plugins.Observe outbound connections.
ResolutionDisable unapproved integrations and document the actual flow.
Security notes
- No model output receives operational authority.
- Restrict data to the approved classification.
Alternatives
- Use workstation loopback only.
- Use a hosted service under approved controls.
Stop conditions
- Stop if exposure, backup or data policy is undefined.
command
Verify host, Docker, storage and clock
Record OS, container runtime, Compose, CPU, memory, disk and time before downloading images or models. Keep independent console access and enough free space for the model plus update and backup copies.
Why this step matters
Model pulls and updates are storage-heavy and TLS/auth depend on a sane clock. A baseline makes later capacity and rollback decisions evidence-based.
What to understand
Confirm supported Docker installation.
Reserve space for old/new image and backup.
Record GPU separately when used.
Verify console recovery before firewall changes.
System changes
- Reads host state only.
- Creates no container or download.
Syntax explained
free -h- Readable memory capacity.
df -h- Filesystem capacity.
NTPSynchronized- Clock synchronization state.
uname -a && docker version --format '{{.Server.Version}}' && docker compose version && free -h && df -h /var/lib/docker && timedatectl show -p NTPSynchronizedLinux ai01 6.8.0-65-generic #68-Ubuntu SMP x86_64 GNU/Linux 27.5.1 Docker Compose version v2.38.2 Mem: 62Gi total, 55Gi available /dev/mapper/vg-docker 900G 112G 743G 14% /var/lib/docker NTPSynchronized=yes
Checkpoint: Approve host capacity
docker info --format '{{json .SecurityOptions}}'Continue whenRuntime is healthy, storage/memory meet plan and clock/console recovery are available.
Stop whenStop on low disk, unsupported runtime, unsynchronized clock or missing recovery access.
If this step fails
Docker commands fail.
Likely causeDaemon or permissions are unhealthy.
systemctl status docker.Inspect group/access policy.
ResolutionRepair the official Docker installation before continuing.
Security notes
- Avoid broad Docker group membership.
- Do not run remote daemon unauthenticated.
Alternatives
- Use Podman only with a separately tested guide.
- Deploy on a larger approved host.
Stop conditions
- Stop on low disk, unsupported runtime, unsynchronized clock or missing recovery access.
command
Create protected configuration, secrets and backup paths
Create a root-owned deployment directory and separate backup filesystem. Generate a stable Open WebUI secret into a mode-0600 environment file and record only its digest in the release manifest.
Why this step matters
A persistent secret keeps sessions stable and protected configuration prevents accidental repository exposure. A separate backup path reduces the chance that container cleanup removes recovery data.
What to understand
Store the secret outside Compose.
Back it up through the secret-management process.
Do not echo its value.
Ensure backup destination has sufficient capacity and protection.
System changes
- Creates directories and one secret file.
- Does not start services.
Syntax explained
umask 077- Creates owner-only secret permissions.
openssl rand -hex 32- Generates high-entropy secret text.
install -d -m 0750- Creates restricted directories.
Values stay on this page and are never sent or saved.
sudo install -d -m 0750 -o root -g root /opt/local-ai {{backupRoot}} && sudo sh -c 'umask 077; printf "WEBUI_SECRET_KEY=%s\n" "$(openssl rand -hex 32)" > /opt/local-ai/secrets.env' && sudo stat -c '%a %U:%G %n' /opt/local-ai/secrets.env600 root:root /opt/local-ai/secrets.env
Checkpoint: Verify secret handling
sudo test -s /opt/local-ai/secrets.env && sudo test "$(stat -c %a /opt/local-ai/secrets.env)" = 600Continue whenSecret exists, is non-empty and mode 0600 without appearing in command output or repository.
Stop whenStop if the secret was printed, committed or made group/world-readable.
If this step fails
Sessions reset after update.
Likely causeSecret file was not loaded or persisted.
Compare secret digest.Inspect Compose env_file.
ResolutionRestore the protected stable secret and require reauthentication after any real rotation.
Security notes
- Never include secret values in backups without encryption/access policy.
- Rotate immediately if exposed.
Alternatives
- Use a managed Docker secret mechanism.
- Use rootless secret injection supported by your runtime.
Stop conditions
- Stop if the secret was printed, committed or made group/world-readable.
config
Define pinned private-network services
Create Compose services with persistent volumes, an internal Ollama endpoint and loopback-only Open WebUI publication. Use reviewed immutable image digests from the release manifest rather than trusting rolling tags.
Why this step matters
Private networking prevents accidental Ollama exposure, loopback binding reserves public access for TLS proxying and named volumes survive container replacement. Immutable image references make update and rollback reproducible.
What to understand
Resolve and review real digests before deployment.
Persist both model and application paths.
Keep auth true.
Do not mount Docker socket or host root.
System changes
- Adds deployment configuration.
- Does not start containers until explicitly applied.
Syntax explained
127.0.0.1:3000:8080- Direct UI listens only on host loopback.
OLLAMA_BASE_URL- Internal service URL.
restart: unless-stopped- Restarts services except when deliberately stopped.
/opt/local-ai/compose.yamlValues stay on this page and are never sent or saved.
services:
ollama:
image: "{{ollamaImage}}"
restart: unless-stopped
volumes:
- ollama-models:/root/.ollama
networks: [local-ai]
open-webui:
image: "{{openWebuiImage}}"
restart: unless-stopped
depends_on: [ollama]
env_file: [secrets.env]
environment:
OLLAMA_BASE_URL: http://ollama:11434
WEBUI_AUTH: "True"
ports:
- "127.0.0.1:3000:8080"
volumes:
- open-webui-data:/app/backend/data
networks: [local-ai]
networks:
local-ai:
driver: bridge
volumes:
ollama-models:
open-webui-data:services=ollama,open-webui ollama_host_ports=none openwebui_bind=127.0.0.1:3000 openwebui_data=/app/backend/data auth=true images=immutable-digest compose_validation=PASS
Checkpoint: Validate Compose and image pins
cd /opt/local-ai && sudo docker compose config --quietContinue whenConfiguration resolves, images contain reviewed digests and no Ollama host port exists.
Stop whenStop if images are mutable for production, data volumes absent or ports bind all interfaces.
If this step fails
Ollama appears on host port 11434.
Likely causeCompose publishes the port.
Inspect docker ps.Inspect compose config.
ResolutionRemove the ports mapping and recreate after review.
Security notes
- No Docker socket mount.
- No privileged container unless separately justified.
Alternatives
- Bind both services to loopback for host-installed proxy.
- Use an isolated VM boundary.
Stop conditions
- Stop if images are mutable for production, data volumes absent or ports bind all interfaces.
command
Start services and verify the private Ollama API
Pull pinned images, start the stack and test Ollama from inside its network and Open WebUI from loopback. Confirm that port 11434 has no host listener.
Why this step matters
Starting services is the first state change. Immediate listener and health checks catch unsafe exposure before DNS or proxy publication.
What to understand
Review pulled digests against manifest.
Inspect container status and recent logs.
Test internal Ollama with docker compose exec.
Test external port blocking from another host later.
System changes
- Downloads images and starts persistent services.
- Creates container networks and volumes.
Syntax explained
compose pull- Fetches exact pinned images.
compose up -d- Reconciles services in background.
! ss ...11434- Asserts no host listener.
cd /opt/local-ai && sudo docker compose pull && sudo docker compose up -d && sudo docker compose ps && curl -fsS http://127.0.0.1:3000/health && ! ss -lnt | grep -q ':11434 'NAME IMAGE SERVICE STATUS
local-ai-ollama-1 sha256:... ollama Up (healthy)
local-ai-open-webui-1 sha256:... open-webui Up (healthy)
{"status":true}
ollama_host_listener=absentCheckpoint: Verify service and exposure state
cd /opt/local-ai && sudo docker compose exec open-webui curl -fsS http://ollama:11434/api/versionContinue whenOpen WebUI container reaches Ollama internally and host exposes no 11434 listener.
Stop whenStop if health fails, digest differs or Ollama is externally reachable.
If this step fails
Open WebUI cannot resolve ollama.
Likely causeServices are not on the same network.
Inspect compose networks.Resolve ollama inside container.
ResolutionAttach both services to the private network and recreate.
Security notes
- Review logs for accidental secrets.
- Do not temporarily publish 11434 to troubleshoot.
Alternatives
- Use container healthchecks and a local diagnostic container.
- Run Ollama on host loopback with explicit firewall.
Stop conditions
- Stop if health fails, digest differs or Ollama is externally reachable.
command
Pull, inspect and smoke one approved model
Pull the reviewed model, list and inspect it, record its digest/size in the manifest and run a deterministic smoke. Measure memory and remove only explicitly retired models after rollback review.
Why this step matters
Model tags, artifacts and memory requirements are part of the release. A concrete smoke proves the artifact can load and respond before users depend on it.
What to understand
Review license and intended use.
Record returned ID/digest and size.
Observe pull storage and load memory.
Use ollama ps/stop for residency and ollama rm only under approved lifecycle.
System changes
- Downloads a large model artifact and loads it for inference.
- Consumes disk and RAM/VRAM.
Syntax explained
ollama pull- Downloads/updates the named model.
ollama show- Displays model metadata.
ollama run- Loads model and performs inference.
Values stay on this page and are never sent or saved.
cd /opt/local-ai && sudo docker compose exec ollama ollama pull {{modelName}} && sudo docker compose exec ollama ollama list && sudo docker compose exec ollama ollama show {{modelName}} && sudo docker compose exec ollama ollama run {{modelName}} 'Reply with exactly: MODEL_OK'pulling manifest pulling 5c3... 100% ▕████████████████▏ 3.3 GB verifying sha256 digest writing manifest success NAME ID SIZE MODIFIED gemma3:4b a2af6cc3eb7f 3.3 GB Less than a minute ago MODEL_OK
Checkpoint: Record model manifest and capacity
cd /opt/local-ai && sudo docker compose exec ollama ollama psContinue whenApproved model ID/size are recorded and load fits capacity without swapping or errors.
Stop whenStop if license, digest, disk or memory behavior is unacceptable.
If this step fails
Model process queues or swaps heavily.
Likely causeModel exceeds practical capacity.
Run ollama ps.Inspect memory/GPU.
ResolutionStop it and select a smaller reviewed model after quality evaluation.
Security notes
- Do not pull unreviewed model artifacts in production.
- Model output remains untrusted.
Alternatives
- Use a smaller quantized model.
- Use a hosted approved model for workloads exceeding capacity.
Stop conditions
- Stop if license, digest, disk or memory behavior is unacceptable.
instruction
Bootstrap the first administrator through a protected path
Before public exposure, access loopback through console or SSH tunnel, create the intended first administrator, verify authentication and administrative ownership, then close the bootstrap path. Never run shared service with WEBUI_AUTH disabled.
Why this step matters
Initial account creation can establish administrative control. Performing it before exposure prevents an outsider from claiming the first account.
What to understand
Use SSH tunnel to loopback.
Create a unique strong administrator account.
Test logout/login and non-admin user role.
Record admin recovery procedure without storing password in the guide.
System changes
- Creates initial Open WebUI user/admin state.
- Writes authentication data to persistent volume.
Syntax explained
ssh-tunnel- Protected access to loopback before proxy publication.
WEBUI_AUTH=True- Multi-user authentication remains enabled.
anonymous_access=DENIED- Acceptance check.
bootstrap_path=ssh-tunnel first_admin=created admin_identity=verified WEBUI_AUTH=True anonymous_access=DENIED session_persistence=PASS bootstrap_window=closed
Checkpoint: Verify authentication and ownership
Continue whenOnly intended admin exists, anonymous access fails and sessions survive container restart.
Stop whenStop if first account ownership is uncertain or anonymous access works.
If this step fails
Unexpected admin exists.
Likely causeBootstrap was exposed or reused data is compromised.
Block access.Inspect users and logs.
ResolutionTreat as incident and restore/reinitialize from known clean state.
Security notes
- Use a password manager and MFA/SSO where supported and approved.
- Keep break-glass recovery protected.
Alternatives
- Integrate approved SSO after local admin bootstrap.
- Keep service workstation-local.
Stop conditions
- Stop if first account ownership is uncertain or anonymous access works.
config
Terminate TLS and forward WebSockets
Configure the reviewed reverse proxy for the public hostname, HTTPS, HTTP redirect and WebSocket-compatible proxying to loopback Open WebUI. Keep Caddy state persistent if using automatic certificates.
Why this step matters
TLS protects credentials and conversations in transit, while the reverse proxy is the only intended public boundary. Open WebUI requires WebSocket support for interactive behavior.
What to understand
Validate config before reload.
Persist certificate state and monitor renewal.
Set headers according to application compatibility.
Test from outside the host, not only localhost.
System changes
- Publishes HTTPS service and certificate handling.
- Does not expose Ollama.
Syntax explained
reverse_proxy- Forwards HTTP and WebSocket traffic to loopback.
HSTS- Instructs browsers to prefer HTTPS after careful domain review.
encode- Enables supported response compression.
/etc/caddy/CaddyfileValues stay on this page and are never sent or saved.
{{hostName}} {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
Referrer-Policy "same-origin"
}
}hostname={{hostName}}
http_status=308
https_status=200
certificate_subject={{hostName}}
certificate_expiry_days=89
websocket_upgrade=101
direct_3000_external=BLOCKEDCheckpoint: Run external TLS and WebSocket smoke
curl -I https://{{hostName}} && openssl s_client -connect {{hostName}}:443 -servername {{hostName}} </dev/nullContinue whenValid hostname certificate, HTTPS response, redirect and WebSocket chat; direct ports remain blocked.
Stop whenStop if certificate, WebSocket or direct-port checks fail.
If this step fails
Chat disconnects while page loads.
Likely causeWebSocket forwarding is broken.
Inspect browser 101 upgrade.Inspect proxy logs.
ResolutionApply official proxy guidance and retest streamed chat.
Security notes
- Restrict proxy administration.
- Do not publish origin ports externally.
Alternatives
- Use Nginx with official Open WebUI proxy guidance.
- Use VPN-only access with internal certificates.
Stop conditions
- Stop if certificate, WebSocket or direct-port checks fail.
verification
Verify listeners, firewall and application access
Allow only SSH from administrative networks and HTTP/HTTPS as required for certificate and users. Confirm Ollama and the direct Open WebUI port are unreachable externally, while HTTPS authentication works.
Why this step matters
Compose intent is not proof of exposure. Listener, firewall and external tests verify the actual attack surface.
What to understand
Preserve console before firewall.
Test from a distinct host/network.
Restrict SSH.
Review IPv4 and IPv6.
System changes
- May update host firewall under approved policy.
- No application data change.
Syntax explained
22/tcp- Administrative SSH restricted to approved network.
443/tcp- Primary HTTPS service.
11434- Ollama port that must remain private.
sudo ss -lntp && sudo ufw status verbose22/tcp ALLOW IN 10.20.0.0/16 80/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere 3000/tcp DENY/NO LISTENER external 11434/tcp DENY/NO LISTENER external https_auth=PASS
Checkpoint: Perform external port scan
nmap -Pn -p 22,80,443,3000,11434 {{hostName}}Continue whenOnly approved ports are open and authentication protects HTTPS.
Stop whenStop if lockout risk exists or direct model/application ports are open.
If this step fails
11434 is reachable externally.
Likely causeHost bind or port publication widened.
Inspect ss.Inspect docker port.
ResolutionRemove publication, restore private network and review logs.
Security notes
- Check IPv6 separately.
- Avoid management access from all networks.
Alternatives
- Restrict HTTPS to VPN ranges.
- Place host behind an access proxy/firewall appliance.
Stop conditions
- Stop if lockout risk exists or direct model/application ports are open.
command
Back up volumes and release metadata
Quiesce Open WebUI for a consistent single-host archive, back up its named volume to the separate destination, export Compose/proxy/model manifest and checksum the archive. Decide separately whether to back up large model blobs or redownload them by recorded digest.
Why this step matters
The data volume contains database, chats, settings and uploads. A quiesced archive and checksum create a recoverable point before updates.
What to understand
Store configuration and manifest beside backup.
Protect archive as sensitive.
Use explicit volume name verified from Compose.
Restart and health-check promptly.
System changes
- Briefly stops Open WebUI and writes a backup archive.
- Ollama may remain available internally.
Syntax explained
:ro- Mounts live data read-only in backup helper.
tar czf- Creates compressed archive.
sha256sum- Integrity check, not authenticity or encryption.
Values stay on this page and are never sent or saved.
cd /opt/local-ai && sudo docker compose stop open-webui && sudo docker run --rm -v local-ai_open-webui-data:/data:ro -v {{backupRoot}}:/backup alpine tar czf /backup/openwebui-$(date +%Y%m%d-%H%M%S).tar.gz /data && sudo docker compose start open-webui && sudo sha256sum {{backupRoot}}/openwebui-*.tar.gzContainer local-ai-open-webui-1 Stopped backup=/srv/backups/local-ai/openwebui-20260728-153000.tar.gz size=184M Container local-ai-open-webui-1 Started sha256=7d9a... openwebui-20260728-153000.tar.gz service_health=PASS
Checkpoint: List and verify backup
sudo tar tzf {{backupRoot}}/openwebui-20260728-153000.tar.gz | head && sudo test -s {{backupRoot}}/openwebui-20260728-153000.tar.gzContinue whenArchive contains /data paths, checksum recorded and application health restored.
Stop whenStop if volume name, destination, permissions or service recovery is uncertain.
If this step fails
Archive is tiny or lacks database.
Likely causeWrong volume was mounted.
List archive.Inspect docker volume mounts.
ResolutionIdentify actual /app/backend/data volume and repeat before updates.
Security notes
- Encrypt and restrict backup storage.
- Never upload archives to unapproved services.
Alternatives
- Use storage snapshots after application quiescence.
- Use database-specific backup for scaled external databases.
Stop conditions
- Stop if volume name, destination, permissions or service recovery is uncertain.
verification
Restore into an isolated drill volume
Create a new isolated volume and Compose project, extract the selected archive without touching production, start the pinned rollback image on loopback-only alternate ports and verify users/settings, a sample chat and model connection.
Why this step matters
An archive is not a backup until restoration proves application behavior. Isolated recovery prevents a drill from destroying live data.
What to understand
Use a different project name, network and loopback port.
Load the matched image/secret/config.
Verify actual records and inference.
Delete drill data according to policy afterward.
System changes
- Creates an isolated restore-test volume and temporary service.
- Does not overwrite production.
Syntax explained
volume create- Creates empty isolated target.
:ro- Prevents test from modifying backup archive.
-C /- Restores archive paths as created.
Values stay on this page and are never sent or saved.
sudo docker volume create open-webui-restore-test && sudo docker run --rm -v open-webui-restore-test:/data -v {{backupRoot}}:/backup:ro alpine sh -c 'tar xzf /backup/openwebui-20260728-153000.tar.gz -C /' && echo restore_volume_readyopen-webui-restore-test restore_volume_ready files=1248 database_present=true isolated_start=PASS admin_login=PASS ollama_connection=PASS sample_chat=PASS
Checkpoint: Approve recovery evidence
Continue whenMatched image starts, login/settings/data/model smoke pass and elapsed recovery meets RTO.
Stop whenStop if any command targets production volume or archive identity is ambiguous.
If this step fails
Old image cannot read restored data.
Likely causeBackup was taken after incompatible migration.
Inspect update timestamps.Select matched backup/image.
ResolutionRestore the pre-update pair and improve manifest linkage.
Security notes
- Keep drill isolated and access-restricted.
- Remove test copies after evidence retention.
Alternatives
- Restore on a disposable VM.
- Use storage snapshot clone.
Stop conditions
- Stop if any command targets production volume or archive identity is ambiguous.
decision
Stage image and model updates before production
Resolve new immutable image digests, review release notes, back up production and run the candidate against a restored data copy and model smoke. Never share production volume with dev or candidate containers.
Why this step matters
Open WebUI rolling images and migrations can change. Staging on a copied volume discovers incompatibility while preserving production and makes image/data rollback explicit.
What to understand
Read official update guidance.
Resolve digest after review.
Never share dev volume.
Test auth, proxy, WebSocket, data and model.
System changes
- Downloads candidate images and migrates only staging copy.
- Does not alter production when followed correctly.
Syntax explained
candidate_images=immutable- Reproducible reviewed artifacts.
staging_volume=isolated- No candidate migration touches production.
rollback_pair- Prior image plus pre-update data.
Values stay on this page and are never sent or saved.
node local-ai/release-check.mjs --from {{releaseId}} --candidate local-ai/2026-08-10.1backup_verified=true candidate_images=immutable staging_volume=isolated database_migration=PASS admin_login=PASS websocket=PASS model_smoke=PASS security_checks=PASS rollback_pair=available promotion=APPROVED
Checkpoint: Sign update evidence
node local-ai/release-check.mjs --report local-ai/2026-08-10.1Continue whenAll functional/security smokes pass and matched rollback data/image exist.
Stop whenStop if staging shares production data or rollback pair is missing.
If this step fails
Candidate migrates production unexpectedly.
Likely causeWrong volume/project name used.
Stop candidate.Inspect mounts.
ResolutionPreserve state, restore pre-update backup and strengthen project isolation checks.
Security notes
- Review image provenance and digest.
- Do not automate blind rolling-tag updates.
Alternatives
- Schedule manual update window.
- Remain on current supported version until staging passes.
Stop conditions
- Stop if staging shares production data or rollback pair is missing.
command
Promote a pinned update with a maintenance checkpoint
Announce maintenance, create a fresh verified backup, update manifest to candidate digests, recreate services and run health, login, TLS, WebSocket, data and model checks before reopening access.
Why this step matters
Promotion changes application and potentially database state. A checkpointed maintenance flow prevents half-updated service and keeps rollback decision timely.
What to understand
Use exact reviewed manifest.
Watch migration logs.
Run external tests before reopening.
Keep pre-update backup immutable.
System changes
- Replaces production containers and may migrate Open WebUI data.
- Keeps persistent volumes.
Syntax explained
pull- Fetches pinned candidate images.
up -d- Recreates services to manifest.
--remove-orphans- Removes obsolete services after review.
cd /opt/local-ai && sudo docker compose pull && sudo docker compose up -d --remove-orphans && sudo docker compose psrelease=local-ai/2026-08-10.1 images=pinned services=healthy database_migration=completed admin_login=PASS https=PASS websocket=PASS sample_chat=PASS ollama_external=BLOCKED
Checkpoint: Run production acceptance
node local-ai/acceptance.mjs --release local-ai/2026-08-10.1 --host {{hostName}}Continue whenAuth/data/model/TLS/WebSocket/security checks pass with intended digests.
Stop whenStop and roll back on migration, login, data, model, TLS or exposure failure.
If this step fails
Services healthy but users cannot login.
Likely causeSecret or database migration mismatch.
Compare secret digest.Inspect app logs.
ResolutionRestore matched prior image, secret and pre-update data.
Security notes
- Do not bypass auth to complete update.
- Review new environment defaults.
Alternatives
- Blue/green host cutover.
- Restore current release when maintenance window closes.
Stop conditions
- Stop and roll back on migration, login, data, model, TLS or exposure failure.
verification
Monitor health, capacity, storage and model lifecycle
Collect service health, restart count, storage, Ollama loaded models, inference latency, queueing, TLS expiry and recent errors. Alert before model pulls or backups exhaust disk and review model/image updates on a schedule.
Why this step matters
Local inference consumes finite disk, memory and accelerator capacity. Monitoring detects queues, failed renewals and storage exhaustion before user-visible failure.
What to understand
Alert on volume growth and backup age.
Observe loaded model residency.
Track p95 inference and queue.
Review logs without retaining prompts by default.
System changes
- Reads operational state and emits approved metrics.
- No model or data change.
Syntax explained
ollama ps- Shows models currently loaded.
docker system df- Container storage usage.
tls_expiry_days- Certificate renewal safety margin.
Values stay on this page and are never sent or saved.
cd /opt/local-ai && sudo docker compose ps && sudo docker compose exec ollama ollama ps && sudo docker system df && df -h {{backupRoot}}services_healthy=2/2 restart_count=0 loaded_model=gemma3:4b processor=100% GPU model_volume=3.4G openwebui_volume=1.2G backup_free=1.8T tls_expiry_days=83 recent_errors=0
Checkpoint: Test alert paths
node local-ai/test-alerts.mjsContinue whenDisk, health, latency, queue, backup age and TLS alerts reach operators.
Stop whenStop expansion if monitoring cannot detect capacity or certificate failure.
If this step fails
Disk alert fires after pull failure.
Likely causeThreshold ignored artifact size.
Compare free space and model size.Inspect alert threshold.
ResolutionReserve pull/update/backup headroom and alert earlier.
Security notes
- Do not export raw prompts in metrics.
- Restrict logs and admin dashboards.
Alternatives
- Use existing Prometheus/node monitoring.
- Schedule manual checks for very small isolated deployments.
Stop conditions
- Stop expansion if monitoring cannot detect capacity or certificate failure.
verification
Prove matched image, data and model rollback
Before closing the update, dry-run restoration of the previous images, pre-update Open WebUI archive, secret and model manifest in an isolated project. A live rollback stops access, preserves current state, restores matched data and re-runs acceptance.
Why this step matters
Database migrations mean image rollback alone may fail. A matched release includes data, secret, proxy and model state and must be proven before an incident.
What to understand
Preserve current state before live restore.
Restore to a new volume first.
Verify admin/data/model/proxy.
Cut over only after evidence.
System changes
- Dry-run changes no production state.
- A live run restores matched prior artifacts and data.
Syntax explained
--from- Failed candidate release.
--to- Known-good matched release.
--dry-run- Resolves and tests without production cutover.
Values stay on this page and are never sent or saved.
node local-ai/rollback.mjs --from local-ai/2026-08-10.1 --to {{releaseId}} --dry-runfrom=local-ai/2026-08-10.1
to={{releaseId}}
image_digests=RESOLVED
data_backup=VERIFIED
secret_digest=AVAILABLE
model_manifest=AVAILABLE
isolated_restore=PASS
acceptance=PASS
live_changes=0Checkpoint: Approve rollback evidence
node local-ai/rollback.mjs --status {{releaseId}}Continue whenAll matched artifacts resolve and isolated acceptance passes within RTO.
Stop whenStop promotion if prior data/image/secret/model cannot restore.
If this step fails
Old UI starts but data schema errors continue.
Likely causeNew database remained.
Inspect volume mount.Compare backup timestamp.
ResolutionRestore the matched pre-update archive into a clean volume.
Security notes
- Protect both old and new backups.
- Audit live rollback authorization.
Alternatives
- Blue/green cutback.
- Disable access until clean restore is proven.
Stop conditions
- Stop promotion if prior data/image/secret/model cannot restore.
Finish line
Verification checklist
! ss -lnt | grep -q ':11434 ' && cd /opt/local-ai && sudo docker compose exec open-webui curl -fsS http://ollama:11434/api/versionInternal reachability works and no host listener exists.curl -I https://{{hostName}} && nmap -Pn -p 3000,11434 {{hostName}}HTTPS responds while direct application and Ollama ports are blocked.cd /opt/local-ai && sudo docker compose exec ollama ollama list && sudo docker compose exec ollama ollama run {{modelName}} 'Reply with exactly: MODEL_OK'Approved model ID is present and smoke returns MODEL_OK.node local-ai/restore-check.mjs --backup-root {{backupRoot}} --release {{releaseId}}Isolated admin, data, WebSocket and model smokes pass within RTO.node local-ai/rollback.mjs --status {{releaseId}}Matched image, data, secret, proxy and model artifacts resolve.Recovery guidance
Common problems and safe checks
Open WebUI shows no Ollama models.
Likely causeThe internal base URL, network or Ollama service is wrong.
curl Ollama from inside the Open WebUI container.Inspect both service logs.
ResolutionSet the documented internal Ollama URL, join the same private network and restart after configuration review.
Ollama works on the host but not in the container.
Likely causelocalhost points to the container itself.
Resolve the ollama service name.Test port 11434 on the Compose network.
ResolutionUse http://ollama:11434 for the Compose service and do not publish the API unnecessarily.
A model pull fills the disk.
Likely causeModel size and temporary download capacity were not budgeted.
Check df and docker system df.List model inventory and volume size.
ResolutionStop pulls, add approved storage or remove explicitly retired models after backup/manifest review.
Inference is extremely slow or queues.
Likely causeThe model does not fit available memory/VRAM or too many models remain loaded.
Run ollama ps.Observe host/GPU memory and logs.
ResolutionSelect a smaller reviewed model, stop unused loaded models and cap concurrency based on measurement.
Users are logged out after container replacement.
Likely causeWEBUI_SECRET_KEY changed or the data volume was not persisted.
Verify the mounted data volume.Compare secret digest without printing it.
ResolutionRestore the stable secret and persistent volume; expect reauthentication if the key truly rotated.
The browser reports a WebSocket disconnect.
Likely causeReverse proxy upgrade headers or timeout behavior is incorrect.
Inspect browser network events.Review proxy and Open WebUI logs.
ResolutionApply the official reverse-proxy configuration and retest an active streamed chat.
HTTPS works but direct http://host:3000 also works externally.
Likely causeThe application port is bound to all interfaces or firewall permits it.
Check ss -lntp.Test from an external network.
ResolutionBind 127.0.0.1 only or remove host publication and allow only reverse-proxy traffic.
The first account is not the intended administrator.
Likely causeBootstrap was exposed before the operator enrolled.
Disable external access.Inspect user/admin records and logs.
ResolutionTreat it as an incident, preserve evidence and restore/reinitialize from a known clean state under the documented Open WebUI procedure.
An update starts but migrations fail.
Likely causeThe new image is incompatible with current data or resources.
Inspect update logs.Run the same image against a staging copy.
ResolutionStop production promotion and restore the prior image plus pre-update data snapshot.
Rolling back the image does not fix the application.
Likely causeThe database was migrated and is not backward compatible.
Compare data schema/update logs.Inspect the pre-update backup.
ResolutionRestore both prior image and matched pre-update data in an isolated recovery, then verify before cutover.
Backup archive exists but chats are missing.
Likely causeThe wrong volume or mount path was archived.
List archive paths.Inspect Docker volume mounts.
ResolutionBack up the actual /app/backend/data volume and require a restore smoke before acceptance.
Ollama becomes reachable on the LAN.
Likely causeOLLAMA_HOST or Docker port publication widened its bind.
Inspect Compose ports and service environment.Test 11434 externally.
ResolutionRemove publication, restore private binding/network and review access logs.
Model behavior changes after a pull.
Likely causeA mutable model tag resolved to new content.
Compare model manifest and digest.Run frozen prompts.
ResolutionRestore the approved model artifact/tag and require digest/eval review for lifecycle changes.
TLS certificate renewal fails.
Likely causeDNS, port reachability, clock or proxy storage is unhealthy.
Inspect proxy logs and certificate dates.Verify DNS and system time.
ResolutionRepair renewal prerequisites before expiry; use approved internal PKI for private deployments.
Open WebUI backup contains secrets in plain storage.
Likely causeBackup handling was treated as ordinary application data.
Classify archive contents.Review destination permissions and encryption.
ResolutionRestrict and encrypt storage, rotate exposed secrets and update backup policy.
Reference
Frequently asked questions
Is local inference automatically private?
No. It keeps model inference local, but plugins, external providers, web search, logs and backups may still transmit or retain data. Review the complete data flow.
Should I expose Ollama through the reverse proxy?
Usually no. Let Open WebUI reach it on a private network. Expose an API only with a separate authenticated and authorized gateway designed for that purpose.
Can I use the main or latest image tag in production?
Use it to discover an update, then record and deploy a reviewed immutable digest with a tested rollback. Rolling tags can move.
Do model files need backup?
They can often be pulled again, but retain a manifest and any custom model definitions. Decide whether backing up large blobs is faster and more reliable than redownloading under your recovery objective.
Recovery
Rollback
Stop public access, preserve the current failed state, restore the prior pinned images and matched pre-update Open WebUI data into a clean volume, restore the stable secret and model manifest, then reopen only after external acceptance.
- Block or drain HTTPS access and preserve current volume snapshot and logs under policy.
- Resolve the known-good release's image digests, secret digest, proxy config, model manifest and pre-update archive.
- Restore the archive into a new clean volume; never erase the only live volume first.
- Start the prior release on isolated loopback ports and verify admin login, data, WebSocket and model inference.
- Cut over to the restored volume/release, verify external TLS/auth and confirm 3000/11434 remain blocked.
- Keep failed artifacts for analysis, add the failure to staging acceptance and create a new release for correction.
Evidence