home →
Get the free key
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 →