How to Deploy a Private AI Chatbot with Ollama and Open WebUI on Ubuntu (Docker)

Why run a private AI chatbot?

If you like the convenience of ChatGPT-style assistants but need better privacy, lower latency on your local network, or predictable costs, a self-hosted setup is a strong option. With Ollama you can run modern large language models (LLMs) locally, and with Open WebUI you get a clean web interface for chatting, managing models, and organizing prompts. In this tutorial you will deploy both on an Ubuntu server using Docker, so the install is repeatable and easy to maintain.

What you will build

By the end, you will have:

1) Ollama running as a service (the model runtime)
2) Open WebUI running in Docker (the chat UI)
3) Persistent storage for models and chat data
4) Optional GPU support notes if your server has NVIDIA

Prerequisites

Use an Ubuntu 22.04/24.04 server (VM or bare metal). A modern CPU and at least 8 GB RAM is workable for smaller models; 16–32 GB is more comfortable. You also need a user with sudo rights, outbound internet access to pull images/models, and Docker installed. If you plan to expose the UI beyond your LAN, put it behind a reverse proxy with TLS.

Step 1: Install Docker and Docker Compose

First, install Docker from Ubuntu’s repository (simple and reliable for most homelab and SMB setups):

Commands:
sudo apt update
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker

Add your user to the docker group so you can run Docker without sudo (log out/in after this):

Command:
sudo usermod -aG docker $USER

Step 2: Create folders for persistent data

Persistent volumes are important because LLM files can be large and you do not want to re-download models after every container update. Create a working directory:

Commands:
mkdir -p ~/ai-stack/ollama
mkdir -p ~/ai-stack/openwebui
cd ~/ai-stack

Step 3: Create a Docker Compose file

Create a file named docker-compose.yml in ~/ai-stack. This setup runs Ollama and Open WebUI on the same Docker network. Ollama will listen on port 11434 internally; Open WebUI will be published on port 3000.

docker-compose.yml:

Copy and paste:
version: "3.8"

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    volumes:
      - ./ollama:/root/.ollama
    ports:
      - "11434:11434"

  openwebui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: openwebui
    restart: unless-stopped
    depends_on:
      - ollama
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    volumes:
      - ./openwebui:/app/backend/data
    ports:
      - "3000:8080"

Step 4: Start the services

Bring the stack up in detached mode:

Command:
docker compose up -d

Verify containers are running:

Command:
docker ps

Step 5: Open the Web UI and pull a model

In a browser, open:

http://YOUR_SERVER_IP:3000

Open WebUI will ask you to create an admin account on first run. After login, you can download models through the interface, or you can pull models from the server side using Ollama.

To pull a popular small model (good for testing), run:

Command:
docker exec -it ollama ollama pull llama3.2

Once the model is downloaded, refresh Open WebUI and select the model for chat. If you want a lighter footprint, try smaller parameter models; if you need better answers, larger models require more RAM/VRAM.

Step 6: Basic troubleshooting (the common issues)

Open WebUI loads but shows no models: Confirm the environment variable points to Ollama. Run docker logs openwebui and make sure it can reach http://ollama:11434. Also verify Ollama is healthy with curl http://localhost:11434 on the host.

Model downloads are slow or fail: Check disk space (df -h) and DNS connectivity. LLM downloads can be multiple gigabytes, so a nearly full disk will cause strange errors.

High CPU and slow replies: This is normal on CPU-only servers with larger models. Use a smaller model, reduce concurrent users, or add GPU acceleration.

Optional: NVIDIA GPU acceleration notes

If you have an NVIDIA GPU, install the NVIDIA driver and the NVIDIA Container Toolkit so Docker containers can access the GPU. Then adjust the Ollama service to request GPU resources (exact configuration depends on your Docker and driver versions). GPU support can dramatically improve response time and allow you to run larger models smoothly.

Step 7: Keep it secure and maintainable

For a safer deployment, do not expose port 3000 directly to the internet. Put Open WebUI behind Nginx or Caddy with HTTPS and authentication. For updates, pull new images and recreate containers:

Commands:
cd ~/ai-stack
docker compose pull
docker compose up -d

Because you used persistent volumes, your downloaded models and chat database stay intact across updates.

Wrap-up

Running Ollama with Open WebUI on Ubuntu gives you a practical private AI chatbot you can use for internal documentation, code explanations, drafting emails, and brainstorming without sending prompts to a third-party cloud service. Start with a smaller model to confirm everything works, then scale up based on your hardware and the quality you need.

3.

Deploy a Private RAG Chatbot with Ollama and Open WebUI (No Cloud Required)

Why a private RAG chatbot?

If your team needs an internal chatbot that can answer questions from company documents, you’ve probably looked at cloud AI services. The problem is compliance: sending sensitive data outside your network can be a deal-breaker. A practical alternative is a private RAG setup (Retrieval-Augmented Generation), where a local language model generates answers while a local index retrieves relevant text from your own files. In this tutorial, you’ll build a private RAG chatbot on a Linux server using Ollama (local LLM runtime) and Open WebUI (a friendly chat interface), then connect your documents to it.

What you will build

You will deploy two services with Docker: Ollama to run a model locally, and Open WebUI to provide a web-based chat UI and document ingestion features. This approach is ideal for homelabs, IT departments, and helpdesk teams who want AI-assisted answers without exposing internal knowledge to third parties.

Prerequisites

You need a Linux server or VM (Ubuntu/Debian recommended) with at least 8 GB RAM for smaller models; 16 GB+ is better. Disk space depends on the model (expect several GB). You also need Docker and Docker Compose. If you have an NVIDIA GPU, you can accelerate inference, but this guide works on CPU as well.

Step 1: Install Docker and Docker Compose

On Ubuntu, install Docker with the official packages, then enable the service:

Commands:
sudo apt update
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

Log out and back in so your user can run Docker without sudo. Verify with:

Command:
docker version

Step 2: Create a Docker Compose file

Create a working directory and a compose file. This setup stores model files and WebUI data in persistent volumes so upgrades won’t wipe your configuration.

Commands:
mkdir -p ~/private-rag
cd ~/private-rag
nano docker-compose.yml

Paste the following content:

docker-compose.yml
version: "3.9"
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    volumes:
      - openwebui:/app/backend/data
    depends_on:
      - ollama

volumes:
  ollama:
  openwebui:

Step 3: Start the services

Bring the stack online:

Command:
docker compose up -d

Check that both containers are healthy:

Command:
docker ps

Open WebUI in your browser at http://YOUR_SERVER_IP:3000. The first account you create becomes the admin by default, so choose a strong password.

Step 4: Pull a model with Ollama

You can pull models directly inside the Ollama container. A good starting point for many servers is a smaller, fast instruct model.

Command:
docker exec -it ollama ollama pull llama3.1:8b

If your server has less RAM, try a smaller model. If you have more resources, you can experiment with larger variants for better reasoning. After pulling, confirm it’s available:

Command:
docker exec -it ollama ollama list

Step 5: Connect Open WebUI to the local model

In Open WebUI, go to the model selection menu and choose the model you pulled (for example, llama3.1:8b). Start a basic chat to confirm responses are generated locally. If it errors, verify that Open WebUI can reach Ollama on the internal Docker network and that the environment variable OLLAMA_BASE_URL matches the compose file.

Step 6: Enable RAG by adding your documents

To turn a general chatbot into a “knows our docs” assistant, ingest your content. In Open WebUI, find the section for Documents or Knowledge (wording may vary by version). Upload text-heavy sources such as internal runbooks, SOPs, FAQs, or exported wiki pages. For best retrieval results, prefer clean text formats like TXT, MD, PDF (machine-readable), and avoid scans without OCR.

After upload, Open WebUI will index the content so it can retrieve relevant chunks during chat. Test with a question that can only be answered from your document set, such as “What is our VPN reset procedure?” The response should cite or clearly reflect your internal wording. If the answer seems generic, add more targeted documents or refine your question.

Step 7: Secure access (quick hardening)

A private AI system can still leak data if it’s publicly exposed. First, bind access to trusted networks using a firewall (UFW on Ubuntu is simple) and consider putting Open WebUI behind a reverse proxy with HTTPS. Also, keep the service updated:

Commands:
cd ~/private-rag
docker compose pull
docker compose up -d

