How NVMe-oF Boosts Server Storage Performance
Running your own AI chatbot used to mean sending every prompt, document and customer question to a third-party service, paying per message or per token, and hoping your data stays private. With a dedicated GPU server, you can skip all of that. In this guide, you will set up a private, ChatGPT-style assistant using Ollama (the engine that runs open-source language models on your NVIDIA GPU) and Open WebUI (a clean chat interface with user accounts, document upload and an OpenAI-compatible API for your own apps). Your prompts and files stay on your server, there are no usage limits, and your cost is simply the fixed price of the server.
We will build this on Ubuntu using Docker, so every component stays isolated, easy to update and easy to back up. You will install the NVIDIA driver and the NVIDIA Container Toolkit, run Ollama and Open WebUI with a single Docker Compose file, and put Caddy in front of them for automatic HTTPS. Only Caddy is exposed to the internet, while Ollama and Open WebUI stay on a private Docker network. The whole setup takes about 20 to 30 minutes, needs only copy-and-paste commands, and includes fixes for the most common errors, such as nvidia-smi failing or Ollama running on the CPU instead of the GPU.
❓ Do I need to install the full CUDA Toolkit on the host? No. This is the most common mistake. Ollama ships with the CUDA libraries it needs inside its Docker image. On the host you only need the NVIDIA driver plus the NVIDIA Container Toolkit.
Log in over SSH and update the system:
sudo apt update && sudo apt upgrade -yConfirm Ubuntu can see your GPU:
lspci | grep -i nvidiaYou should see a line with your GPU model. If nothing appears, the GPU is not detected: check with your hosting provider before continuing.
List the recommended driver for your GPU:
sudo ubuntu-drivers devicesInstall it automatically (this picks the recommended version):
sudo ubuntu-drivers autoinstallReboot:
sudo rebootAfter reconnecting, verify:
nvidia-smiYou should see a table showing your GPU name, driver version and VRAM. If you see it, the driver works.
⚠️ Secure Boot warning If Secure Boot is enabled in BIOS, the NVIDIA kernel module may refuse to load and nvidia-smi will fail. Either disable Secure Boot in BIOS/IPMI, or enroll a MOK key when the installer asks. See Troubleshooting, Problem 1.
curl -fsSL https://get.docker.com | sudo shAllow your user to run Docker without sudo:
sudo usermod -aG docker $USERLog out and log back in (or run newgrp docker), then test:
docker run --rm hello-worldThis is the piece that lets Docker containers use your GPU.
Add NVIDIA’s repository:
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L 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://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.listInstall it:
sudo apt update
sudo apt install -y nvidia-container-toolkitTell Docker to use the NVIDIA runtime, then restart Docker:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart dockerdocker run --rm --gpus all ubuntu nvidia-smiIf you see the same GPU table as in Step 2, GPU passthrough to Docker works. Do not continue until this test passes
mkdir -p ~/ai-server && cd ~/ai-servernano docker-compose.ymlPaste this:
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_KEEP_ALIVE=30m # keep model loaded in VRAM for 30 min
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
# No "ports:" section on purpose. Ollama has no login,
# so it must NOT be reachable from the internet.
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
depends_on:
- ollama
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY}
- ENABLE_SIGNUP=${ENABLE_SIGNUP:-true}
volumes:
- open_webui_data:/app/backend/data
caddy:
image: caddy:2
container_name: caddy
restart: unless-stopped
depends_on:
- open-webui
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
ollama_data:
open_webui_data:
caddy_data:
caddy_config:Save with Ctrl+O, Enter, then Ctrl+X.
Generate a random secret key:
echo "WEBUI_SECRET_KEY=$(openssl rand -hex 32)" > .env
echo "ENABLE_SIGNUP=true" >> .envOption A: with a domain (recommended, free automatic HTTPS). First point your domain’s DNS A record to your server IP, then:
cat > Caddyfile << 'EOF'
ai.yourdomain.com {
reverse_proxy open-webui:8080
}
EOFReplace ai.yourdomain.com with your real domain.
Option B: no domain (testing only, plain HTTP).
cat > Caddyfile << 'EOF'
:80 {
reverse_proxy open-webui:8080
}
EOFOnly SSH, HTTP and HTTPS are needed:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable⭐ Important: Docker can bypass UFW for any port you publish withports:. That is why Ollama has no published port in the compose file above. Never publish11434to the internet.
docker compose up -dCheck that all three containers are running:
docker compose psdocker exec -it ollama ollama pull llama3.1:8bTest it from the command line:
docker exec -it ollama ollama run llama3.1:8b "Explain what a dedicated server is in two sentences."While a model is loaded, run:
docker exec -it ollama ollama psLook at the PROCESSOR column:
100% GPU: Perfect: the whole model is in VRAM
40%/60%: Model is too big for VRAM, partly on CPU (slow). Use a smaller model or lower quantization
CPU/GPU: Model is too big for VRAM, partly on CPU (slow). Use a smaller model or lower quantization
100% CPU: GPU is not being used. See Troubleshooting, Problem 3
You can also watch GPU usage live in a second terminal:
watch -n 1 nvidia-smiVisit https://ai.yourdomain.com (or http://YOUR_SERVER_IP for Option B).
Otherwise anyone who finds your URL can sign up.
sed -i 's/ENABLE_SIGNUP=true/ENABLE_SIGNUP=false/' .env
docker compose up -d⚠️ Note In some Open WebUI versions, the signup setting is also stored in the admin panel after first start. If signups are still open, go to Admin Panel → Settings → General and turn off Enable New Sign Ups.
Rule of thumb for 4-bit quantized models (the Ollama default): model size in GB is roughly VRAM needed, plus 1 to 2 GB for context.
Your GPU VRAM: 6 to 8 GB
Comfortable model size: 3B to 8B
Example use: Chat, summaries, simple coding help
Your GPU VRAM: 12 to 16 GB
Comfortable model size: 8B to 14B
Example use: Better reasoning, coding
Your GPU VRAM: 24 GB
Comfortable model size: up to ~30B
Example use: Strong general assistant
Your GPU VRAM: 48 GB
Comfortable model size: up to ~70B
Example use: Near top-tier open models
Your GPU VRAM: 80 GB+
Comfortable model size: 70B+ with long context
Example use: Heavy or multi-user workloads
Browse available models at ollama.com/library and pull any with:
docker exec -it ollama ollama pull MODEL_NAME:TAGList installed models, and delete ones you no longer need:
docker exec -it ollama ollama list
docker exec -it ollama ollama rm MODEL_NAME:TAGOllama is OpenAI-compatible. Because we did not publish the port, call it from inside the Docker network, or temporarily test from the server itself:
docker exec -it ollama curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.1:8b",
"messages": [{"role": "user", "content": "Hello!"}]
}'For remote API access, put it behind an authenticated gateway or use a VPN such as WireGuard. Never expose raw Ollama to the internet.
Likely causes and fixes:
sudo reboot.mokutil --sb-state. If enabled, disable Secure Boot in BIOS/IPMI or enroll the MOK key.sudo apt install --reinstall linux-headers-$(uname -r)
sudo ubuntu-drivers autoinstall
sudo rebootnouveau driver is loaded. Check with lsmod | grep nouveau. If it shows, blacklist it:echo -e "blacklist nouveau\noptions nouveau modeset=0" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
sudo update-initramfs -u && sudo rebootThe NVIDIA Container Toolkit is missing or Docker was not configured. Re-run:
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart dockerThen retest: docker run — rm — gpus all ubuntu nvidia-smi
Work through this checklist in order:
nvidia-smi work on the host? If not, go to Problem 1.docker run --rm --gpus all ubuntu nvidia-smi work? If not, go to Problem 2.deploy.resources.reservations.devices block for the ollama service? Without it, the container gets no GPU.docker logs ollama 2>&1 | grep -i -E "gpu|cuda|vram"ollama ps. A split such as 30%/70% CPU/GPU means it is overflowing. Use a smaller model.This is a known issue on some Linux setups where the GPU driver state is lost. Try reloading the UVM module and restarting the container:
sudo rmmod nvidia_uvm && sudo modprobe nvidia_uvm
docker restart ollamaIf it keeps happening, make sure you are on a recent driver version and keep the system updated.
OLLAMA_BASE_URL=http://ollama:11434 is set and both containers are in the same compose project.docker compose ps and docker logs ollama.docker exec -it ollama ollama list.docker compose restart open-webui.dig +short ai.yourdomain.com.docker logs caddy.nvidia-smi shows processes using the GPU.ollama ps: if it is not 100% GPU, that is your cause.OLLAMA_KEEP_ALIVE=30m (already set) reduces this.You should not publish these ports. Remove any ports: entries for ollama and open-webui, then run docker compose up -d. Remember Docker bypasses UFW for published ports.
Update to the latest versions:
cd ~/ai-server
docker compose pull
docker compose up -d
docker image prune -fBack up your data (chats, users, settings):
docker run --rm -v ai-server_open_webui_data:/data -v $(pwd):/backup ubuntu \
tar czf /backup/open-webui-backup.tar.gz /data(The volume name is your folder name plus _open_webui_data. Check yours with docker volume ls.)
Useful daily commands:
docker compose psdocker compose logs -fdocker exec -it ollama ollama psdocker compose downdocker compose up -d nvidia-smiThat’s it! You now have a fully functional, private AI chatbot running on your own hardware. Your data is secure, you have an API ready for your own applications, and you completely avoid those expensive per-token API costs.
Self-hosting AI is incredibly rewarding, but it does require the right hardware to run smoothly. If you are currently looking for a reliable machine to host your models, we at MIG servers provide high-performance dedicated GPU servers that are perfectly suited for running Ollama and other heavy AI workloads.
Comments
Post a Comment