OmniRoute/contrib/vps
Praveen K Palaniswamy 65e81158ab
Some checks failed
Publish to Docker Hub / Resolve Docker release metadata (push) Has been cancelled
Release-Green (continuous) / Validate active release branch (push) Has been cancelled
Release-Green (continuous) / Validate main branch (push) Has been cancelled
Release-Green (continuous) / Bank ratchet shrinks (push) Has been cancelled
OpenSSF Scorecard / Scorecard analysis (push) Has been cancelled
semgrep / semgrep (push) Has been cancelled
opencode-plugin CI / Test (Node 22) (push) Has been cancelled
Radar Export / publish-export (push) Has been cancelled
Build App / Fast Production Build (push) Has been cancelled
CI / Change Classification (push) Has been cancelled
CI / PR Test Policy (push) Has been cancelled
opencode-plugin CI / Test (Node 24) (push) Has been cancelled
Wiki Sync / Sync wiki with docs (push) Has been cancelled
Publish to Docker Hub / Build Docker (linux/amd64) (push) Has been cancelled
Publish to Docker Hub / Build Docker (linux/arm64) (push) Has been cancelled
Publish to Docker Hub / Publish multi-arch manifests (push) Has been cancelled
CI / E2E Tests (4/9) (push) Has been cancelled
CI / E2E Tests (5/9) (push) Has been cancelled
CI / E2E Tests (6/9) (push) Has been cancelled
CI / E2E Tests (7/9) (push) Has been cancelled
CI / E2E Tests (8/9) (push) Has been cancelled
CI / E2E Tests (9/9) (push) Has been cancelled
CI / CI Dashboard (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Quality Ratchet (push) Has been cancelled
CI / Quality Gates (Extended) (push) Has been cancelled
CI / Docs Sync (Strict) (push) Has been cancelled
CI / Docs Lint (prose — advisory) (push) Has been cancelled
CI / i18n UI Coverage (push) Has been cancelled
CI / i18n Glossary (zh-CN, ko) (push) Has been cancelled
CI / i18n Validation (all languages) (push) Has been cancelled
CI / Unit Tests (2/8) (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Package Artifact (push) Has been cancelled
CI / Electron Package Smoke (ubuntu-latest) (push) Has been cancelled
CI / Electron Package Smoke (windows-latest) (push) Has been cancelled
CI / Unit Tests (1/8) (push) Has been cancelled
CI / E2E Tests (1/9) (push) Has been cancelled
CI / E2E Tests (2/9) (push) Has been cancelled
CI / Unit Tests (3/8) (push) Has been cancelled
CI / Unit Tests (4/8) (push) Has been cancelled
CI / Unit Tests (5/8) (push) Has been cancelled
CI / Unit Tests (6/8) (push) Has been cancelled
CI / Unit Tests (7/8) (push) Has been cancelled
CI / Unit Tests (8/8) (push) Has been cancelled
CI / E2E Tests (3/9) (push) Has been cancelled
CI / Bun SQLite Compatibility (push) Has been cancelled
CI / Bun SQLite Compatibility-1 (push) Has been cancelled
CI / Vitest (MCP / autoCombo / UI components) (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / SonarQube (push) Has been cancelled
CI / Integration Tests (1/2) (push) Has been cancelled
CI / Integration Tests (2/2) (push) Has been cancelled
CI / Ecosystem E2E (live server) (push) Has been cancelled
CI / PR Coverage Comment (push) Has been cancelled
CI / Security Tests (push) Has been cancelled
CI / Protocol Clients E2E (live server, advisory) (push) Has been cancelled
opencode-plugin CI / Build (push) Has been cancelled
fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00
..
.env.example fix(ollama): route models by advertised capability (#11088) 2026-08-23 11:45:01 -03:00
compose.yaml fix(ollama): route models by advertised capability (#11088) 2026-08-23 11:45:01 -03:00
README.md fix(ollama): route models by advertised capability (#11088) 2026-08-23 11:45:01 -03:00

Headless Linux VPS deployment

This bundle runs the published OmniRoute server image on a Linux VPS without the Electron desktop shell. It keeps the dashboard on loopback by default, does not publish Redis, persists application data, and adds conservative resource and log limits.

Use this bundle when the VPS only needs the API and web dashboard. The existing root-level Compose profiles remain the right choice for local development, building from source, bundled provider CLIs, or the Playwright/Chromium image.

Prerequisites

  • A supported Linux distribution with Docker Engine and Docker Compose v2.
  • At least 2 GiB of available RAM for the default limits. The host needs more headroom if other workloads run beside OmniRoute.
  • SSH access for the loopback dashboard tunnel.

Install

Build the headless server image from the exact release checkout. Building it locally avoids assuming that a matching version tag has already been published to a container registry:

git switch --detach release/v3.8.50
test "$(node -p "require('./package.json').version")" = "3.8.50"
docker build --target runner-base --tag omniroute:3.8.50-vps .

Then initialize the deployment from the repository root:

cd contrib/vps
cp .env.example .env
chmod 600 .env

Generate separate values for every secret, then paste them into .env:

openssl rand -base64 48  # JWT_SECRET
openssl rand -hex 32     # API_KEY_SECRET
openssl rand -base64 48  # OMNIROUTE_WS_BRIDGE_SECRET
openssl rand -base64 24  # INITIAL_PASSWORD

Do not reuse these values across installations. Keep REQUIRE_API_KEY=true. Keep OMNIROUTE_IMAGE on the locally built version tag, or replace it with an immutable registry digest; do not use the floating latest or next tags for unattended production.

Validate and start the stack:

docker compose config --quiet
docker compose up -d
docker compose ps

The dashboard is intentionally bound to 127.0.0.1. Reach it through SSH:

ssh -L 20128:127.0.0.1:20128 user@your-vps

Then open http://127.0.0.1:20128 locally. For a public hostname, put a trusted reverse proxy on the same host in front of the loopback port and terminate TLS there. Do not change OMNIROUTE_BIND_HOST to 0.0.0.0 merely to make the dashboard reachable.

Verify

docker compose ps
curl --fail --silent http://127.0.0.1:20128/healthz
docker compose logs --tail=100 omniroute

/healthz is a lifecycle probe. Use the authenticated monitoring/API routes for deeper provider validation after the first login.

Web-session providers on a VPS

Consumer web-session providers can enforce IP reputation, TLS fingerprint, or browser-session binding. A cookie copied on a workstation may therefore fail from a datacenter VPS even when the Linux container is healthy. In particular, Grok clearance cookies can be tied to the browser IP, User-Agent, and TLS fingerprint. Prefer official API credentials for unattended workloads. When a web-session provider is required, use only credentials from an account you own and follow that provider's guide; do not weaken TLS verification or bypass an access challenge.

Backup

Stop writes before copying SQLite data, then archive the named volume:

docker compose stop omniroute
mkdir -p backups
docker run --rm \
  -v omniroute-vps_omniroute-data:/data:ro \
  -v "$PWD/backups:/backup" \
  docker.io/library/alpine:3.23 \
  tar -C /data -czf /backup/omniroute-data.tar.gz .
docker compose start omniroute

Verify the archive before relying on it:

tar -tzf backups/omniroute-data.tar.gz >/dev/null

Store a timestamped copy outside the VPS. The fixed filename above is kept simple for copy/paste; rename it after each verified backup.

Update and rollback

Before updating, record the currently running immutable digest and take a verified backup:

docker image inspect "$(docker compose images -q omniroute)" \
  --format '{{index .RepoDigests 0}}'

Build the new local version tag first, or set OMNIROUTE_IMAGE in .env to a new immutable registry digest. Pull only when the selected image is remote, then recreate the application container:

# Registry images only: docker compose pull omniroute
docker compose up -d --no-deps omniroute
docker compose ps
curl --fail --silent http://127.0.0.1:20128/healthz

To roll back the application image, restore the previous value of OMNIROUTE_IMAGE and repeat the applicable pull and up commands. Restore the data archive only when a migration changed the persisted data and image rollback alone is insufficient. Keep the stack stopped while restoring the volume.

Remove the stack

docker compose down

This preserves both named volumes. docker compose down -v deletes persistent data and is intentionally not part of the normal uninstall path.