Runbook · self-hosting
Your box, your rules.
UPtrim ships as a single bundled binary — no Python, no pip, no virtualenv. This page is the long way round: a Linux server, a real domain, TLS you terminate yourself. If you just want your proxy reachable from your phone, read the box below and stop there.
The short way
Or skip all of this LIVE
UPtrim has remote access built in. Dashboard → Remote Access:
Cloudflare Tunnel
- One click for an instant
*.trycloudflare.com URL — no account needed
- Or sign in with Cloudflare in the browser and use your own hostname — the named tunnel and DNS route are created for you
- Install as an OS service so it survives reboots; a watchdog restarts it with exponential backoff
Tailscale
- One click publishes the proxy at
https://<machine>.<tailnet>.ts.net
- Sharing lives inside tailscaled, so it survives proxy restarts and reboots
- Turn on Funnel to make the URL public; headless boxes can use an auth key
Tunnels are a Standard tier feature ($5/mo). They give you HTTPS without owning a server, a domain, or a certificate. Requests arriving through a tunnel are always treated as remote — never mistaken for “local” — so the dashboard password still applies.
Step 1
Provision the box + DNS
Reference target: Ubuntu 24.04 LTS. UPtrim itself is modest — the GPU work happens on whatever LLM backend you point it at, which does not have to be this machine.
Server
- 2 vCPU, 2–4 GB RAM is enough for the proxy alone
- Open 80/443 in the firewall — and only 80/443
- SSH keys only, no password auth
- Give the data directory real local disk: SQLite on a network share or a cloud-synced folder is corruption-class, and the boot storage probe will warn you loudly about it
DNS
- A record
ai.your-domain.com → the VPS public IP - TTL 300 while you are still testing
- Add
downloads.your-domain.com too if you also plan to serve files (step 7)
Step 2
Install UPtrim
Download, unpack, run. There is no build step and nothing to install into a system Python.
ssh ubuntu@your-server-ip
sudo mkdir -p /opt/uptrim /var/lib/uptrim
sudo chown -R $USER:$USER /opt/uptrim /var/lib/uptrim
cd /opt/uptrim
curl -fLO https://dl.uptrim.dev/v1.0.0/UPtrim-1.0.0-linux-x86_64.tar.gz
tar -xzf UPtrim-1.0.0-linux-x86_64.tar.gz
# first run: creates the data directory and asks you to set the admin password
UPTRIM_DATA_DIR=/var/lib/uptrim ./ContextProxy --headless --host 127.0.0.1 --port 9099
Bind to 127.0.0.1 before you expose anything. The default is 0.0.0.0, which is right for a laptop and wrong for a public VPS — you want Nginx to be the only thing that can reach port 9099. --host pins it per run; you can also set it in the dashboard (System → it carries a RESTART badge) or in config.json inside your data directory. --headless skips the boot TUI and the browser it would otherwise open, neither of which a service unit has any use for. And yes — the binary is called ContextProxy; it is UPtrim’s engine.
Everything — database, config, uploads, backups — lives in one relocatable folder. UPTRIM_DATA_DIR pins it; otherwise Linux defaults to ~/.local/share/uptrim. Back that one folder up and you have backed up the whole install.
Step 3
Run it 24/7 with systemd
sudo tee /etc/systemd/system/uptrim.service >/dev/null <<'SERVICE'
[Unit]
Description=UPtrim proxy
After=network-online.target
Wants=network-online.target
[Service]
User=ubuntu
WorkingDirectory=/opt/uptrim
Environment=UPTRIM_DATA_DIR=/var/lib/uptrim
ExecStart=/opt/uptrim/ContextProxy --headless --host 127.0.0.1 --port 9099
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
SERVICE
sudo systemctl daemon-reload
sudo systemctl enable --now uptrim
sudo systemctl status uptrim
journalctl -u uptrim -f
UPtrim supervises its own subsystems — each one gets exponential backoff from 30 s up to 15 minutes, then quarantine, with the severity surfaced on the dashboard. Restart=always is only there for the process dying outright.
Step 4
Put Nginx in front
Two things matter here and both are easy to get wrong: streaming must not be buffered, and uploads must not be truncated.
sudo apt update
sudo apt install -y nginx
sudo tee /etc/nginx/sites-available/uptrim >/dev/null <<'NGINX'
server {
listen 80;
server_name ai.your-domain.com;
# file uploads — raise to match your tier's per-file ceiling
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:9099;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# token-by-token replies die behind a buffer
proxy_buffering off;
proxy_read_timeout 600s;
}
}
NGINX
sudo ln -s /etc/nginx/sites-available/uptrim /etc/nginx/sites-enabled/uptrim
sudo nginx -t
sudo systemctl reload nginx
Leave proxy_buffering on and every streamed reply arrives in one lump at the end. Set client_max_body_size below your per-file limit and large uploads fail with a confusing 413 instead of a real error.
Step 5
Add HTTPS (Let's Encrypt)
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d ai.your-domain.com
# confirm the renewal timer is armed
sudo systemctl status certbot.timer
Certbot rewrites the server block above to listen on 443 and redirect 80. Your proxy is now reachable at https://ai.your-domain.com/v1 — that is the base URL you paste into Open WebUI, SillyTavern, or any OpenAI-compatible client.
Step 6
Prefer Caddy? Two lines.
ai.your-domain.com {
reverse_proxy 127.0.0.1:9099 {
flush_interval -1 # stream immediately, never buffer
}
}
Caddy fetches and renews the certificate itself. flush_interval -1 is the Caddy equivalent of turning Nginx's buffering off — without it, streaming breaks the same way.
Step 7
Identity behind a proxy
This is the part people lose an evening to. Once a reverse proxy sits in front, every request arrives from 127.0.0.1 — so UPtrim has to be told whose header to believe.
Open WebUI
Set ENABLE_FORWARD_USER_INFO_HEADERS=true in Open WebUI's environment. Without it, Open WebUI never sends who the user is, and everyone shares one memory pool. This is the single most common setup problem.
trusted_proxies
Comma-separated list of IPs allowed to identify users. Defaults to ::1,127.0.0.1. If Open WebUI runs on a different machine than the proxy, add that machine's IP here.
trust_owui_headers
auto trusts identity headers only from localhost and trusted IPs. Set it to always when traffic arrives through a Cloudflare Tunnel. never ignores them entirely.
Forwarded headers are checked for spoofing, and a request that came through a tunnel or reverse proxy is never mistaken for a local one — the dashboard password applies from everywhere, including localhost. If you want signed identity, set owui_hmac_secret and unsigned headers get rejected in strict mode.
Step 8 · optional
Also serving your own release files
Unrelated to running the proxy — this is for publishing installers from your own domain.
sudo mkdir -p /var/www/uptrim/releases
sudo chown -R $USER:$USER /var/www/uptrim
# from your local machine
scp UPtrim-1.0.0-Setup.exe ubuntu@your-server-ip:/var/www/uptrim/releases/
scp UPtrim-1.0.0-linux-x86_64.tar.gz ubuntu@your-server-ip:/var/www/uptrim/releases/
sudo tee /etc/nginx/sites-available/uptrim-downloads >/dev/null <<'NGINX'
server {
listen 80;
server_name downloads.your-domain.com;
root /var/www/uptrim;
autoindex off;
location / {
try_files $uri $uri/ =404;
}
}
NGINX
sudo ln -s /etc/nginx/sites-available/uptrim-downloads /etc/nginx/sites-enabled/uptrim-downloads
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d downloads.your-domain.com
Caddy does the same thing in four lines:
downloads.your-domain.com {
root * /var/www/uptrim
file_server
}
Step 9
Basics worth not skipping
Checksums
sha256sum /var/www/uptrim/releases/*
Publish them next to the files so people can verify what they downloaded.
Rate limits
Nginx limit_req in front of the download host mitigates scraping. UPtrim enforces its own per-user request limits separately, sized by your scale profile.
Backups
One-click backup and restore lives in the dashboard, but a cron'd copy of UPTRIM_DATA_DIR off the box is what saves you when the box does not come back.
Running several proxies against one shared memory database is a different job — that is the multi-node fleet, available for Business and Enterprise deployments. Read the fleet story →