Why AI services are a target
Ollama's API has no password. Anyone who can reach port 11434 can run your models, fill your disk and use your CPU, and some versions have had security bugs. Automated scanners look for exposed AI services and other self-hosted tools continuously, so a service left open is usually found within hours or days.
The rule is simple. Services listen on 127.0.0.1 only. The only things reachable from the internet are your SSH port and, if you publish something, a reverse proxy with HTTPS and a login.
sudo ss -lntpBind each service to localhost
For a native Ollama install, make sure OLLAMA_HOST is not set to 0.0.0.0. The default is localhost. For containers, publish ports with the 127.0.0.1 prefix, as in 127.0.0.1:3000:8080. A mapping without the prefix opens the port to everyone.
systemctl show ollama -p Environment
sudo ss -lntp | grep 11434sudo docker ps --format "{{.Names}}\t{{.Ports}}" | grep -E "0\.0\.0\.0|\[::\]"Do not trust the firewall with Docker
UFW and firewalld rules do not protect ports published by Docker, because Docker inserts its own rules ahead of them. A closed port in your firewall status can still be open. Fix the publishing, rather than the firewall: bind to 127.0.0.1, or put the container on a private network with no published port, as the Open WebUI guide does for Ollama.
Still enable the host firewall for everything that is not Docker, and allow only SSH, 80 and 443.
sudo ufw status verbose 2>/dev/null
sudo firewall-cmd --list-all 2>/dev/nullReach private services over an SSH tunnel
The safest way to use a private service is to tunnel to it. The command below forwards port 3000 on your computer to port 3000 on the server through your normal encrypted SSH login. Nothing extra is exposed, and it works with the key-only SSH settings from the hardening guide.
ssh -N -L 3000:127.0.0.1:3000 deploy@YOUR_SERVER
# then open http://localhost:3000Publish through a reverse proxy with a login
If other people need to reach the service, publish it through Nginx with HTTPS as in the reverse proxy guide, and require a login. Open WebUI has its own accounts. Services without any login, such as a raw Ollama API, need one added. Basic authentication in Nginx is a simple option for a small private group.
Create a password file with htpasswd, which is in apache2-utils on Ubuntu and httpd-tools on AlmaLinux, then reference it in the Nginx location block.
sudo apt install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd alicesudo dnf install httpd-tools
sudo htpasswd -c /etc/nginx/.htpasswd aliceauth_basic "Private";
auth_basic_user_file /etc/nginx/.htpasswd;sudo nginx -t && sudo systemctl reload nginxLock down accounts and secrets
Turn off open registration after you create your admin account, use long unique passwords, and keep API keys and secret keys in files readable only by their owner, not in compose files that you share or paste into chats. Keep the system, Docker images and AI software updated, because these projects release security fixes often.
ls -l ~/openwebui/.env
chmod 600 ~/openwebui/.envsudo apt update && sudo apt upgradesudo dnf upgradecd ~/openwebui && sudo docker compose pull && sudo docker compose up -dTest from outside
Check from a different network, such as your phone on mobile data or another server, rather than from the VPS itself. These tests should all fail to connect. If one succeeds, the port is exposed.
curl -m 5 http://YOUR_SERVER_IP:11434/api/tags
curl -m 5 http://YOUR_SERVER_IP:3000/
curl -m 5 http://YOUR_SERVER_IP:8080/Watch resource use and logs
Unexpected CPU load, a full disk or unfamiliar models are signs of misuse. Check them from time to time, and install Fail2ban as described in the hardening guide. A small VPS that suddenly runs slowly is worth a look.
ollama list 2>/dev/null
sudo docker stats --no-stream 2>/dev/null
df -h /
sudo journalctl -u ollama --since "1 day ago" --no-pager | tail -n 20Official documentation
These upstream references provide more detail on the commands and workflows in this guide.