norboten · cheat sheet

A proxy in front of a model is not a proxy in front of a web page — cheat sheet

ollama, ai-services, networking
# split the problem in two, first
curl -s -m 5 localhost:11434/api/tags     # the backend directly (exit 7 = could not connect)
curl -si -m 5 localhost:8080/api/tags     # through the proxy
sudo ss -lntp | grep ollama               # what is ACTUALLY listening, and on which port
sudo journalctl -u ollama -b --no-pager | tail
sudo tail -5 /var/log/nginx/error.log     # nginx names the upstream address it tried

# the service account and its model store
systemctl show -p User -p Environment --value ollama
chown -R ollama:ollama /srv/models ; chmod 755 /srv/models
sudo -u ollama ls /srv/models             # a permissions test
ollama list                               # a SERVER test: it is an HTTP client, it reads nothing from disk
find /srv/models \! -user ollama          # after any root-run maintenance: should be silent

# an nginx proxy for a model API
#   proxy_pass http://127.0.0.1:11434;   (NO trailing slash = pass the URI through unchanged)
#   proxy_http_version 1.1;              (default 1.0)
#   proxy_read_timeout 600s;             (default 60s: the max GAP between reads, not the total —
#                                          and a stream:false request is one long gap)
#   proxy_buffering off;                 (default on: nginx MAY hold and spool; off guarantees it won't)
#   proxy_send_timeout 600s ; proxy_request_buffering off ; client_max_body_size 32m
nginx -t && systemctl reload nginx ; sleep 1   # reload returns before the old workers are gone

# errnos in an upstream error
# 111 ECONNREFUSED  nothing is listening there
# 110 ETIMEDOUT     proxy_read_timeout ("while reading response header"), or a firewall dropping
#  13 EACCES        a policy: SELinux httpd_can_network_connect, or AppArmor

# reproduce a timeout on purpose: time the backend, then the proxy
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' localhost:11434/api/generate -d "$LONG"
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' localhost:8080/api/generate  -d "$LONG"
# a 504 whose time equals proxy_read_timeout is that timeout

# measure a stream instead of guessing: when did each line arrive?
curl -N -s localhost:8080/api/generate -d "$STREAM" | python3 -u /tmp/gaps.py
# log format: add $request_time $upstream_response_time