Finally, treat uploaded documents as sensitive: only allow authenticated users, and review what content is ingested. A RAG chatbot is powerful precisely because it can surface internal text quickly.

Troubleshooting tips

Model is slow: Use a smaller model, add RAM, or use GPU acceleration. Also reduce concurrent users.
WebUI can’t see the model: Confirm Ollama is running and reachable on port 11434 inside Docker, and that the model is listed in ollama list.
RAG answers are inaccurate: Upload more relevant documents, remove outdated versions, and prefer clean text sources. Retrieval quality depends heavily on document quality.

Next steps

Once your private RAG chatbot works, you can expand it by creating separate knowledge collections for different departments, adding a reverse proxy for SSO-like access control, or running multiple models for different tasks (fast model for chat, larger model for complex reasoning). This setup gives you a modern AI assistant while keeping your data inside your own environment.

Deploy Ollama + Open WebUI on Ubuntu with GPU Acceleration using Docker Compose

Running large language models locally is now practical and fast, especially with GPU acceleration. In this tutorial, you will deploy Ollama and Open WebUI on Ubuntu 22.04/24.04 using Docker Compose. This stack gives you a private, browser-based interface for modern LLMs (Llama, Mistral, Phi, etc.) with one-click model management and secure, self-hosted inference.

Why this stack?

Ollama simplifies downloading, quantizing, and serving LLMs on your machine. Open WebUI adds a clean chat interface, prompt templates, file uploads, and multi-user access. Together, they provide a robust local AI setup that is easy to update and portable across servers.

Prerequisites

- Ubuntu Server 22.04 or 24.04 (fresh system recommended)

- An NVIDIA GPU with recent drivers (T4, RTX 20/30/40, A-series, etc.)

- sudo access and an internet connection

- Optional: a domain name for HTTPS (e.g., ai.example.com)

Step 1 — Install Docker Engine and Compose

Install Docker from the official repository to ensure up-to-date features like GPU support in Docker Compose.

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose version

Step 2 — Enable GPU with NVIDIA Container Toolkit

Install the NVIDIA Container Toolkit to pass the GPU into containers. Verify that the host can see the GPU with nvidia-smi before proceeding.

# If you don't have drivers:
# sudo ubuntu-drivers install && sudo reboot

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit.gpg] https://#g' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit

# Configure Docker to use the NVIDIA runtime
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# Sanity check
nvidia-smi

Step 3 — Create the Docker Compose stack

We will run two services: Ollama (backend API on port 11434) and Open WebUI (frontend on port 3000) connected via a Docker network. The compose file also enables GPU support for Ollama.

mkdir -p ~/ollama-openwebui && cd ~/ollama-openwebui
cat > docker-compose.yml <<'YAML'
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama
    gpus: all
    environment:
      - OLLAMA_KEEP_ALIVE=1h
      - OLLAMA_HOST=0.0.0.0

  openwebui:
    image: ghcr.io/open-webui/open-webui:latest
    container_name: openwebui
    restart: unless-stopped
    depends_on:
      - ollama
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_AUTH=True
    volumes:
      - openwebui:/app/backend/data

volumes:
  ollama:
  openwebui:
YAML

Step 4 — Launch and access Open WebUI

Start the stack and watch logs for any errors. The first launch will pull images.

docker compose up -d
docker compose logs -f --tail=100

Open your browser to http://SERVER_IP:3000. Create the first admin user when prompted. Open WebUI will automatically detect Ollama via the internal URL and list available models.

Step 5 — Pull a model and test

Use either the WebUI model manager or the CLI to fetch models. The example below pulls a popular 7B model.

# Pull from the host (proxies into the container)
docker exec -it ollama ollama pull llama3.1:8b

# Quick API smoke test
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.1:8b",
  "prompt": "Say hello from a local LLM.",
  "stream": false
}'

In Open WebUI, select the model from the dropdown and start chatting. If you have enough VRAM, consider quantized larger models (e.g., 13B/70B Q4/Q5) for better reasoning.

Optional — Secure with a Caddy reverse proxy and HTTPS

If you have a domain, use Caddy to obtain and renew TLS automatically. This example exposes Open WebUI securely on port 443 and keeps Ollama private.

sudo apt install -y caddy
sudo tee /etc/caddy/Caddyfile >/dev/null <<'CADDY'
ai.example.com {
  encode zstd gzip
  reverse_proxy 127.0.0.1:3000
}
CADDY
sudo systemctl reload caddy

Point your DNS A/AAAA record to the server. Then visit https://ai.example.com. For teams, enable WebUI auth (already set) and create users from the admin settings.

Back up and update

To back up your models and chats, save the named volumes. You can also snapshot the folders from the host.

# Export volumes to tarballs
docker run --rm -v ollama:/v -v $(pwd):/b busybox tar czf /b/ollama-vol.tgz -C /v .
docker run --rm -v openwebui:/v -v $(pwd):/b busybox tar czf /b/openwebui-vol.tgz -C /v .

# Update images safely
docker compose pull
docker compose up -d

Troubleshooting

- No GPU detected: Ensure nvidia-smi works on the host. Re-run nvidia-ctk runtime configure, restart Docker, and verify the container sees the GPU:

docker exec -it ollama bash -lc 'nvidia-smi || ls -l /dev/nvidia*'

- Slow generation: Use quantized models (Q4_K_M/Q5_K_M), avoid oversize context windows, and confirm GPU is actually used (GPU utilization should rise in nvidia-smi during inference).

- Port conflicts: Change mapped ports in docker-compose.yml, e.g., "3001:8080" for Open WebUI or put a reverse proxy in front.

- Permission errors on volumes: Ensure your user is in the docker group and that the Docker daemon can write to the volume paths.

Security tips

- Keep Ollama bound to the internal network and only expose Open WebUI through TLS.

- Enable authentication (already set via WEBUI_AUTH=True). Use strong passwords and consider putting Open WebUI behind a VPN or SSO.

- Restrict firewall ports using UFW: allow 22/tcp and 443/tcp, then deny others.

Conclusion

You now have a GPU-accelerated, private AI stack with Ollama and Open WebUI on Ubuntu, orchestrated by Docker Compose. It is easy to upgrade, portable across servers, and suitable for personal research or team deployments. With this foundation, you can iterate quickly, evaluate new models as they drop, and keep your data fully on-prem.

Deploy Ollama and Open WebUI with NVIDIA GPU on Ubuntu 24.04 using Docker Compose

Overview

This tutorial shows how to self-host large language models locally by deploying Ollama and Open WebUI on Ubuntu 24.04 LTS with NVIDIA GPU acceleration using Docker Compose. Ollama handles model runtimes and downloads, while Open WebUI provides a friendly web interface, prompt management, and multi-user features. By the end, you will have a reproducible, GPU-enabled AI stack reachable from a browser on your LAN.

Prerequisites

Before you start, confirm: (1) Ubuntu 24.04 LTS installed and updated, (2) An NVIDIA GPU supported by recent drivers, (3) Administrative (sudo) access, and (4) Internet connectivity. If Secure Boot is enabled, you may need to enroll the NVIDIA kernel module signing key during driver installation.

Step 1: Prepare Ubuntu

sudo apt update && sudo apt -y upgrade
sudo apt -y install curl git ca-certificates gnupg

Step 2: Install the NVIDIA Driver

Use Ubuntu’s built-in tool to select the correct, current driver:

ubuntu-drivers list
sudo ubuntu-drivers autoinstall
sudo reboot

After reboot, verify the GPU is recognized:

nvidia-smi

Step 3: Install Docker Engine and Compose

Add the official Docker repository and install the engine plus the Compose plugin:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker

Step 4: Install NVIDIA Container Toolkit

This toolkit lets Docker containers access the GPU:

curl -fsSL https://nvidia.github.io/nvidia-container-toolkit/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit.gpg
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/nvidia-container-toolkit/$distribution/nvidia-container-toolkit.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt -y install nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Test GPU access in a container:

docker run --rm --gpus all nvidia/cuda:12.4.1-runtime-ubuntu22.04 nvidia-smi

Step 5: Create the Docker Compose project

Make a working directory and create your Compose file:

mkdir -p ~/ai-stack && cd ~/ai-stack

Create a file named docker-compose.yaml with the following content (indentation matters):

