Skip to main content
Lowest ops: Railway handles managed Postgres, TLS, and a public URL automatically. Cost is usage-based and higher than a self-managed VPS.
Use 0.24.0 or newer.
1

Create the service

Choose New, then Docker Image, and enter mahimairaja/voicegateway:0.24.0.The exposed port is optional: the image binds $PORT, which Railway sets, and the healthcheck follows it. VOICEGW_PORT overrides both.
2

Add Postgres

Choose New in the same project and add the PostgreSQL plugin.
3

Configure environment variables

In the app service’s Variables tab, add:Paste VOICEGW_DB_URL literally: Railway resolves the ${{Postgres.*}} references at deploy time, so the password never leaves Railway.
Keep the +asyncpg, and do not substitute Railway’s own DATABASE_URL. It is plain postgresql://, which fails at boot: the image carries no driver for it.
VOICEGW_API_KEY registers a wildcard ingest key without needing an auth.api_keys: block in voicegw.yaml.
4

Deploy

Redeploy after setting variables. HTTPS is automatic at https://<your-service>.<your-project>.up.railway.app.

Verify

Two checks. The first proves the deploy works, the second proves it is not open to the internet. Run both.
1

A row survives a round trip

Returns {"accepted":1}, then a body whose components.llm_ttft_ms is 447.0.This is the check that matters. Passing it proves the process runs, your key is accepted, Postgres connected, migrations ran, and a write survives a read. Nothing else needs to pass for the deploy to be good.
2

The endpoint is not open to the internet

Returns 401. The check above proves your key is accepted; this one proves a request without it is refused. /v1/ingest has to be publicly reachable for agents to push to it, so anything other than 401 means anyone can write to your telemetry.

If the round trip failed

Two commands tell you where.
The round trip leaves one row behind, under project verify. It carries no cost, so it does not move your totals, but it does count as one request. No API call removes it: DELETE /v1/projects/verify deletes a project’s configuration, not its recorded requests. Run the check before you point real agents at the deploy and it stays easy to ignore.
To point an agent at it, use the Railway URL as collector_url and VOICEGW_API_KEY as api_key. See Connect your agent.

Deploying from source instead

A clone or fork works too, with no build configuration: railway.json at the repository root supplies the Dockerfile builder, its path, and healthcheckPath. Such a build reports 0.0.0.dev0 at /health, because Railway passes no VERSION argument. It is current, just unstamped.

Or let a coding agent do it

Runs every step on this page against the Railway CLI, including both checks.