Self-hosted Nango on Railway
Status (2026-05-25): Nango is deployed on Railway for all three environments (dev, staging, production). The Nango catalog autocomplete, SA tool-permissions toggle UI, and OAuth connect session + revoke wiring are all live (PRs #422, #423, #426, #427, #428). Issue #421 closed.
h.work uses the D-28 hybrid integration strategy: existing Shopify/Amazon integrations remain bespoke, while new OAuth SaaS vendors such as QuickBooks and Xero route through a single self-hosted Nango environment. Per-org isolation is enforced at the Nango connectionId layer using {org_slug}`-`{provider}.
Nango is Elastic License v2. OQ-203 must be ratified by Eusden before production rollout.
Railway shapeโ
Create these services in the humanwork Railway project:
nango-serverfrom Docker imagenangohq/nango-server:hostednango-dbas Railway Postgres 16 with a persistent volume- reuse the existing humanwork Redis service via
REDIS_URL
Railway deploymentsโ
Railway project: humanwork (ee0b91b9-1c2b-4e4c-b457-5a3f9c5cbdd5) in the Humanity workspace.
| Railway env | Nango server | Nango DB | Redis | Public URL |
|---|---|---|---|---|
dev (0303be2d-a70d-4cbc-8f01-e80b6c855440) | nango-server (f3f28f14-8212-4295-8b4e-db7bddc3874c) | nango-db (1c0a05b5-b0ab-4f77-9ef2-9de9f1a4ea81) | redis-dev | https://nango-server-dev-e568.up.railway.app |
staging (e1e7f4d9-3819-4607-be1f-0c23b87cea59) | nango-server-staging (bfd6ed57-1ee6-4ff1-8fe2-55f0d03ae569) | nango-db-staging (fb8fcf1a-a18f-4812-adfb-ba6d2dbde824) | redis-staging | https://nango-server-staging-staging.up.railway.app |
production (caa0a321-13be-4ad6-a6ef-ad7a0a82f57b) | nango-server-production (a061cc92-107c-4ee5-b953-e0b94e76ed15) | nango-db-production (b86e1b80-7a7e-4a9d-8e8c-d0da387d2766) | redis | https://nango-server-production-production.up.railway.app |
Each Nango DB service runs postgres:16-alpine with a persistent Railway volume mounted at /var/lib/postgresql/data and PGDATA=/var/lib/postgresql/data/pgdata.
The api service in each Railway environment has NANGO_SERVER_URL and NANGO_SECRET_KEY configured from the matching Nango instance: dev uses the Nango dev API key; staging and production use their instance's Nango prod API key.
Required nango-server variablesโ
NANGO_ENCRYPTION_KEY: 32-byte random secret. Do not rotate without taking anango-dbbackup and scheduling a maintenance window.NANGO_DB_USERNANGO_DB_PASSWORDNANGO_DB_HOSTNANGO_DB_NAMEREDIS_URL: existing humanwork Redis URLNANGO_DASHBOARD_USERNAMENANGO_DASHBOARD_PASSWORDNANGO_SERVER_URL: Railway internal/public service URL used by API servicesNANGO_PUBLIC_SERVER_URL: externally reachable URL for OAuth redirects
If customer-facing OAuth screens are needed, put Cloudflare in front of nango-server and set NANGO_PUBLIC_SERVER_URL to that hostname.
Humanwork API variablesโ
Set these on the API service:
NANGO_SERVER_URLNANGO_SECRET_KEY
The NestJS NangoModule uses those to trigger Nango actions from /v1/agent-api/tools/:toolName registry dispatch.
Connect flow & revokeโ
Client admins start OAuth for Nango-backed tools with:
POST /v1/integrations/nango/session
Content-Type: application/json
{ "provider": "quickbooks" }
The API checks org role and tool permissions, builds the Nango connectionId as {org_slug}-{provider}, creates a Connect Session, and returns:
{ "sessionToken": "<short-lived-token>", "connectionId": "<org-slug>-quickbooks" }
After the Nango UI reports success, the client confirms the connection:
POST /v1/integrations/credentials/nango/confirm
Content-Type: application/json
{ "provider": "quickbooks", "nango_connection_id": "<org-slug>-quickbooks" }
The API verifies the connection with Nango and stores only the nango_connection_id plus non-secret metadata such as scopes, connection status, and sync timestamp in IntegrationCredential. OAuth tokens stay in Nango.
Revocation is upstream-first. DELETE /orgs/:orgId/integrations/:id calls Nango DELETE /connection/{id} before deleting the local credential row for QuickBooks and Xero. If Nango revoke fails, the API returns a 5xx with Could not revoke at provider โ please retry and preserves the local row so the revoke can be retried.
Catalog & SA enablementโ
The SuperAdmin client Integrations tab searches the Nango provider catalog through the Humanwork API:
GET /v1/admin/integrations/catalog?q=<provider>
Catalog source (as shipped โ 2026-06-03). IntegrationsCatalogService queries GET ${NANGO_SERVER_URL}/providers with Authorization: Bearer ${NANGO_SECRET_KEY} as its primary source whenever both env vars are set โ which they are in all three Railway environments. It falls back to https://docs.nango.dev/providers.json (public, unauthenticated) only on a 404 from the self-hosted endpoint. Results are cached in-process for one hour. This means the catalog reflects the provider list pinned to your self-hosted Nango version; if your Nango image is older than the public catalog, providers added in newer Nango releases will not appear until you upgrade the image. NANGO_SECRET_KEY is also consumed by NangoClient for connect-session / connection-management API calls.
SuperAdmin catalog selection is metadata-only: selecting a provider writes enabled=true to the org's tool_permissions row for that provider key. It does not modify api/src/agent-api/tool-registry.ts or wire dispatch. Agent-call handlers remain engineer-curated in the registry; SuperAdmin enablement only controls whether the client can see and start the provider connection flow.
Health checksโ
From another Railway service in the same project:
curl -f "$NANGO_SERVER_URL/health"
Dashboard smoke:
- Open the Railway-assigned domain or Cloudflare hostname.
- Log in with
NANGO_DASHBOARD_USERNAME/NANGO_DASHBOARD_PASSWORD. - Confirm the dashboard can list/create provider configs.
Database smoke from nango-server shell:
psql "postgresql://${NANGO_DB_USER}:${NANGO_DB_PASSWORD}@${NANGO_DB_HOST}/${NANGO_DB_NAME}" -c 'select 1'
Backup and rotationโ
Before changing NANGO_ENCRYPTION_KEY:
- Stop OAuth write traffic.
- Take a Railway Postgres backup of
nango-db. - Export the current
NANGO_ENCRYPTION_KEYinto the incident/change record. - Rotate the key only with a tested Nango re-encryption procedure.
- Validate existing connections by triggering a harmless action per provider.
No key rotation is allowed without a backup because encrypted connection credentials can become unrecoverable.
Open operational questionsโ
- OQ-203: ratify Nango Elastic License v2 before production rollout.
- OQ-207: finalize tested encryption-key rotation and disaster-recovery procedure.
Open GitHub Issuesโ
| # | Title | Priority |
|---|---|---|
| #176 | Domain tools & integrations โ Finance/IR tools, OAuth flows | P2 |
Recently Resolvedโ
| # | Title | Closed |
|---|---|---|
| #421 | Backend โ Nango Connect Session + revoke wiring (PR #427) | 2026-05-24 |
SA Catalog & Tool Permissions (live as of v0.3.5+)โ
The SuperAdmin UI on /ops/clients/:id (Tools tab) now shows:
- A tool-permissions toggle per client org (PR #422)
- Nango catalog autocomplete with link-out (PR #423)
The SA can enable/disable specific integrations per org. Backend dispatch via POST /v1/agent-api/tools/:toolName is handled by the Nango + Jumio registry dispatch (PR #399).