version: "3.9"
services:
ollama:
image: ollama/ollama:latest
restart: unless-stopped
ports:
- "11434:11434"
environment:
- OLLAMA_HOST=0.0.0.0
volumes:
- ollama:/root/.ollama
gpus: all

openwebui:
image: ghcr.io/open-webui/open-webui:latest
restart: unless-stopped
depends_on:
- ollama
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_NAME=MyLocalAI
volumes:
- openwebui:/app/backend/data

volumes:
ollama:
openwebui:

Step 6: Launch the stack

docker compose up -d

Wait a few seconds. Visit http://localhost:3000 (or http://SERVER_IP:3000) to open Open WebUI. The first user usually becomes the admin. You can manage models from the UI or the CLI.

Step 7: Pull a model and test

Pull a model into the Ollama volume (example: Meta’s Llama 3.1 8B):

docker compose exec ollama ollama pull llama3.1

Generate a quick response from the API:

curl -s http://localhost:11434/api/generate -d '{"model":"llama3.1","prompt":"Say hello from a local GPU!","stream":false}' | jq .response

In Open WebUI, choose the model from the dropdown and start chatting.

Step 8: Use the OpenAI-compatible API

Ollama exposes an OpenAI-style API under /v1. Example with Python’s OpenAI SDK:

pip install openai
python - <<'PY'
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.1",
messages=[{"role":"user","content":"Give me a one-line fun fact."}]
)
print(resp.choices[0].message.content)
PY

Maintenance and updates

To update images without losing your data or models stored in volumes, run:

cd ~/ai-stack
docker compose pull
docker compose up -d

To update or add models, use the UI or the CLI, for example: docker compose exec ollama ollama pull mistral.

Troubleshooting

nvidia-smi fails inside containers: Ensure the NVIDIA driver is installed and matches your GPU. Reboot after installation. Confirm Docker sees the GPU with docker run --rm --gpus all nvidia/cuda:12.4.1-runtime-ubuntu22.04 nvidia-smi.

Compose “gpus” not recognized: Check your Compose plugin version with docker compose version. Update Docker packages if outdated. As a fallback, configure the NVIDIA runtime as default and remove the gpus key: sudo nvidia-ctk runtime configure --runtime=docker --set-as-default && sudo systemctl restart docker.

Slow downloads or OOM: Models are large; use a fast, stable network and ensure enough VRAM and RAM. If a model does not fit your GPU, choose a smaller variant (e.g., llama3.1:8b or a quantized build like q4_K_M).

Security tips

Bind the services to your LAN or localhost by default and place them behind a reverse proxy with TLS if exposing over the internet. In Open WebUI, enable authentication and restrict new user registration if not needed. Consider a firewall rule to limit access to ports 11434 and 3000.

Remove the stack

To stop the containers while preserving data: docker compose down. To remove everything, including downloaded models and chat history: docker compose down -v.

You now have a modern, GPU-accelerated local AI stack that is easy to manage and update. The same approach works for additional services like vector databases or reverse proxies, making it a flexible foundation for on-prem AI experiments and production prototypes.

How to Configure Traefik v3 as a Docker Reverse Proxy with Automatic Let’s Encrypt on Ubuntu 24.04

Overview

This tutorial shows how to deploy Traefik v3 as a modern Docker reverse proxy with automatic Let’s Encrypt TLS certificates on Ubuntu 24.04. You will set up secure HTTPS for any containerized web app using Docker Compose, with zero manual certificate handling. The guide uses the HTTP-01 challenge for public A-record domains and includes a note on switching to the DNS-01 challenge for wildcard certificates.

Prerequisites

- A fresh Ubuntu 24.04 server with sudo access.

- A domain name with an A record pointing to your server’s public IP (for example, whoami.example.com).

- Ports 80 and 443 open on the server firewall and any upstream firewall or cloud security group.

Step 1: Install Docker Engine and the Compose plugin

Install Docker using the official repository to get current packages. This also installs the docker compose plugin.

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu noble stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker

Step 2: Prepare directories, permissions, and a Docker network

Create a project folder for Traefik and a persistent location to store ACME data. The acme.json file must be readable only by the Traefik process to keep private keys safe.

sudo mkdir -p /opt/traefik/letsencrypt
sudo touch /opt/traefik/letsencrypt/acme.json
sudo chmod 600 /opt/traefik/letsencrypt/acme.json
sudo chown -R $USER:$USER /opt/traefik
docker network create proxy
cd /opt/traefik

Step 3: Create an .env file

Store reusable variables in a .env file. Replace the placeholders with your real email and domain. The email is used by Let’s Encrypt for certificate notices.

cat > .env << 'EOF'
[email protected]
DOMAIN=example.com
EOF

Step 4: Write the Docker Compose file

The Compose file below pulls Traefik v3, configures HTTP-to-HTTPS redirection, enables the Docker provider, and uses the HTTP-01 challenge on port 80 to issue certificates. It also deploys a sample “whoami” app behind TLS at whoami.your-domain.

cat > docker-compose.yml << 'EOF'
version: "3.9"

