Deep-dive guide

Expose the Ollama API Safely with an API Key

Keep Ollama on localhost and put Caddy in front with an API key and HTTPS, so OpenAI-compatible clients can reach it from other machines and nobody else can.

Ollama's API has no authentication. Its docs say plainly that the local API at http://localhost:11434 does not require it. That is fine while Ollama listens only on 127.0.0.1, its default. Set OLLAMA_HOST=0.0.0.0 to reach it from elsewhere, though, and anyone who finds the port can run your models, pull new ones and delete the ones you have.

This guide keeps Ollama on loopback and puts Caddy in front of it, with HTTPS and an API key checked on every request. OpenAI-compatible clients already send a key: Ollama's docs say the client "requires an API key value, but Ollama ignores it". With the proxy, that key starts to count.

The Ollama self-host guide protects the API with a username and password (basic_auth). A bearer key suits API clients and SDKs better, because they send one without changes. Prefer one click? Deploy Ollama from the VeloxaHost marketplace.

What you need

  • Ollama installed as in the self-host guide, listening on its default 127.0.0.1:11434.
  • A domain or subdomain, such as ollama.example.com.
  • A dedicated IPv4 address. Caddy needs ports 80 and 443 to get a certificate and serve HTTPS. The shared IPv4 address every server gets has no 80 or 443, only a block of forwarded ports. A dedicated IPv4 is a paid add-on (the console shows the current price): choose it as "Network access" on the create page, or take one from the IP addresses page and attach it.

The proxy adds little load; size the server for the model, as in choosing a model size.

Keep Ollama on loopback

Check what Ollama listens on (ours):

ss -ltnp | grep 11434

The line should show 127.0.0.1:11434. If it shows 0.0.0.0 or *, an OLLAMA_HOST line is set: open the override with sudo systemctl edit ollama.service, delete it, then reload and restart as Ollama's FAQ describes:

sudo systemctl daemon-reload
sudo systemctl restart ollama

Do not forward a port of your block straight to 11434 either. Forwarded traffic arrives on the server's network interface, so it would need OLLAMA_HOST=0.0.0.0, the setup this guide avoids.

Put Caddy in front with a key

  1. Add the dedicated IPv4 to the interface and to the network configuration, as in the self-host guide, and create a DNS A record for ollama.example.com pointing at it. VeloxaHost has no IPv6 in US East, so add no AAAA record.

    ip addr add 198.51.100.5/32 dev eth0
    
  2. Install Caddy from its apt repository, as Caddy's install docs give it:

    sudo apt install --yes debian-keyring debian-archive-keyring apt-transport-https curl
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
    sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
    sudo apt update
    sudo apt install caddy
    
  3. Generate a key (ours):

    openssl rand -hex 32
    
  4. Replace /etc/caddy/Caddyfile with this (ours, built from Caddy's documented header and not matchers and its respond and reverse_proxy directives). The Host line is the one in Ollama's own proxy example:

    ollama.example.com {
        @no_key not header Authorization "Bearer <your key>"
        respond @no_key 401
    
        reverse_proxy localhost:11434 {
            header_up Host localhost:11434
            header_up -Authorization
        }
    }
    

    Caddy runs respond before reverse_proxy in its fixed directive order, so a request without the exact key gets a 401 and never reaches Ollama. header_up -Authorization drops the key before the request goes upstream, since Ollama does not use it. The key sits in the Caddyfile, so treat that file as a secret.

  5. Optionally, accept only known networks as well. Caddy's client_ip matcher with abort closes every other connection (ours, from Caddy's matcher example). Add these two lines at the top of the site block, with your own ranges:

    @outsiders not client_ip 203.0.113.0/24
    abort @outsiders
    
  6. Reload Caddy:

    sudo systemctl reload caddy
    

Caddy gets a Let's Encrypt certificate on its own once the A record points at the server and the ports are reachable.

Set the firewall

VeloxaHost firewalls are network-level and stateful. In the console, go to Firewalls, New Firewall, Add Rule. Allow TCP 22 only from YOUR.IP/32, TCP 80 from 0.0.0.0/0, and TCP 443 from 0.0.0.0/0, or only from your clients' addresses if they are fixed. Attach the firewall on the server's page; until one is attached, all traffic is allowed.

Keep port 80 open to everyone (ours, from Caddy's docs): Caddy's HTTP challenge needs port 80 reachable from outside to get and renew the certificate, so it keeps working even with 443 limited to your clients.

Connect your clients

Clients send the key in the Authorization: Bearer header. Ollama's native API and its OpenAI-compatible endpoints under /v1 both work through the proxy. This is Ollama's /v1/chat/completions example, pointed at the proxy with the header added (ours):

curl -X POST https://ollama.example.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your key>" \
-d '{
  "model": "llama3.2:3b",
  "messages": [{ "role": "user", "content": "Say this is a test" }]
}'

In OpenAI SDKs, set the base URL to https://ollama.example.com/v1/ and the API key to your key. The client sends it as the bearer token. Keep the key on servers and out of browser code, as Ollama's docs advise for its own keys: anything in a web page can be read by its visitors.

Verify it works

Call the list of models without the key, then with it:

curl -i https://ollama.example.com/api/tags
curl -H "Authorization: Bearer <your key>" https://ollama.example.com/api/tags

The first returns 401. The second returns your models as JSON. Then confirm that Ollama itself is not reachable from outside: from your own computer, a request to port 11434 on the server's address should time out (ours):

curl -m 5 http://198.51.100.5:11434/api/tags

Troubleshooting

A 401 with the right key. The header has to be exactly Bearer, one space, then the key, matching the Caddyfile. Check for a stray space or a missing reload.

Errors from Ollama through Caddy, but curl localhost:11434 works. Check the header_up Host localhost:11434 line, which Ollama's proxy example sets.

No certificate. Check that the A record resolves to the dedicated IPv4, the address is on the interface, and the firewall allows port 80 from everyone. Then read journalctl -u caddy.

The API returns 503. That comes from Ollama, not the proxy: its queue (OLLAMA_MAX_QUEUE, 512 by default) is full.

FAQ

Does Ollama have its own API keys?

Only for its cloud. Ollama's docs say direct cloud inference at https://ollama.com/api requires an API key, while the local API needs no authentication. A server you run gets its key check from the proxy in front of it.

Why not open port 11434 and limit it in the firewall?

A firewall rule limits where connections come from, not who makes them, and the traffic to Ollama stays unencrypted. The proxy adds HTTPS and a key, and the firewall can still limit addresses on top.

Can I give each client its own key?

Not with this short Caddyfile, which checks one key. Rotating it means editing the file, reloading Caddy and updating every client. For per-user accounts, put an application with its own users in front, such as Open WebUI.

Is basic_auth or a bearer key better?

Both are checked by Caddy over HTTPS. Use basic_auth from the self-host guide when people call the API with curl or a browser; use a bearer key when the callers are SDKs and tools built for the OpenAI API.

Commands and settings checked on 2026-10-19 against the official documentation: docs.ollama.com, caddyserver.com. Software changes; if a step no longer matches, the vendor's docs win.

Ready to deploy?

Start a free trial, or compare plans to match your team's scale.