
If you want to install Ollama on Ubuntu and run it like a real service, use systemd. You get startup on boot, automatic restarts, and journald logs. You also get a clean place to apply resource limits and basic hardening.
This walkthrough uses a VPS-friendly setup with a safe bind address. Ollama listens on localhost, not the public internet.
If you need controlled remote access, you’ll add an optional Nginx reverse proxy.
The end result is an LLM runtime you can run on a VPS or dedicated server. It’s easy to monitor. It also won’t become an accidental public API.
What you’ll build (and what you won’t)
- Ollama installed on Ubuntu using the upstream installer
- A systemd service that starts on boot and restarts on failure
- Ollama bound to 127.0.0.1 by default (private by default)
- Practical logging, quick health checks, and basic hardening
You won’t get GPU acceleration in this guide. If you need GPU, use a GPU VPS or dedicated server and follow a CUDA/ROCm-specific setup.
Prerequisites and sizing notes for a VPS
This walkthrough targets Ubuntu Server on a VPS. Ubuntu 22.04 LTS and Ubuntu 24.04 LTS are both common in 2026. Either works well here.
- CPU: 4 vCPU minimum for comfortable interactive use; 8 vCPU is noticeably better for concurrency.
- RAM: 8 GB minimum; 16 GB is a safer baseline. CPU inference is memory-hungry, and the kernel page cache matters.
- Disk: plan for 20–60 GB free depending on how many models you pull. Models live under
/usr/share/ollamaby default.
If you’re starting from scratch, a HostMyCode VPS is a clean fit for a private AI assistant, internal search experiments, or an embeddings endpoint.
If you’d rather not babysit OS updates and baseline security, managed VPS hosting can cover the routine work.
Step 1: Prepare the server (packages, user, firewall)
Log in over SSH as a sudo-capable user.
ssh ubuntu@YOUR_SERVER_IP
Update packages. Then install a few tools for testing and reverse proxying.
sudo apt update
sudo apt -y upgrade
sudo apt -y install curl ca-certificates jq nginx
Run Ollama under a dedicated service account. Create a system user with no interactive shell.
sudo useradd -r -s /usr/sbin/nologin -m -d /var/lib/ollama ollama
If you use UFW, only open what you need. A typical setup allows SSH and HTTPS.
Ollama stays on localhost, so it doesn’t need a firewall rule.
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw --force enable
sudo ufw status
Hardening tip: if you already run Nginx, add brute-force protection. This pairs nicely with Set Up Fail2ban for Nginx on Ubuntu VPS.
Step 2: Install Ollama on Ubuntu
Use the upstream install script. It installs the binary and creates the required directories.
curl -fsSL https://ollama.com/install.sh | sudo sh
Confirm the binary is present:
ollama --version
which ollama
Next, decide where models should live. The default location is usually fine.
On smaller system disks, the model store can fill up quickly.
If you have attached storage (for example, mounted at /mnt/models), move models there. This keeps the root disk from getting crowded.
Optional: move the model store to a larger volume:
# Example: create a models directory on a larger disk
sudo mkdir -p /mnt/ollama
sudo chown -R ollama:ollama /mnt/ollama
In the next step, you’ll point the service at this path using OLLAMA_MODELS.
Step 3: Create a systemd service with a safe bind address
Don’t publish Ollama directly to the internet by default. Bind it to 127.0.0.1 so only local processes (like Nginx) can reach it.
Create a dedicated systemd unit:
sudo nano /etc/systemd/system/ollama.service
Paste this unit file:
[Unit]
Description=Ollama LLM runtime
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ollama
Group=ollama
# Safer default: bind to localhost only
Environment=OLLAMA_HOST=127.0.0.1:11434
# Optional: store models on a bigger disk
# Environment=OLLAMA_MODELS=/mnt/ollama
# If you run multiple services, raise file limits a bit
LimitNOFILE=1048576
ExecStart=/usr/local/bin/ollama serve
Restart=on-failure
RestartSec=2
# Basic sandboxing (keep it conservative to avoid breaking model storage)
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/var/lib/ollama
# If you use OLLAMA_MODELS on another path, add it here too:
# ReadWritePaths=/var/lib/ollama /mnt/ollama
[Install]
WantedBy=multi-user.target
Reload systemd and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now ollama
sudo systemctl status ollama --no-pager
Follow logs in journald:
sudo journalctl -u ollama -f
If the service dies immediately, it’s usually one of two things:
- (1) The unit points at the wrong binary path.
- (2) The service user can’t write to the models directory.
Fix ownership and restart:
sudo chown -R ollama:ollama /var/lib/ollama
sudo systemctl restart ollama
Step 4: Pull a model and run a quick test
With the daemon up, pull a small chat model to confirm everything works. On CPU-only VPS instances, smaller models keep response times reasonable.
Run the first model pull. Running this as your admin user is fine.
Ollama serves models system-wide:
ollama pull llama3
ollama list
Start an interactive prompt:
ollama run llama3
Or do a quick non-interactive check:
ollama run llama3 "Write a one-paragraph status page update about a planned maintenance window."
Health check the local API:
curl -s http://127.0.0.1:11434/api/tags | jq
Reality check: CPU inference slows down quickly as context grows or multiple users hit the service.
If this is going behind a chatbot, keep concurrency low. Otherwise, plan a move to GPU hardware.
Step 5: Put Ollama behind Nginx (recommended for controlled access)
Keeping Ollama on localhost is the safe default. When you need an HTTPS endpoint for apps, internal tools, or a private UI, put Nginx in front.
Nginx handles TLS, access control, and request sizing.
Create an Nginx site config. Replace ai-api.example.com with your domain.
sudo nano /etc/nginx/sites-available/ollama-api
Paste this (HTTP only for now; add TLS after you verify routing):
server {
listen 80;
server_name ai-api.example.com;
# Basic hygiene
client_max_body_size 20m;
# Optional: simple IP allowlist (recommended if you have fixed office IPs)
# allow 203.0.113.10;
# deny all;
location / {
proxy_pass http://127.0.0.1:11434;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Keep connections stable for streamed responses
proxy_buffering off;
proxy_read_timeout 300s;
}
}
Enable the site and test Nginx:
sudo ln -s /etc/nginx/sites-available/ollama-api /etc/nginx/sites-enabled/ollama-api
sudo nginx -t
sudo systemctl reload nginx
Test from your workstation:
curl -s http://ai-api.example.com/api/tags | jq
If you hit 413 Request Entity Too Large with larger prompts, increase client_max_body_size.
The underlying issue is the same as in Nginx 413 Request Entity Too Large Fix On VPS.
Step 6: Add HTTPS with Let’s Encrypt
For production, don’t serve an AI API over plaintext HTTP. Use Let’s Encrypt.
Install Certbot (Nginx plugin):
sudo apt -y install certbot python3-certbot-nginx
Issue a certificate:
sudo certbot --nginx -d ai-api.example.com
Certbot updates your server block and configures renewal. Verify renewal works:
sudo certbot renew --dry-run
If you’d rather use Caddy for automatic HTTPS, HostMyCode has a dedicated guide: Set Up Let’s Encrypt With Caddy for a VPS Site.
Step 7: Add basic auth (or use a tunnel) instead of an open endpoint
An unauthenticated LLM endpoint will get abused. At minimum, add authentication and rate limits.
For a straightforward setup, Nginx basic auth works well.
Create credentials:
sudo apt -y install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd ollamauser
Edit your Nginx site and add auth inside location /:
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
Reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
Test with curl:
curl -u ollamauser -s https://ai-api.example.com/api/tags | jq
If you need tighter controls (API keys, rate limiting, clearer separation), follow the approach in Secure vLLM API With Nginx, Keys, and Rate Limits.
Apply the same Nginx patterns to your Ollama upstream.
Step 8: Operational checks (logs, restarts, memory pressure)
Once this sits behind a real app, you’ll want quick answers during a slowdown or outage.
- Service status:
systemctl status ollama - Live logs:
journalctl -u ollama -f - Resource use:
top,htop(optional install),free -h
Watch for swap. Heavy swapping makes LLM workloads feel like the server is locked up.
free -h
vmstat 1
If swap stays active, reduce model size or context. You can also add RAM or move to a larger plan.
For an all-day feature, CPU-only sizing is often the limiting factor.
Step 9: Optional: expose Ollama safely to a private network only
Sometimes you want Ollama reachable from another server (for example, your web app VM). You still don’t want it public.
Two safe patterns:
- Private networking / VPN (recommended). Put the AI host behind a VPN like Tailscale/Headscale. See Self-Host Headscale on a VPS for Tailscale VPN.
- Bind to a private interface and firewall it strictly (only allow your app server’s IP).
If you do bind to a non-localhost address, update OLLAMA_HOST in /etc/systemd/system/ollama.service.
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart ollama
Be strict about this. A public bind without auth gets found quickly.
Common pitfalls (and quick fixes)
- Ollama works in your SSH session but not as a service: confirm the unit uses the correct binary path (
/usr/local/bin/ollamais common). Checkjournalctl -u ollama. - Permission errors while pulling models: the
ollamauser needs write access to the models path. Fix withchown -R ollama:ollama. - Nginx returns 502: Ollama isn’t running or is bound to the wrong address/port. Confirm with
curl http://127.0.0.1:11434/api/tags. If you need a systematic approach, see Nginx 502 Bad Gateway Fix on Ubuntu VPS. - Performance is unusable on CPU: switch to a smaller model, reduce context, or move to GPU hardware.
Where to go next
Once Ollama is stable under systemd, you can build on it without fighting your infrastructure.
- Private UI: Open WebUI or LibreChat behind HTTPS, so you’re not sharing raw API credentials with users.
- Embeddings: run an embeddings model and store vectors in Postgres or a dedicated vector DB for RAG.
- Website controls: if you’re also thinking about AI bots crawling your site, HostMyCode has a practical guide: Self-Host AI Crawlers Blocklist With robots.txt.
Summary
You now have a repeatable way to install Ollama on Ubuntu and run it as a first-class VPS service. systemd handles uptime, and journald captures logs.
Binding to localhost keeps the API private by default.
Add Nginx only when you need HTTPS access. Then layer authentication and limits.
If you want a predictable environment for self-hosted AI endpoints, start with a HostMyCode VPS. For heavier usage and tighter operational support, managed VPS hosting keeps routine maintenance covered while you focus on the app.
Ollama behaves much better as a service when the server underneath it stays stable. HostMyCode offers right-sized plans for self-hosted AI runtimes, from a basic HostMyCode VPS to managed VPS hosting where routine OS maintenance and monitoring are handled for you.
FAQ
Should I expose port 11434 directly to the internet?
No. Keep Ollama bound to 127.0.0.1 and publish it through a reverse proxy with HTTPS and authentication, or through a private VPN.
How do I change where Ollama stores models?
Set OLLAMA_MODELS in your systemd unit to a path on a larger disk (for example /mnt/ollama), ensure the ollama user owns that directory, then restart the service.
Why is it slow on my VPS?
CPU inference is latency-heavy, and RAM pressure makes it worse. Use a smaller model, reduce context, or move to a GPU-capable server for multi-user workloads.
How do I see what the service is doing?
Use sudo journalctl -u ollama -f for live logs and systemctl status ollama for unit health. For request-level visibility, log at the Nginx layer.
Can I run a web UI with this setup?
Yes. Keep Ollama local and run a UI like Open WebUI on the same VPS, or proxy to it with Nginx. This avoids exposing the raw API broadly.