---
title: "Deploy OmniRoute"
description: "OmniRoute [Oct'26] — one OpenAI-compatible endpoint, your provider keys"
category: "AI/ML"
url: https://railway.com/deploy/omniroute-llm-gateway
---

# Deploy OmniRoute

OmniRoute [Oct'26] — one OpenAI-compatible endpoint, your provider keys

**[Deploy OmniRoute on Railway](https://railway.com/template/omniroute-llm-gateway)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/omniroute-llm-gateway/manifest.json

- **Creator:** SB
- **Category:** AI/ML

## Template content

### Redis https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg

- **Image:** redis:8.2
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### OmniRoute https://cdn.jsdelivr.net/gh/selfhst/icons/svg/omniroute.svg

- **Image:** diegosouzapw/omniroute:latest
- **Public domain:** Yes

## Documentation

# Deploy and Host OmniRoute on Railway

OmniRoute is an open-source AI gateway: one OpenAI-compatible endpoint in front of every LLM provider you use, with a dashboard for provider credentials, per-app keys, model aliases and fallback rules. Point your tools at one base URL instead of maintaining provider-specific integrations in each. This template deploys it with Redis, a volume mounted where the keys actually land, and the routing behaviour documented rather than assumed.

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| `omniroute` | Gateway and dashboard on port `20128`. Public HTTPS domain. |
| `Redis` | Routing state, rate limiting and runtime cache. |
| Volume | Provider definitions, generated API keys and configuration. |

Both services talk over Railway's private network. The volume holds the only thing expensive to recreate: every provider you have configured and every key you have entered.

## About Hosting

A gateway makes many providers look like one endpoint. The cost of that convenience is that it also becomes one place where your requests can change and one place where all your keys live.

**The model that answers may not be the model you asked for.** Quota-aware fallback and circuit breakers are the point of a gateway — when a provider rate-limits or errors, the request goes elsewhere. So a request you priced against one model can be served by another, with different cost per token and different output quality. Read the `model` field in responses, and build fallback chains only from models you would accept interchangeably.

**Prompt compression is lossy, and applied before the model sees your text.** Useful for bulk summarisation and long-context cost control; a correctness risk for few-shot prompts, structured extraction and anything where exact wording carries meaning, because the model receives something other than what you wrote. Leave it off until you have measured its effect on your own outputs.

**The dashboard is a bigger target than the endpoint.** Securing `/v1` with a generated key solves half the problem. The dashboard holds the provider credentials themselves, so a weak admin password does not leak one key — it leaks your OpenAI, Anthropic and Gemini accounts at once. Set `INITIAL_PASSWORD` long and random before the domain resolves; a public Railway URL is discoverable the moment it exists.

**The volume path and the application's data path are not the same string.** The app's internal setting points at `/app/data`; the Railway volume mounts at `/data`. Use the wrong one and the deployment looks healthy, the dashboard works, and every provider and key vanishes on the next redeploy. Confirm the mount before entering a single credential.

**Pin the tag.** The official image publishes `latest`, and a gateway sitting between your applications and every model you call is the wrong component to let change on its own schedule. Pin a version you have tested and bump it deliberately.

**A gateway is a shared point of failure.** Before it, a provider outage broke calls to that provider. After it, a gateway outage breaks every call you make. Usually a worthwhile trade for the operational simplicity — but a trade, and worth knowing you made it.

Typical cost: **~$10–20/month** for the gateway and Redis at $10/GB/month RAM, $20/vCPU/month CPU and $0.15/GB/month volumes. Half a gigabyte is not enough headroom for this image. Inference bills to your own provider accounts.

## How It Compares

| | OmniRoute | LiteLLM | OpenRouter | Direct SDKs |
| --- | --- | --- | --- | --- |
| Hosting | Self-hosted | Self-hosted | Vendor | None needed |
| Budgets and spend tracking | Basic | Strong, per team | Built in | None |

The honest edge: LiteLLM is the more complete gateway if you need per-team virtual keys, budgets and spend attribution — the right answer for an organisation rather than a developer. OpenRouter removes the operations entirely if you will pay a margin and let someone else hold the routing. OmniRoute sits between: a dashboard-driven gateway that is quick to stand up, with your keys on infrastructure you control. Pick it for a small team or a personal stack, not as billing infrastructure.

## Deploy in Under 5 Minutes

1. Click **Deploy** and pick a workspace. **Set `INITIAL_PASSWORD` here** — it becomes your dashboard login on first boot and it guards every key you are about to enter.
2. Confirm the volume is mounted at `/data` before adding anything, and give the service more than half a gigabyte of memory.
3. Open the dashboard, sign in, and add one provider key.
4. Generate a per-application key and point a client at `https://your-domain/v1` with it. Send one request.
5. Check the response's `model` field matches what you requested — that tells you routing is behaving before you build on it.

> Verify before you rely on it: redeploy, then reopen the dashboard. If your provider is still configured, the volume is mounted correctly. If it is empty, stop and fix the mount path rather than re-entering keys.

## Common Use Cases

- **One base URL for every tool** — point coding agents, scripts and apps at a single endpoint instead of configuring each separately.
- **Provider failover** — keep working when one provider rate-limits, with fallback to a model you have deliberately chosen as acceptable.
- **Per-application keys** — issue and revoke a key per tool without touching the underlying provider credentials.

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `INITIAL_PASSWORD` | Required | Dashboard login, applied on first boot. Guards every provider key. |
| `BASE_URL`, `NEXT_PUBLIC_BASE_URL` | Auto | Public Railway domain the app reports for itself. |
| `REDIS_URL` | Auto | Reference variable on the private Redis hostname. |
| Storage volume | Pre-set | Mounted at `/data`, holding providers, keys and configuration. |

> **Set `INITIAL_PASSWORD` before the first deploy.** It applies on first boot only, and the dashboard behind it holds the credentials to every provider account you connect.

> **Do not confuse `DATA_DIR` with the volume mount point.** They are different paths, and getting it wrong produces a gateway that works perfectly until the next redeploy wipes every provider you configured.

## Dependencies for OmniRoute Hosting

- **Railway account** — ~$10–20/month for the gateway and Redis; more than 0.5 GB of memory is required.
- **Bundled services** — Redis for routing state and rate limiting, wired over private networking.
- **Volume** — required, for provider definitions, generated keys and configuration.
- **Provider accounts** — your own keys for whichever models you route to. OmniRoute supplies no inference itself.

### Deployment Dependencies

- [OmniRoute on GitHub](https://github.com/diegosouzapw/OmniRoute)
- [OmniRoute Docker image](https://hub.docker.com/r/diegosouzapw/omniroute)
- [Railway private networking](https://docs.railway.com/networking)
- [Railway volumes](https://docs.railway.com/volumes)

### Implementation Details

The gateway runs the official image on a pinned version rather than `latest`, serving port `20128` behind Railway's HTTPS edge, with Redis reached by private hostname through a reference variable. Redis carries routing state, rate-limit counters and cache — all reconstructible. The volume carries provider definitions, the encrypted key store and configuration, none of which is. Treating the two as interchangeable is how people end up with a gateway that survives a restart and loses its credentials.

The mount point deserves its own sentence because it reads like a typo and is not one. The application's data directory setting and the path the Railway volume attaches to are different strings, and only one is the volume. A deployment mounted at the wrong path behaves identically to a correct one until the first redeploy, at which point the dashboard is empty and nothing in the logs explains why.

Routing behaviour is worth instrumenting rather than trusting. Fallback chains, circuit breakers and compression all sit between your application and the model, and each changes either which model answered or what text it received. Log the response `model` field yourself, enable compression only after measuring its effect, and build fallback chains from models you would genuinely accept in place of each other — the gateway will not tell you when the substitution mattered.

## Frequently Asked Questions

**Does OmniRoute need a database?** Only Redis, for routing state and rate limiting. Durable configuration lives on the volume.

**Will my providers and keys survive a redeploy?** Yes, with the volume mounted at the correct path. This is the single most common misconfiguration, because the wrong path fails silently.

**Can a request be served by a different model than I asked for?** Yes. That is what fallback and circuit breakers do. Check the `model` field in responses, and choose fallback targets you would accept.

**Should I enable prompt compression?** Not by default. It is lossy, applied before the model sees your text, and the effect depends on your prompts. Measure first.

**Is my data safe behind the dashboard password?** The dashboard holds every provider credential you add, so that password is the whole boundary. Make it long and random, and treat the deployment as infrastructure rather than an app.

## Why Deploy OmniRoute on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying OmniRoute on Railway you get a gateway configured for the failures that are not obvious — the volume on the path that actually holds your keys, a dashboard password set before the domain resolves, a pinned version, and routing behaviour documented so you know which model answered.

## Similar templates

- [Chat Chat](https://railway.com/deploy/-WWW5r) — Chat Chat, your own unified chat and search to AI platform.
- [stella](https://railway.com/deploy/stella) — Self-host stella with web, API, Postgres, Redis, and object storage.
- [Hermes Agent | OpenClaw Alternative with Dashboard](https://railway.com/deploy/hermes-agent-or-openclaw-alternative-wit) — Self-Hosted Hermes AI Agent for Telegram, Discord & Slack

Open this page in a browser: https://railway.com/deploy/omniroute-llm-gateway