networks:
  proxy:
    external: true

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy
    restart: unless-stopped

  whoami:
    image: traefik/whoami:v1.10
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`)
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.tls.certresolver=le
      - traefik.http.services.whoami.loadbalancer.server.port=80
    networks:
      - proxy
    restart: unless-stopped
EOF

Step 5: Start the stack and verify HTTPS

Bring the services online and watch Traefik’s first-run logs. The proxy will request and store certificates in acme.json. Ensure your DNS A record for whoami.example.com points to this server before you start.

docker compose up -d
docker logs -f traefik

When the logs show that certificates were obtained, browse to https://whoami.example.com. You should see a simple page from the whoami container over HTTPS. You can also test from the terminal:

curl -I https://whoami.example.com

Optional: Use DNS-01 for wildcard certificates

If you need a wildcard like *.example.com, switch to the DNS-01 challenge. This requires a DNS provider API token. As an example, for Cloudflare you would add two flags and an environment variable. Consult Traefik’s documentation for the exact variable names supported by your DNS provider.

# In docker-compose.yml, replace the HTTP-01 lines with:
      - --certificatesresolvers.le.acme.dnschallenge=true
      - --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare

# And add, under the traefik service:
    environment:
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}

# Then define it in .env (use a least-privilege token scoped to DNS edit):
CF_DNS_API_TOKEN=your_cloudflare_dns_token

After changing the challenge type, remove the old acme.json or start with a fresh file, then redeploy so Traefik can issue new certificates using DNS-01.

Security and maintenance tips

- Keep the Docker socket mount read-only, as shown, to reduce risk. Consider using a socket proxy if you expose Traefik to untrusted networks.

- Do not expose the Traefik dashboard publicly without authentication. If needed, put the dashboard behind a router with basic auth middleware and IP allowlists.

- Back up /opt/traefik/letsencrypt/acme.json. It contains your issued certificates and keys.

- Use a process manager (Compose restart policy is already set) and keep Traefik updated to the latest v3 patch release.

Troubleshooting

- If Let’s Encrypt fails, confirm that ports 80 and 443 are reachable from the internet and that your DNS A record is correct. The HTTP-01 challenge requires port 80 to reach the server.

- Check logs with docker logs -f traefik for clear error messages (rate limiting, challenge timeouts, or permission issues).

- Ensure acme.json permissions remain 600. Incorrect permissions can prevent Traefik from writing certificates.

- If labels do not seem to apply, verify that the whoami container is on the same Docker network named proxy and that exposedbydefault is false (which requires explicit traefik.enable=true).

You now have a production-ready reverse proxy on Ubuntu 24.04 with automatic HTTPS, simple app onboarding via labels, and a clean path to wildcard certificates when needed.

How to Run Local AI: Deploy Ollama and Open WebUI with NVIDIA GPU on Ubuntu via Docker Compose

Overview

This step-by-step guide shows you how to run a local AI stack on Ubuntu 22.04/24.04 using Docker Compose, Ollama, and Open WebUI with NVIDIA GPU acceleration. Ollama provides a lightweight local API for popular large language models (LLMs) like Llama 3, Mistral, and Qwen, while Open WebUI delivers a clean, user-friendly chat interface. By the end, you will have a secure, updatable setup that serves a local LLM with GPU support for fast responses and offline privacy.

Prerequisites

System: Ubuntu 22.04 or 24.04 with a recent NVIDIA GPU driver installed. Aim for at least 16 GB RAM and sufficient disk space (20–40 GB or more, depending on models). This tutorial uses Docker Engine, Docker Compose plugin, and the NVIDIA Container Toolkit.

Network/Ports: Ollama exposes port 11434 (local only in this guide). Open WebUI will use port 3000. Adjust firewall rules if the server is internet-facing.

1) Install Docker Engine and Compose

Run the following commands to install Docker and the Compose plugin:

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker

2) Enable NVIDIA GPU for Containers

Install the NVIDIA Container Toolkit so Docker can pass your GPU to containers. Make sure the host driver is already installed and nvidia-smi works on the host.

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Quick GPU test inside a container (optional):

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

3) Create Docker Compose for Ollama + Open WebUI

Create a working folder and a docker-compose.yml file:

mkdir -p ~/local-llm && cd ~/local-llm
nano docker-compose.yml

Paste the following content, then save:

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    volumes:
      - ollama:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=2h
    gpus: all
    ports:
      - "127.0.0.1:11434:11434"

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    depends_on:
      - ollama
    environment:
      - OLLAMA_API_BASE=http://ollama:11434
      - WEBUI_SECRET_KEY=change_me_long_random
      - ENABLE_SIGNUP=false
      - [email protected]
    volumes:
      - open-webui:/app/backend/data
    ports:
      - "3000:8080"

volumes:
  ollama:
  open-webui:

Binding Ollama to 127.0.0.1 keeps the model API private. Open WebUI is exposed on port 3000. For a remote VPS, secure it with a firewall or reverse proxy before exposing it.

4) Start the Stack and Pull a Model

Bring everything up:

docker compose up -d

Pull a model into Ollama (example: Llama 3.1 8B):

docker exec -it ollama ollama pull llama3.1:8b

Test the API locally:

curl http://127.0.0.1:11434/api/tags
curl http://127.0.0.1:11434/api/generate -d '{"model":"llama3.1:8b","prompt":"Say hello in one sentence."}'

Open your browser to http://SERVER_IP:3000 (or http://localhost:3000) to access Open WebUI and start chatting with the model you pulled.

5) Secure Access

If this runs on a server, restrict port 3000 to trusted IPs or place it behind HTTPS using a reverse proxy (Caddy, Nginx, or Traefik). For quick private access through SSH tunneling, use:

ssh -L 3000:localhost:3000 user@SERVER_IP

Set ENABLE_SIGNUP=false to prevent public registrations and choose a strong WEBUI_SECRET_KEY. You can also bind Open WebUI to localhost only by changing the port mapping to 127.0.0.1:3000:8080 and serving it via your reverse proxy.

6) Update, Backup, and Maintenance

Update images: keep the stack current with:

docker compose pull && docker compose up -d

Backup models and data: the named volumes hold your models and UI data. You can archive them like this:

mkdir -p ~/local-llm/backups && cd ~/local-llm
docker run --rm -v ollama:/data -v "$PWD/backups":/backup alpine sh -c 'tar czf /backup/ollama-vol.tar.gz -C /data .'
docker run --rm -v open-webui:/data -v "$PWD/backups":/backup alpine sh -c 'tar czf /backup/openwebui-vol.tar.gz -C /data .'

Stop/Start: docker compose down stops containers but keeps volumes. Use docker compose down -v to remove volumes as well (this deletes downloaded models and chat history).

7) Troubleshooting

GPU not detected: run nvidia-smi on the host; if it fails, reinstall the NVIDIA driver. Verify the container sees your GPU with docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi. Ensure you ran sudo nvidia-ctk runtime configure --runtime=docker and restarted Docker.

Slow or out-of-memory: choose a smaller or quantized model (for example, llama3.1:8b or mistral:7b). Large models need more VRAM. You can also run CPU-only by removing GPU options, but performance will drop.

Port conflicts: change the host ports in docker-compose.yml (e.g., "127.0.0.1:11435:11434" and "3001:8080"), then docker compose up -d.

Cannot access WebUI: confirm the container is healthy with docker ps and check logs via docker logs open-webui. If remote, verify firewall rules allow your IP to reach port 3000 or use SSH tunneling.

What You Achieved

You now have a modern, GPU-accelerated local LLM platform on Ubuntu using Docker Compose. Ollama handles model management and API requests, while Open WebUI provides a polished chat experience. This stack is easy to update, simple to back up, and private by default—ideal for development, helpdesk knowledge assistants, and secure, offline AI workflows.

Deploy Local AI on Ubuntu: Ollama + Open WebUI with NVIDIA GPU via Docker Compose

Overview

This step-by-step guide shows you how to deploy a fast, private, and GPU-accelerated AI chat on Ubuntu using two popular open-source tools: Ollama (model runner) and Open WebUI (user interface). We will use Docker Compose and the NVIDIA Container Toolkit so your NVIDIA GPU can accelerate large language models (LLMs) locally. By the end, you will have a browser-based chat UI running on top of a local model with persistent storage and easy updates.

Prerequisites

- A 64-bit Ubuntu 22.04 or 24.04 machine with an NVIDIA GPU (6–8 GB VRAM minimum recommended for smaller models, more for larger ones).
- SSH or terminal access with sudo privileges.
- Internet connectivity and at least 20 GB of free disk space.
- Basic familiarity with Docker.

1) Install NVIDIA Driver and Verify GPU

First, install the recommended NVIDIA driver. If you already have a working proprietary NVIDIA driver and the nvidia-smi command runs, you can skip to the next step.

sudo apt update
sudo ubuntu-drivers autoinstall
sudo reboot

After the reboot, confirm the driver:

nvidia-smi

You should see your GPU listed along with driver and CUDA versions. If not, fix the driver before continuing.

2) Install Docker Engine and Compose

Install Docker from the official repository to ensure you get the latest stable version.

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker

Validate Docker:

docker run --rm hello-world

3) Enable GPU in Containers (NVIDIA Container Toolkit)

Install the NVIDIA Container Toolkit to allow Docker containers to access your GPU.

distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/${distribution}/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Test GPU access inside a container:

docker run --rm --gpus all nvidia/cuda:12.3.2-base-ubuntu22.04 nvidia-smi

If the output shows your GPU, you are ready to proceed.

4) Create a Docker Compose Stack for Ollama + Open WebUI

Create a project folder and a docker-compose.yml file. This configuration runs Ollama (the model server) and Open WebUI (the frontend), shares data persistently, and enables GPU acceleration for Ollama.

mkdir -p ~/ai-stack && cd ~/ai-stack
nano docker-compose.yml

Paste the following Compose file:

version: "3.8"
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0
    gpus: all

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    depends_on:
      - ollama
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    volumes:
      - open-webui:/app/backend/data

volumes:
  ollama:
  open-webui:

Bring the stack online:

docker compose up -d
docker compose logs -f

Wait until both containers show as healthy or running without errors.

5) Pull a Model and Run Your First Prompt

Ollama downloads models on demand. Pull a popular, instruction-tuned model. Smaller or quantized models are best for GPUs with less VRAM.

# Example: Llama 3.1 8B Instruct
docker exec -it ollama ollama pull llama3.1:8b

# Lower VRAM option (quantized):
docker exec -it ollama ollama pull llama3.1:8b-instruct-q4_K_M

Test generation via API to confirm everything is working:

curl http://localhost:11434/api/generate \
  -d '{"model":"llama3.1:8b","prompt":"Say hello from a local GPU-accelerated LLM."}'

Open your browser to http://<server-ip>:3000, create an account when prompted, select the model you pulled, and start chatting.

6) Performance, Updates, and Autostart

- For best performance, use GPUs with higher VRAM and prefer models that match your hardware capacity. Quantized variants (e.g., q4_K_M) drastically reduce VRAM usage at a small quality trade-off.
- The Compose file uses restart: unless-stopped, so your stack will auto-start after reboots.
- To update images safely, run: docker compose pull && docker compose up -d. Your models and settings persist in the named volumes.

7) Troubleshooting

No GPU in container: Re-check nvidia-smi on the host, verify the NVIDIA Container Toolkit installation, and confirm the gpus: all setting in Compose. Retest with the CUDA container command above. Ensure Secure Boot is disabled if your driver fails to load.

Model fails to load: Choose a smaller or quantized build. For example, use llama3.1:8b-instruct-q4_K_M instead of a full precision model when VRAM is tight.

Port conflicts: Change the mapped ports in docker-compose.yml (for example, 3001:8080 for the UI or 11435:11434 for Ollama) and run docker compose up -d again.

Slow downloads: Models can be large (several GB). Ensure good bandwidth and enough disk space in Docker’s data root and volumes.

8) Security and Remote Access

By default, this setup is intended for local access. If you expose ports to the internet, secure them behind a reverse proxy with TLS (e.g., Caddy, Nginx, or Traefik), enable authentication in Open WebUI, and restrict access with a firewall or a VPN like WireGuard or Tailscale. Keep Docker and base images updated to benefit from security patches.

Wrap-up

You now have a modern, GPU-accelerated local AI stack on Ubuntu with a clean web interface, powered by Ollama and Open WebUI. This setup is easy to maintain, performs well on consumer GPUs, and keeps your data on your own hardware. Add or switch models as needed, tune quantization levels for your GPU, and enjoy private, fast AI inference without relying on external cloud services.

Deploy Ollama and Open WebUI on Ubuntu with NVIDIA GPU Using Docker Compose

Overview

This guide shows how to deploy Ollama (for running local LLMs) together with Open WebUI (a clean ChatGPT-like interface) on Ubuntu 22.04/24.04 using Docker Compose and an NVIDIA GPU. You will install Docker, enable GPU acceleration with the NVIDIA Container Toolkit, run both services, pull a model, and fix common errors. If you do not have a GPU, a CPU-only note is included.

Prerequisites

- Ubuntu 22.04 or 24.04 with sudo access.

- An NVIDIA GPU (Turing or newer recommended) with recent drivers (535+ works well) and at least 8 GB VRAM for medium models.

- Internet connectivity and ports 11434 (Ollama) and 3000 (Open WebUI) available.

Step 1: Verify and Install NVIDIA Drivers

Ensure a recent NVIDIA driver is installed and visible to the system. Check with: nvidia-smi. If it shows driver and GPU details, continue. If not, install a recommended driver and reboot:

sudo ubuntu-drivers install
sudo reboot

Step 2: Install Docker Engine and Compose Plugin

Set up the official Docker repository and install Docker plus the Compose plugin:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release; echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker

Step 3: Install NVIDIA Container Toolkit for Docker

This toolkit exposes your GPU to containers via Docker. Install and restart Docker:

distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Test that containers can see the GPU:

docker run --rm --gpus all nvidia/cuda:12.3.0-base-ubuntu22.04 nvidia-smi

Step 4: Create a Docker Compose File

Create a project directory, then a compose file:

mkdir -p ~/ollama-openwebui && cd ~/ollama-openwebui
nano docker-compose.yml

Paste the following content. This maps GPU to Ollama, persists data, and links the UI to the API.

services:
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama:/root/.ollama
environment:
- OLLAMA_KEEP_ALIVE=6h
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"]
# If your Docker Compose supports it, prefer: gpus: all
# gpus: all

open-webui:
image: ghcr.io/open-webui/open-webui:latest
container_name: open-webui
restart: unless-stopped
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- ENABLE_SIGNUP=false
volumes:
- openwebui:/app/backend/data
depends_on:
- ollama

volumes:
ollama:
openwebui:

Note: If your Compose version errors on deploy.resources..., upgrade Docker Compose and use gpus: all under the ollama service instead.

Step 5: Start the Stack and Pull a Model

Launch both containers:

docker compose up -d

Pull a model into Ollama (example: Llama 3.1 8B). You can pull from the host or exec into the container:

docker exec -it ollama ollama pull llama3.1:8b

Open your browser at http://<server-ip>:3000. Create an admin account on first run (if sign-up is disabled, enable it temporarily or set credentials via UI). Choose the model you pulled and start chatting.

Optional: CPU-Only Mode

If you do not have a supported GPU, remove the GPU settings and add OLLAMA_NO_GPU=1 to the ollama environment. Performance will be slower, so consider smaller models like llama3.1:8b-instruct or mistral.

Security, Updates, and Backups

- Network access: Do not expose port 11434 to the internet. Only expose 3000 (the UI) behind a reverse proxy like Nginx, Traefik, or Caddy with HTTPS.

- Authentication: Open WebUI supports local accounts. Disable public sign-ups by keeping ENABLE_SIGNUP=false and add users manually via the admin panel.

- Updates: Pull new images and recreate containers: docker compose pull && docker compose up -d.

- Backups: Save volumes with docker run --rm -v ollama:/v -v $PWD:/b busybox tar czf /b/ollama.tgz -C /v . and similarly for openwebui. Restore by reversing the process.

Troubleshooting

Open WebUI cannot connect to Ollama: Ensure OLLAMA_BASE_URL=http://ollama:11434 and that both services run on the same default Compose network. Check logs with docker logs open-webui.

GPU not visible in container: Confirm nvidia-smi works on host. Verify toolkit with docker run --rm --gpus all nvidia/cuda:12.3.0-base-ubuntu22.04 nvidia-smi. If Compose does not support GPUs, update to the latest Docker and use gpus: all or start Ollama once with docker run --gpus all to validate.

“could not load libcuda” or CUDA errors: Upgrade to a newer NVIDIA driver, restart Docker, and ensure nvidia-container-toolkit is correctly configured. Run sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker.

Permission denied on Docker: Add your user to the docker group (sudo usermod -aG docker $USER) and re-login.

Memory or OOM kills: Use smaller models, reduce concurrent sessions, or increase swap. You can also set OLLAMA_NUM_GPU=1 or adjust GPU split for multi-GPU hosts.

What’s Next

Explore model variants (LLM, vision, embedding) via Ollama’s registry, enable HTTPS with a reverse proxy, and connect automation via the compatible OpenAI API endpoints exposed by Open WebUI. With this setup, you get a fast, private, self-hosted AI chat experience backed by your own hardware.

How to Deploy Traefik v3 with Docker Compose and Automatic HTTPS via Cloudflare DNS-01

Overview

This tutorial shows how to deploy Traefik v3 as a modern reverse proxy with Docker Compose and automatic HTTPS certificates using Let’s Encrypt via the Cloudflare DNS-01 challenge. The DNS-01 method works even behind NAT, on residential ISPs, and with Cloudflare’s orange cloud (proxy) enabled. By the end, you will have a secure, production-ready reverse proxy and a sample container accessible over HTTPS.

Prerequisites

- A Linux server (Ubuntu 22.04/24.04 or similar) with Docker Engine and Docker Compose v2 installed.
- A domain managed by Cloudflare (nameservers pointing to Cloudflare).
- A Cloudflare API token with Zone.DNS:Edit and Zone:Read permissions for the zone you’ll use.
- Basic terminal access and a user with Docker privileges.

Step 1 — Verify Docker and Compose

Confirm your Docker setup is ready. Run: docker --version and docker compose version. If Compose v2 is not present, install the latest Docker Engine from the official repository. On Ubuntu, ensure the docker group exists and your user is a member: sudo usermod -aG docker $USER then re-log.

Step 2 — Create a Dedicated Docker Network

Create an external network so Traefik can share it with your app containers: docker network create proxy. Using a dedicated network helps isolate traffic and makes adding new services predictable.

Step 3 — Prepare Folders and Secrets

Make a working directory for Traefik and create a place to store ACME data (certificates):

mkdir -p ~/traefik/letsencrypt
cd ~/traefik
touch ./letsencrypt/acme.json
chmod 600 ./letsencrypt/acme.json

Create an .env file to hold your Cloudflare token securely. This file will be read by Docker Compose:

echo "CF_DNS_API_TOKEN=<paste_your_cloudflare_api_token>" > .env

The API token should include Zone.DNS:Edit and Zone.Zone:Read permissions for the domain. Restrict the token to the specific zone for better security.

Step 4 — Create docker-compose.yml

Create a docker-compose.yml file in ~/traefik with the following content. Replace [email protected] with your email and whoami.example.com with a real subdomain in your zone.

services:
  traefik:
    image: traefik:v3.1
    command:
     - --providers.docker=true
     - --providers.docker.exposedbydefault=false
     - --entrypoints.web.address=:80
     - --entrypoints.websecure.address=:443
     - --entrypoints.web.http.redirections.entrypoint.to=websecure
     - --entrypoints.web.http.redirections.entrypoint.scheme=https
     - [email protected]
     - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
     - --certificatesresolvers.letsencrypt.acme.dnschallenge=true
     - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare
     - --api.dashboard=true
    ports:
     - "80:80"
     - "443:443"
    environment:
     - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    volumes:
     - /var/run/docker.sock:/var/run/docker.sock:ro
     - ./letsencrypt:/letsencrypt
    networks:
     - proxy

  whoami:
    image: traefik/whoami:v1.10
    labels:
     - "traefik.enable=true"
     - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
     - "traefik.http.routers.whoami.entrypoints=websecure"
     - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
    networks:
     - proxy

networks:
  proxy:
    external: true

Create a DNS A/AAAA record for whoami.example.com pointing to your server’s public IP in Cloudflare. The orange cloud (proxy) can be ON or OFF; DNS-01 works either way.

Step 5 — Launch and Test

Start the stack from the ~/traefik directory: docker compose up -d. Traefik will request a certificate from Let’s Encrypt using the Cloudflare DNS-01 challenge. Check logs with docker compose logs -f traefik to confirm issuance (look for “Server responded with a certificate”).

Open https://whoami.example.com in your browser. You should see the whoami test service showing headers and IP details over HTTPS.

Optional: Secure the Traefik Dashboard

The dashboard is enabled but not published by default in this setup. To expose it safely, add labels to a new service or to Traefik itself using a distinct host like traefik.example.com, require basic auth middleware, and keep it behind TLS. Always disable --api.insecure=true in production.

Troubleshooting Tips

- If certificates do not issue, verify the API token has Zone.DNS:Edit and is scoped to the correct zone. Also confirm the .env is loaded and the environment variable name matches.
- If you see rate-limit errors, you may have requested too many certificates; wait and try again or use the Let’s Encrypt staging endpoint during testing (--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory).
- Ensure your firewall allows TCP 80 and 443 inbound to the server.

Maintaining and Adding Services

To add a new app behind Traefik, place it on the proxy network and attach labels for rule, entrypoint, and TLS resolver. Example labels: traefik.enable=true, traefik.http.routers.app.rule=Host(`app.example.com`), traefik.http.routers.app.entrypoints=websecure, and traefik.http.routers.app.tls.certresolver=letsencrypt. Restart only the new service; Traefik hot-reloads routes automatically.

Conclusion

With Traefik v3, Docker Compose, and Cloudflare’s DNS-01 challenge, you can ship secure containers with automatic HTTPS and minimal friction. This setup scales cleanly, keeps certificates current, and works in challenging network environments. Add your apps with labels, keep tokens scoped and secret, and enjoy a tidy, TLS-by-default container platform.

3.

Deploy Ollama + Open WebUI on Ubuntu 24.04 with Docker (GPU Optional)

Overview

This tutorial shows you how to deploy a fast, private, local AI stack on Ubuntu 24.04 using Docker Compose. We will run Ollama (which downloads and serves LLMs like Llama 3.1) together with Open WebUI (a friendly web interface) on port 3000. You will also learn how to enable optional NVIDIA GPU acceleration, set up persistence, and manage the stack with systemd for reliable startup at boot.

What you will build

You will create a two-container setup: Ollama provides the model runtime API on an internal network, and Open WebUI connects to it and exposes a browser UI at http://server-ip:3000. Data (models and chat history) is stored on Docker volumes so updates do not erase your content.

Prerequisites

- Ubuntu 24.04 LTS server or VM with 4+ GB RAM (more is better for larger models), 20+ GB free disk, and a user with sudo rights.

- Internet access to pull Docker images and models.

- Optional: An NVIDIA GPU with drivers if you want hardware acceleration.

Step 1 — Install Docker Engine and Docker Compose

Install Docker from the official repository (includes the compose plugin):

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose version

The last two commands verify that Docker and Docker Compose are installed correctly.

Step 2 — Optional: Enable NVIDIA GPU for containers

If your host has an NVIDIA GPU, install the driver and the NVIDIA container toolkit so Docker can access the GPU. Reboot after installing the driver if required.

# Install the recommended NVIDIA driver (reboot if prompted)
sudo ubuntu-drivers install

# Add NVIDIA Container Toolkit repository and install
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
  sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/$distribution/nvidia-container-toolkit.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list > /dev/null
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

To confirm GPU visibility, you can later run: docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi.

Step 3 — Create the Docker Compose project

Create a project directory and a compose file that defines two services, persistent volumes, and a port mapping for the web interface.

sudo mkdir -p /opt/ollama-webui
sudo chown -R $USER:$USER /opt/ollama-webui
cd /opt/ollama-webui

cat > compose.yaml <<'YAML'
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    volumes:
      - ollama:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=24h
    # Uncomment the next line if you've installed the NVIDIA container toolkit
    # and want GPU acceleration:
    # gpus: all

  open-webui:
    image: ghcr.io/open-webui/open-webui:latest
    container_name: open-webui
    restart: unless-stopped
    depends_on:
      - ollama
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    ports:
      - "3000:8080"
    volumes:
      - openwebui:/app/backend/data

volumes:
  ollama:
  openwebui:
YAML

This configuration keeps Ollama’s model files under the ollama volume and Open WebUI data (users, chats, settings) under openwebui. If you enabled GPU, remove the comment character in front of gpus: all.

Step 4 — Start the stack

Bring up both services in the background:

docker compose up -d
docker compose ps

Open a browser to http://<server-ip>:3000. The first load may take a moment while the UI initializes.

Step 5 — Pull a model and chat

You can download models from the web UI, or pull them directly via the Ollama container. For example, to grab a compact and capable model:

docker exec -it ollama ollama pull llama3.1:8b

Return to Open WebUI, select llama3.1:8b in the model picker, and start chatting. For better performance, use GPU acceleration if available, or choose a smaller model for CPU-only machines.

Step 6 — Start at boot with systemd (optional)

Use a systemd unit so your AI stack starts automatically after reboots.

sudo tee /etc/systemd/system/ollama-webui.service >/dev/null <<'UNIT'
[Unit]
Description=Ollama + Open WebUI (Docker Compose)
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/ollama-webui
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now ollama-webui
systemctl status ollama-webui --no-pager

The service will run docker compose up -d on boot and cleanly stop the stack on shutdown.

Updating and maintenance

To update to the latest images without losing data, run:

cd /opt/ollama-webui
docker compose pull
docker compose up -d

For logs and troubleshooting, use:

docker compose logs -f
docker logs ollama -f
docker logs open-webui -f

Troubleshooting tips

- If the UI does not load, confirm that port 3000 is open in your server’s firewall and that no other service is bound to it.

- If models fail to load due to disk space, expand your storage or prune unused images with docker image prune.

- If GPU acceleration does not work, verify the host’s nvidia-smi, then test GPU inside a container. Ensure gpus: all is enabled in compose.yaml and restart the stack.

- For remote exposure over HTTPS, place Open WebUI behind a reverse proxy (Caddy, Nginx, or a cloud tunnel) and restrict access with authentication.

You are done

You now have a modern, private AI chat environment running locally on Ubuntu 24.04. With Docker volumes for persistence, optional GPU acceleration, and systemd for auto-start, this setup is reliable and easy to maintain. Add or switch models anytime using Ollama, and enjoy a clean, fast interface with Open WebUI.

Deploy a Private Ollama + Open WebUI Stack with Docker (GPU or CPU)

Overview

This step-by-step guide shows you how to deploy a private local AI stack using Ollama and Open WebUI with Docker. Ollama runs language models locally (LLMs), and Open WebUI provides a friendly browser interface. The setup supports both NVIDIA GPUs for acceleration and CPU-only machines. You will get persistent storage, a clean Docker Compose file, and optional reverse proxy hardening.

Why this stack?

Running models locally gives you fast, private inference with full control. Ollama supports popular models like Llama 3, Mistral, and Phi 3. Open WebUI offers chat history, model switching, prompt templates, and a polished UX. Docker keeps everything reproducible and easy to update. With GPU enabled, throughput improves dramatically; without a GPU, it still works on modern CPUs.

Prerequisites

You need a 64-bit Linux host (Ubuntu 22.04+ recommended), macOS, or Windows with WSL2. Install Docker Engine and Docker Compose Plugin. If you have an NVIDIA GPU on Linux, install the proprietary driver and NVIDIA Container Toolkit so containers can see the GPU. Confirm Docker is functional with a simple hello-world container before proceeding.

Check your GPU (optional but recommended)

On Linux with NVIDIA, verify the driver and CUDA stack are working. The command below should list your GPU. If it fails, resolve driver issues before continuing.

nvidia-smi

Create a project directory

Create a working folder to store the Docker Compose file and your persistent volumes. The same directory will hold your reverse proxy config if you enable it later. For example, use ~/ollama-stack on Linux or a similar path on other systems.

Write the Docker Compose file

Save the following as docker-compose.yml. It defines two services: the Ollama model server and Open WebUI. Volumes ensure model files and chat history survive container updates.

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama-data:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=24h
    # GPU: uncomment this block if you have NVIDIA drivers and Container Toolkit installed
    # deploy:
    #   resources:
    #     reservations:
    #       devices:
    #         - driver: nvidia
    #           count: all
    #           capabilities: ["gpu"]

  open-webui:
    image: ghcr.io/open-webui/open-webui:latest
    container_name: open-webui
    restart: unless-stopped
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama
    volumes:
      - openwebui-data:/app/backend/data

volumes:
  ollama-data:
  openwebui-data:

Start the services

From the folder that contains docker-compose.yml, bring up the stack in the background. The first run will download images; future starts are much faster.

docker compose up -d
docker compose ps

Pull a model

Ollama does not ship with models. Pull one to get started. Llama 3 8B is a great baseline on consumer GPUs or modern CPUs. You can pull models through Open WebUI, but using the CLI is immediate and reliable.

docker exec -it ollama ollama pull llama3:8b
# Alternative models:
# docker exec -it ollama ollama pull mistral
# docker exec -it ollama ollama pull phi3

Open the interface

Visit http://localhost:3000 in your browser. On first load, Open WebUI initializes its database. Select your model (for example, llama3:8b) and start chatting. If you are accessing from another device on the LAN, replace localhost with the host’s IP address.

Enable GPU acceleration (Linux/NVIDIA)

If you have an NVIDIA GPU, install the NVIDIA Container Toolkit so Docker can pass the GPU into the container. After installation, uncomment the GPU block in the Compose file and redeploy. On CPU-only systems, keep the GPU configuration commented out; Ollama will fall back to CPU.

# On Ubuntu:
# 1) Install drivers via the "Additional Drivers" tool or:
# sudo apt-get update && sudo apt-get install -y nvidia-driver-535

# 2) Install NVIDIA Container Toolkit:
# sudo apt-get install -y nvidia-container-toolkit
# sudo nvidia-ctk runtime configure
# sudo systemctl restart docker

# 3) Recreate the stack:
docker compose down
docker compose up -d
# Validate GPU usage:
docker exec -it ollama nvidia-smi

Secure with a reverse proxy (optional)

If you plan to expose the interface on the internet, add a reverse proxy with TLS and HTTP Basic Auth. The example below uses Caddy for automatic HTTPS on a public domain. Replace example.com with your domain and set a strong username and password.

services:
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
    depends_on:
      - open-webui

# Caddyfile (place next to docker-compose.yml)
# example.com {
#   basicauth {
#     admin JDJhJDEwJHh5eXouLi4  # use `caddy hash-password --plaintext YOURPASS`
#   }
#   reverse_proxy open-webui:8080
# }

Persist and back up your data

Models and chat history live in Docker volumes named ollama-data and openwebui-data. Back them up by stopping the stack and using docker run --rm -v VOL:/data -v "$PWD":/backup alpine tar to archive each volume. Restoring is the reverse: create an empty volume and extract the tarball into it.

Update the stack

To update to the latest images, pull and recreate. Your data volumes remain intact. If a model gets corrupted or partially downloaded, remove it with ollama rm MODEL and pull again.

docker compose pull
docker compose up -d
docker exec -it ollama ollama list

Troubleshooting

If Open WebUI cannot reach Ollama, ensure the OLLAMA_BASE_URL uses the service name ollama (not localhost) inside Docker. If you see “could not select device driver with capabilities gpu,” the NVIDIA toolkit is missing or misconfigured; confirm nvidia-smi works on the host and restart Docker. If ports are already in use, change 11434 and 3000 in the Compose file to free ports. For slow responses on CPU, try smaller models (for example, llama3:8b-instruct) or quantized variants.

Performance tips

Use GPU when available for large models and higher throughput. Pin the model that matches your VRAM; 8B models typically fit in 8–12 GB of VRAM with quantization. Increase OLLAMA_KEEP_ALIVE to avoid cold starts. If running on SSD-backed storage, model loading is faster. On multi-user setups, place the stack behind a reverse proxy and consider segmenting access per user.

What you built

You now have a private, locally hosted AI chat interface backed by Ollama and Open WebUI, packaged with Docker for easy management. It runs fully offline, can leverage your GPU, and is simple to back up and update. From here, explore custom prompt templates, load additional models, or integrate the HTTP API for programmatic inference.

Deploy Ollama + Open WebUI on Ubuntu with Docker Compose (GPU Optional) and HTTPS

Overview

This guide shows you how to deploy Ollama and Open WebUI on Ubuntu using Docker Compose, with optional NVIDIA GPU acceleration and automatic HTTPS. You will get a clean, reproducible setup suitable for a home lab, a developer VM, or a small on-prem server. The steps are focused on Ubuntu 22.04/24.04 LTS, but will work on other modern distributions with minor changes.

What You Will Build

You will run three containers: Ollama (LLM runtime), Open WebUI (a friendly web front end), and Caddy (a reverse proxy that issues and renews free TLS certificates). Data will persist in Docker volumes so updates and restarts do not wipe your models or chat history.

Prerequisites

1) An Ubuntu server with at least 16 GB RAM recommended for medium models (more is better). 2) A domain or subdomain (e.g., ai.example.com) pointed to your server’s public IP (A/AAAA record). 3) Ports 80 and 443 open to the Internet. 4) Optional: an NVIDIA GPU with recent drivers for acceleration. 5) A non-root user with sudo.

Step 1 — Install Docker and Compose

Update the OS and install Docker Engine and the Compose plugin from Docker’s repository:

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER && newgrp docker

Step 2 — (Optional) Enable NVIDIA GPU for Containers

If you have an NVIDIA GPU, install the driver and the NVIDIA Container Toolkit so Ollama can use CUDA.

Install drivers: sudo ubuntu-drivers autoinstall, then reboot. Verify with nvidia-smi.

Install the container toolkit:

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) && \
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -fsSL https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Step 3 — Prepare the Project

Create a directory for your stack and move into it:

mkdir -p ~/ollama-stack && cd ~/ollama-stack

We will create a docker-compose.yml and a Caddyfile. Replace ai.example.com and your email as needed.

Step 4 — Docker Compose File

Create docker-compose.yml with the content below. If you have a GPU, keep the deploy.resources.reservations.devices section; otherwise you can remove it.

services:
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

openwebui:
image: ghcr.io/open-webui/open-webui:latest
container_name: openwebui
restart: unless-stopped
environment:
- OLLAMA_BASE_URL=http://ollama:11434
depends_on:
- ollama
volumes:
- openwebui_data:/app/backend/data

caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- openwebui

volumes:
ollama_data:
openwebui_data:
caddy_data:
caddy_config:

Step 5 — Caddy Reverse Proxy

Create Caddyfile with your domain. Caddy will automatically issue and renew a Let’s Encrypt certificate and proxy traffic to Open WebUI.

ai.example.com {
encode gzip
reverse_proxy openwebui:8080
}

Ensure your DNS A/AAAA record points to the server before continuing. If you only need local access, you can skip Caddy and access Open WebUI on http://SERVER_IP:8080 by publishing that port; however, TLS is strongly recommended.

Step 6 — Launch the Stack

Start everything with Docker Compose:

docker compose up -d

Watch the logs for any errors, especially domain or certificate issues:

docker compose logs -f caddy

After a minute, visit https://ai.example.com and complete the initial Open WebUI setup. In Settings, verify the Ollama endpoint is http://ollama:11434 (it should be pre-set from the environment variable).

Step 7 — Pull a Model and Test

You can pull and manage models via the Open WebUI interface, or via the CLI inside the Ollama container:

docker exec -it ollama ollama pull llama3.1
docker exec -it ollama ollama run llama3.1

If you enabled GPU support, Ollama should automatically leverage CUDA. You can confirm GPU usage with nvidia-smi while running a prompt.

Security and Hardening Tips

- Create an admin user in Open WebUI and do not expose the Ollama port 11434 to the Internet unless you really need the API externally. In the Compose file above, only Caddy is published publicly on 80/443, which is safer.

- Restrict access by IP or add basic auth in Caddy if you want a quick gate. Example inside your site block: basicauth { user JDJhJDEw$... } (generate hashes with caddy hash-password).

- Keep images updated: docker compose pull && docker compose up -d. Consider enabling automatic re-deploys on a schedule.

Performance Hints

- Use models that fit your VRAM/RAM. Smaller models like q4_K_M quantizations work well on modest GPUs and CPUs. For CPU-only servers, prefer 7B or smaller models.

- Set swap if RAM is tight: sudo fallocate -l 16G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile. Add to /etc/fstab for persistence.

- Place Docker volumes on fast storage (NVMe) for quicker model load times. You can bind-mount a directory like ./ollama:/root/.ollama if you prefer easy backups.

Backup and Restore

Back up the volumes for Ollama and Open WebUI to keep models and chat history. Example quick backup of models:

docker run --rm -v ollama_data:/data -v $(pwd):/backup alpine tar czf /backup/ollama-data.tgz -C /data .

Repeat similarly for openwebui_data. To restore, reverse the process by untarring into an identically named volume.

Troubleshooting

- If Caddy fails to get a certificate, verify your DNS record, that ports 80/443 are reachable, and no other service (like another web server) is binding them.

- If GPU is not detected, confirm nvidia-smi works on the host and that the nvidia-container-toolkit is installed. Restart Docker and the containers after changes.

- If Open WebUI cannot reach Ollama, ensure the environment variable points to http://ollama:11434 and that both containers share the same default network (they do in this Compose file).

Conclusion

You now have a production-grade, self-hosted LLM stack with Ollama and Open WebUI, managed by Docker Compose and protected by automatic HTTPS via Caddy. This setup is easy to maintain, portable across servers, and ready for experimentation or internal use. With GPU acceleration, you can serve sophisticated models efficiently; without a GPU, you can still run smaller quantized models for private inference. Keep your containers updated, monitor resource usage, and iterate on models that best fit your hardware and use cases.

How to Deploy Ollama and Open WebUI with NVIDIA GPU on Ubuntu using Docker Compose

Overview

This tutorial shows how to deploy Ollama (a lightweight local LLM runner) and Open WebUI (a clean chat interface) on Ubuntu using Docker Compose, with optional NVIDIA GPU acceleration. You will get a private, browser-based interface to run models like Llama 3 locally without sending data to the cloud. The steps work on Ubuntu 22.04/24.04. If you do not have a compatible NVIDIA GPU, you can still run everything on CPU.

Prerequisites

- Ubuntu 22.04 or newer (server or desktop)

- Sudo privileges

- For GPU acceleration: an NVIDIA GPU with recent drivers and CUDA support

1) Install Docker and Docker Compose

Install the Docker Engine and the Compose plugin in a few commands. You can also use official packages from Docker to stay current.

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
sudo apt-get install -y docker-compose-plugin
docker compose version

2) Install NVIDIA Container Toolkit (GPU only)

If you have an NVIDIA GPU, install drivers (if you have not already), then add the NVIDIA Container Toolkit so Docker can access the GPU.

# Install recommended NVIDIA drivers (reboot may be required)
sudo apt-get update
sudo apt-get install -y ubuntu-drivers-common
sudo ubuntu-drivers autoinstall
# After this finishes, reboot if drivers were installed/updated
# sudo reboot

# Add NVIDIA Container Toolkit repository and install
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# Configure Docker runtime and restart Docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Verify GPU access from Docker:

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

You should see your GPU listed. If not, ensure drivers are installed correctly and Docker has restarted.

3) Create the Docker Compose project

Create a working directory and a Compose file that runs two services: Ollama (backend API) and Open WebUI (frontend). The configuration below binds Ollama to localhost for safety and exposes Open WebUI on port 3000.

mkdir -p ~/ollama-openwebui
cd ~/ollama-openwebui
nano docker-compose.yml

Paste the following content. If you do not have a GPU, remove the runtime line and the NVIDIA environment variable in the ollama service.

version: "3.8"

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=24h
      - NVIDIA_VISIBLE_DEVICES=all
    runtime: nvidia

  open-webui:
    image: ghcr.io/open-webui/open-webui:latest
    container_name: open-webui
    restart: unless-stopped
    depends_on:
      - ollama
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_API_BASE=http://ollama:11434
    volumes:
      - open-webui:/app/backend/data

volumes:
  ollama:
  open-webui:

4) Start the stack

Bring everything up in the background and follow the logs to ensure both services are healthy.

docker compose up -d
docker compose ps
docker compose logs -f ollama

5) Pull and run a model

Use Ollama to pull a model such as llama3 (Meta’s Llama 3 8B). This downloads the model into the ollama volume. The first pull may take a while.

docker exec -it ollama ollama pull llama3
docker exec -it ollama ollama run llama3

You can also open the browser interface at http://<your-server-ip>:3000, choose Ollama as the provider (it should auto-detect), select or download a model, and start chatting. When a supported GPU is available, Ollama will automatically use it.

6) Secure and tune

Network access: By default, Ollama is bound to localhost and Open WebUI is exposed on port 3000. If this is a public server, restrict access with a firewall (UFW, security groups) or place Open WebUI behind a reverse proxy (Caddy, Nginx) with HTTPS.

Authentication: Open WebUI supports user accounts. Open the UI, create an admin, and disable open signups in Settings if you do not want others to register. For single-user setups, keep the service bound to a private network.

Model storage: Models are stored in the ollama named volume. To reclaim space, remove unused models with docker exec -it ollama ollama rm <model>.

Updates: Update to the latest images and restart:

docker compose pull
docker compose up -d

Troubleshooting

Docker cannot see the GPU: If --gpus all fails, confirm the NVIDIA driver is installed and loaded (nvidia-smi on host). Re-run sudo nvidia-ctk runtime configure --runtime=docker and sudo systemctl restart docker. Some older setups require a reboot after driver installation.

Address already in use: Change ports in the Compose file (for example, map Open WebUI to "127.0.0.1:3001:8080") if port 3000 is occupied.

CPU-only mode: If you have no GPU, remove the runtime: nvidia line and NVIDIA_VISIBLE_DEVICES environment variable from the ollama service. Performance will be lower but still usable for smaller models.

Slow inference: Use quantized models (e.g., llama3:8b-instruct-q4_0) and increase RAM/swap. On GPU, ensure you have sufficient VRAM; otherwise, use a smaller or more aggressively quantized model.

What you built

You now have a maintainable, containerized local AI stack with Ollama and Open WebUI on Ubuntu. This setup is easy to update, safe to run offline, and flexible enough to add more services later (embeddings, vector databases, or reverse proxies). Enjoy private, low-latency LLM chat on your own hardware.

Popular Posts

Install Ollama and Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Install Ollama + Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Install a Local AI Chatbot on Ubuntu 24.04 with Ollama and Open WebUI (Step-by-Step)

Trending Now

Recovering from Btrfs Boot Failures Using GUI Tools on Fedora

By the end of this guide the reader will be able to identify a Btrfs‑based Fedora installation, boot from a live USB, list and restore snapshots using the graphical utilities btrfs‑assistant and snapper, and verify that the system returns to a functional state without resorting to the command line. Understanding the Btrfs Layout Used by Fedora Fedora Workstation and Fedora KDE install the root filesystem as a single Btrfs partition that contains two default sub‑volumes. One sub‑volume holds the traditional “/” hierarchy, while the second is dedicated to /var/lib/machines . The latter exists to keep container images out of snapshot operations; it remains empty on systems that do not run virtual machines. Because Btrfs stores data in sub‑volumes rather than separate partitions, a snapshot captures the state of an entire sub‑volume at a point in time. The installer (Anaconda) automatically registers these sub‑volumes with the snapper service. Snapper maintains a series of read‑only ...