{
  "manifest_version": "1.0.0",
  "template": {
    "id": "50da603c-3713-4bfe-bb94-3a31a0986d8a",
    "slug": "onyx-lite-chat-postgres",
    "name": "Onyx Lite Chat + Postgres",
    "description": "Onyx Lite self hosted AI chat with Postgres, four services",
    "url": "https://railway.com/deploy/onyx-lite-chat-postgres",
    "upstream": {
      "image": "nginx:1.25.5-alpine"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "Postgres",
      "source": {
        "image": "ghcr.io/railwayapp-templates/postgres-ssl:17"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "tcp_ports": [
        5432
      ],
      "http": false
    },
    {
      "name": "onyx-api",
      "source": {
        "image": "onyxdotapp/onyx-backend:v4.7.7"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "Onyx",
      "source": {
        "image": "nginx:1.25.5-alpine"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "onyx-web",
      "source": {
        "image": "onyxdotapp/onyx-web-server:v4.7.7"
      },
      "needs_volume": false,
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "PGDATA",
      "service": "Postgres",
      "description": "Provide a value for PGDATA.",
      "secret": false,
      "strategy": "default",
      "default": "/var/lib/postgresql/data/pgdata"
    },
    {
      "key": "PGHOST",
      "service": "Postgres",
      "description": "Provide a value for PGHOST.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PGPORT",
      "service": "Postgres",
      "description": "Provide a value for PGPORT.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "PGUSER",
      "service": "Postgres",
      "description": "Provide a value for PGUSER.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PGDATABASE",
      "service": "Postgres",
      "description": "Provide a value for PGDATABASE.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PGPASSWORD",
      "service": "Postgres",
      "description": "Provide a value for PGPASSWORD.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "POSTGRES_DB",
      "service": "Postgres",
      "description": "Database created on first boot. Holds users, chats, agents, settings, cache, sessions and uploaded files.",
      "secret": false,
      "strategy": "default",
      "default": "onyx"
    },
    {
      "key": "DATABASE_URL",
      "service": "Postgres",
      "description": "Private-network connection string (includes port).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "POSTGRES_USER",
      "service": "Postgres",
      "description": "Database superuser. Superuser is required: the Onyx migrations run CREATE EXTENSION pg_trgm and pgcrypto.",
      "secret": false,
      "strategy": "default",
      "default": "onyx"
    },
    {
      "key": "SSL_CERT_DAYS",
      "service": "Postgres",
      "description": "Provide a value for SSL_CERT_DAYS.",
      "secret": false,
      "strategy": "default",
      "default": "820"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "Postgres",
      "description": "Generated database password, referenced by onyx-api.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "DATABASE_PUBLIC_URL",
      "service": "Postgres",
      "description": "Public URL via the TCP proxy, for psql or a GUI client.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DATABASE_PRIVATE_URL",
      "service": "Postgres",
      "description": "Provide a value for DATABASE_PRIVATE_URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "Postgres",
      "description": "Grace period so Postgres can shut down cleanly on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "PORT",
      "service": "onyx-api",
      "description": "uvicorn listen port. Railway's healthcheck probes $PORT/health, so keep it equal to the port in the start command and to the port in ONYX_API_HOST and INTERNAL_URL.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "AUTH_TYPE",
      "service": "onyx-api",
      "description": "Legacy pre-v4.4 variable, kept only because older Onyx guides still mention it. Authentication is ALWAYS on in v4.7: the first account to sign up becomes the admin, and SSO (Google / OIDC / SAML) is configured in Admin Panel > Organization > SSO Providers. AUTH_TYPE=disabled is no longer supported and only logs a warning.",
      "secret": false,
      "strategy": "default",
      "default": "basic"
    },
    {
      "key": "LOG_LEVEL",
      "service": "onyx-api",
      "description": "Log verbosity for the API server (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "WEB_DOMAIN",
      "service": "onyx-api",
      "description": "Public base URL, used to build redirect URIs after login and links in emails. Points at the Onyx (nginx) service because that is the only public entry point.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "POSTGRES_DB",
      "service": "onyx-api",
      "description": "Database name. `alembic upgrade head` runs against it on every boot (440 migrations on a fresh database, which is why healthcheckTimeout is 900).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AUTH_BACKEND",
      "service": "onyx-api",
      "description": "Session tokens live in Postgres instead of Redis (upstream lite overlay), so logins survive an API server redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "CACHE_BACKEND",
      "service": "onyx-api",
      "description": "Caches, locks and ephemeral state live in Postgres instead of Redis (upstream lite overlay). The API server refuses to start with CACHE_BACKEND=postgres unless DISABLE_VECTOR_DB=true.",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "POSTGRES_HOST",
      "service": "onyx-api",
      "description": "Private hostname of the Postgres service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "POSTGRES_PORT",
      "service": "onyx-api",
      "description": "Postgres port. Private networking always needs an explicit port.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "POSTGRES_USER",
      "service": "onyx-api",
      "description": "Postgres user (mirrors the Postgres service).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "USER_AUTH_SECRET",
      "service": "onyx-api",
      "description": "Signs password-reset, email-verification, OAuth state and captcha cookies. Required: the API server refuses to start when it is empty. 64 hex characters, the equivalent of `openssl rand -hex 32`.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "DISABLE_TELEMETRY",
      "service": "onyx-api",
      "description": "Turns off anonymous usage telemetry to Onyx. Set to false to opt back in.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "DISABLE_VECTOR_DB",
      "service": "onyx-api",
      "description": "Onyx Lite mode, from upstream deployment/docker_compose/docker-compose.onyx-lite.yml. Skips document index setup and embedding warm-up, so neither OpenSearch nor the model servers are needed. Connectors and RAG search are off; chat, Projects, agents, actions and user file uploads stay on. Setting this to false also requires adding OpenSearch, Redis and two model servers.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "onyx-api",
      "description": "Postgres password (mirrors the Postgres service).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FILE_STORE_BACKEND",
      "service": "onyx-api",
      "description": "User file uploads and generated images are stored in Postgres instead of S3/MinIO (upstream lite overlay), so no MinIO service is needed.",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "VALID_EMAIL_DOMAINS",
      "service": "onyx-api",
      "description": "Comma separated email domains allowed to register, for example acme.com. Onyx has no signup switch: without this, anyone who finds the URL can create an account. Your first signup at one of these domains becomes the administrator.",
      "secret": false,
      "strategy": "ask_user"
    },
    {
      "key": "DISABLE_MODEL_SERVER",
      "service": "onyx-api",
      "description": "No inference or indexing model server runs in this template. Each model-server image is 4.8 GB and only serves local embeddings and reranking, which Lite mode never calls. Also skips the GPU probe at boot.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "ENCRYPTION_KEY_SECRET",
      "service": "onyx-api",
      "description": "Encrypts stored credentials and LLM provider API keys at rest in Postgres. Do not rotate it after credentials are saved or they become unreadable.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "SESSION_EXPIRE_TIME_SECONDS",
      "service": "onyx-api",
      "description": "Login session lifetime in seconds (upstream default, 7 days).",
      "secret": false,
      "strategy": "default",
      "default": "604800"
    },
    {
      "key": "POSTGRES_API_SERVER_POOL_SIZE",
      "service": "onyx-api",
      "description": "SQLAlchemy pool size per engine. Onyx defaults to 40 and the API server opens a sync AND an async engine, which would reach the stock max_connections=100 of the Postgres image. 20 plus 10 overflow per engine leaves headroom.",
      "secret": false,
      "strategy": "default",
      "default": "20"
    },
    {
      "key": "POSTGRES_API_SERVER_POOL_OVERFLOW",
      "service": "onyx-api",
      "description": "SQLAlchemy overflow connections per engine (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "10"
    },
    {
      "key": "ENABLE_PAID_ENTERPRISE_EDITION_FEATURES",
      "service": "onyx-api",
      "description": "Enterprise Edition features need a paid Onyx license. Leave false for the community build.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "PORT",
      "service": "Onyx",
      "description": "nginx listen port. Railway's healthcheck and the public domain probe $PORT, so keep this equal to the domain target port.",
      "secret": false,
      "strategy": "default",
      "default": "80"
    },
    {
      "key": "ONYX_API_HOST",
      "service": "Onyx",
      "description": "host:port of the Onyx API service on the private network. The start script renders it into nginx as the /api upstream and re-resolves it per request (upstream's app.conf.template hardcodes api_server:8080 inside an upstream block, which nginx resolves once at boot and which does not exist here).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ONYX_WEB_HOST",
      "service": "Onyx",
      "description": "host:port of the Onyx Web (Next.js) service on the private network. Everything that is not /api, /openapi.json, /scim or /auth/saml is proxied here.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "NGINX_PROXY_READ_TIMEOUT",
      "service": "Onyx",
      "description": "Upstream read timeout in seconds (upstream default). Chat responses stream for as long as the model takes.",
      "secret": false,
      "strategy": "default",
      "default": "300"
    },
    {
      "key": "NGINX_PROXY_SEND_TIMEOUT",
      "service": "Onyx",
      "description": "Upstream send timeout in seconds (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "300"
    },
    {
      "key": "NGINX_CLIENT_MAX_BODY_SIZE",
      "service": "Onyx",
      "description": "Maximum upload size (upstream default). Lower it to cap user file uploads at the proxy.",
      "secret": false,
      "strategy": "default",
      "default": "5G"
    },
    {
      "key": "NGINX_PROXY_CONNECT_TIMEOUT",
      "service": "Onyx",
      "description": "Upstream connect timeout in seconds (upstream default). Long LLM streams need a generous value.",
      "secret": false,
      "strategy": "default",
      "default": "300"
    },
    {
      "key": "ENABLE_ALPINE_PRIVATE_NETWORKING",
      "service": "Onyx",
      "description": "Alpine (musl) image: required for *.railway.internal DNS resolution from this container.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PORT",
      "service": "onyx-web",
      "description": "Port the Next.js standalone server binds. Must match the port in the Onyx service's ONYX_WEB_HOST.",
      "secret": false,
      "strategy": "default",
      "default": "3000"
    },
    {
      "key": "HOSTNAME",
      "service": "onyx-web",
      "description": "Next.js standalone binds this. '::' listens on both address families; the image would otherwise set it to the container id.",
      "secret": false,
      "strategy": "default",
      "default": "::"
    },
    {
      "key": "INTERNAL_URL",
      "service": "onyx-web",
      "description": "Server-side base URL the web app uses to reach the API for SSR and for the /openapi.json and /api/docs rewrites. Must include the port.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "WEB_FRAME_PROTECTION_ENABLED",
      "service": "onyx-web",
      "description": "Emits a frame-ancestors CSP so other sites cannot iframe Onyx. Set to false only if you intentionally embed Onyx.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "onyx-lite-chat-postgres"
      }
    },
    "cli": "railway deploy --template onyx-lite-chat-postgres",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "50da603c-3713-4bfe-bb94-3a31a0986d8a",
            "serializedConfig": {
              "services": {
                "2f61a183-54ff-4747-b8b5-34b4ef6e0ec0": {
                  "icon": "https://devicons.railway.app/i/postgresql.svg",
                  "name": "Postgres",
                  "build": {},
                  "deploy": {
                    "requiredMountPath": "/var/lib/postgresql/data",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 5
                  },
                  "source": {
                    "image": "ghcr.io/railwayapp-templates/postgres-ssl:17"
                  },
                  "variables": {
                    "PGDATA": {
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "PGHOST": {
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "PGPORT": {
                      "defaultValue": "5432"
                    },
                    "PGUSER": {
                      "defaultValue": "${{POSTGRES_USER}}"
                    },
                    "PGDATABASE": {
                      "defaultValue": "${{POSTGRES_DB}}"
                    },
                    "PGPASSWORD": {
                      "defaultValue": "${{POSTGRES_PASSWORD}}"
                    },
                    "POSTGRES_DB": {
                      "description": "Database created on first boot. Holds users, chats, agents, settings, cache, sessions and uploaded files.",
                      "defaultValue": "onyx"
                    },
                    "DATABASE_URL": {
                      "description": "Private-network connection string (includes port).",
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_PRIVATE_DOMAIN}}:5432/${{PGDATABASE}}"
                    },
                    "POSTGRES_USER": {
                      "description": "Database superuser. Superuser is required: the Onyx migrations run CREATE EXTENSION pg_trgm and pgcrypto.",
                      "defaultValue": "onyx"
                    },
                    "SSL_CERT_DAYS": {
                      "isOptional": true,
                      "defaultValue": "820"
                    },
                    "POSTGRES_PASSWORD": {
                      "description": "Generated database password, referenced by onyx-api.",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    },
                    "DATABASE_PUBLIC_URL": {
                      "description": "Public URL via the TCP proxy, for psql or a GUI client.",
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_TCP_PROXY_DOMAIN}}:${{RAILWAY_TCP_PROXY_PORT}}/${{PGDATABASE}}"
                    },
                    "DATABASE_PRIVATE_URL": {
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_PRIVATE_DOMAIN}}:5432/${{PGDATABASE}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Grace period so Postgres can shut down cleanly on redeploy.",
                      "defaultValue": "60"
                    }
                  },
                  "networking": {
                    "tcpProxies": {
                      "5432": {}
                    },
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "4a3f13cb-8310-4272-843a-e2574f952823": {
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  }
                },
                "368956ff-c280-4b8d-9395-cc0dfa0107de": {
                  "icon": "https://raw.githubusercontent.com/onyx-dot-app/onyx/v4.7.7/web/public/logo.png",
                  "name": "onyx-api",
                  "deploy": {
                    "startCommand": "sh -c 'echo IyEvYmluL3NoCiMgUmFpbHdheSBzdGFydCBjb21tYW5kIGZvciB0aGUgT255eCBBUEkgc2VydmVyLgojCiMgbmdpbnggYW5kIHRoZSB3ZWIgc2VydmVyIGJvdGggY2FsbCB0aGlzIHNlcnZpY2Ugb3ZlciBSYWlsd2F5J3MgcHJpdmF0ZSBuZXR3b3JrLCB3aGljaCBpcyBJUHY2CiMgb25seSwgd2hpbGUgUmFpbHdheSdzIG93biBoZWFsdGhjaGVjayBhcnJpdmVzIG92ZXIgSVB2NC4gdXZpY29ybiBjYW4gYmluZCBvbmUgYWRkcmVzcyBmYW1pbHkgYXQgYQojIHRpbWU6IC0taG9zdCAwLjAuMC4wIGxvc2VzIHRoZSBwcml2YXRlIGNhbGxlcnMsIC0taG9zdCA6OiBsb3NlcyB0aGUgaGVhbHRoY2hlY2ssIGJlY2F1c2UgYXN5bmNpbwojIHNldHMgSVBWNl9WNk9OTFkgb24gdGhlIHNvY2tldCBpdCBjcmVhdGVzLiBTbyBjcmVhdGUgdGhlIGxpc3RlbmluZyBzb2NrZXQgaGVyZSB3aXRoCiMgSVBWNl9WNk9OTFkgb2ZmIGFuZCBoYW5kIHV2aWNvcm4gdGhlIGZpbGUgZGVzY3JpcHRvci4Kc2V0IC1lCmFsZW1iaWMgdXBncmFkZSBoZWFkCmVjaG8gIlN0YXJ0aW5nIE9ueXggQXBpIFNlcnZlciIKZXhlYyBweXRob24gLSA8PCdQWScKaW1wb3J0IG9zLCBzb2NrZXQKcyA9IHNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQ2LCBzb2NrZXQuU09DS19TVFJFQU0pCnMuc2V0c29ja29wdChzb2NrZXQuU09MX1NPQ0tFVCwgc29ja2V0LlNPX1JFVVNFQUREUiwgMSkKcy5zZXRzb2Nrb3B0KHNvY2tldC5JUFBST1RPX0lQVjYsIHNvY2tldC5JUFY2X1Y2T05MWSwgMCkKcy5iaW5kKCgiOjoiLCBpbnQob3MuZW52aXJvbi5nZXQoIlBPUlQiLCAiODA4MCIpKSkpCnMubGlzdGVuKDIwNDgpCm9zLnNldF9pbmhlcml0YWJsZShzLmZpbGVubygpLCBUcnVlKQpvcy5leGVjdnAoInV2aWNvcm4iLCBbInV2aWNvcm4iLCAib255eC5tYWluOmFwcCIsICItLWZkIiwgc3RyKHMuZmlsZW5vKCkpXSkKUFkK | base64 -d > /tmp/start.sh && exec sh /tmp/start.sh'",
                    "healthcheckPath": "/health",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 900,
                    "restartPolicyMaxRetries": 5
                  },
                  "source": {
                    "image": "onyxdotapp/onyx-backend:v4.7.7"
                  },
                  "variables": {
                    "PORT": {
                      "description": "uvicorn listen port. Railway's healthcheck probes $PORT/health, so keep it equal to the port in the start command and to the port in ONYX_API_HOST and INTERNAL_URL.",
                      "defaultValue": "8080"
                    },
                    "AUTH_TYPE": {
                      "description": "Legacy pre-v4.4 variable, kept only because older Onyx guides still mention it. Authentication is ALWAYS on in v4.7: the first account to sign up becomes the admin, and SSO (Google / OIDC / SAML) is configured in Admin Panel > Organization > SSO Providers. AUTH_TYPE=disabled is no longer supported and only logs a warning.",
                      "defaultValue": "basic"
                    },
                    "LOG_LEVEL": {
                      "description": "Log verbosity for the API server (upstream default).",
                      "defaultValue": "info"
                    },
                    "WEB_DOMAIN": {
                      "description": "Public base URL, used to build redirect URIs after login and links in emails. Points at the Onyx (nginx) service because that is the only public entry point.",
                      "defaultValue": "https://${{Onyx.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "POSTGRES_DB": {
                      "description": "Database name. `alembic upgrade head` runs against it on every boot (440 migrations on a fresh database, which is why healthcheckTimeout is 900).",
                      "defaultValue": "${{Postgres.POSTGRES_DB}}"
                    },
                    "AUTH_BACKEND": {
                      "description": "Session tokens live in Postgres instead of Redis (upstream lite overlay), so logins survive an API server redeploy.",
                      "defaultValue": "postgres"
                    },
                    "CACHE_BACKEND": {
                      "description": "Caches, locks and ephemeral state live in Postgres instead of Redis (upstream lite overlay). The API server refuses to start with CACHE_BACKEND=postgres unless DISABLE_VECTOR_DB=true.",
                      "defaultValue": "postgres"
                    },
                    "POSTGRES_HOST": {
                      "description": "Private hostname of the Postgres service.",
                      "defaultValue": "${{Postgres.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "POSTGRES_PORT": {
                      "description": "Postgres port. Private networking always needs an explicit port.",
                      "defaultValue": "5432"
                    },
                    "POSTGRES_USER": {
                      "description": "Postgres user (mirrors the Postgres service).",
                      "defaultValue": "${{Postgres.POSTGRES_USER}}"
                    },
                    "GEN_AI_API_KEY": {
                      "isOptional": true,
                      "description": "Optional. Seeds a default LLM provider key at first boot. The normal path is to add providers in Admin Panel > Configuration > LLM after deploy.",
                      "defaultValue": ""
                    },
                    "USER_AUTH_SECRET": {
                      "description": "Signs password-reset, email-verification, OAuth state and captcha cookies. Required: the API server refuses to start when it is empty. 64 hex characters, the equivalent of `openssl rand -hex 32`.",
                      "defaultValue": "{{USER_AUTH_SECRET}}"
                    },
                    "DISABLE_TELEMETRY": {
                      "description": "Turns off anonymous usage telemetry to Onyx. Set to false to opt back in.",
                      "defaultValue": "true"
                    },
                    "DISABLE_VECTOR_DB": {
                      "description": "Onyx Lite mode, from upstream deployment/docker_compose/docker-compose.onyx-lite.yml. Skips document index setup and embedding warm-up, so neither OpenSearch nor the model servers are needed. Connectors and RAG search are off; chat, Projects, agents, actions and user file uploads stay on. Setting this to false also requires adding OpenSearch, Redis and two model servers.",
                      "defaultValue": "true"
                    },
                    "POSTGRES_PASSWORD": {
                      "description": "Postgres password (mirrors the Postgres service).",
                      "defaultValue": "${{Postgres.POSTGRES_PASSWORD}}"
                    },
                    "FILE_STORE_BACKEND": {
                      "description": "User file uploads and generated images are stored in Postgres instead of S3/MinIO (upstream lite overlay), so no MinIO service is needed.",
                      "defaultValue": "postgres"
                    },
                    "VALID_EMAIL_DOMAINS": {
                      "description": "Comma separated email domains allowed to register, for example acme.com. Onyx has no signup switch: without this, anyone who finds the URL can create an account. Your first signup at one of these domains becomes the administrator.",
                      "defaultValue": "{{VALID_EMAIL_DOMAINS}}"
                    },
                    "DISABLE_MODEL_SERVER": {
                      "description": "No inference or indexing model server runs in this template. Each model-server image is 4.8 GB and only serves local embeddings and reranking, which Lite mode never calls. Also skips the GPU probe at boot.",
                      "defaultValue": "true"
                    },
                    "ENCRYPTION_KEY_SECRET": {
                      "description": "Encrypts stored credentials and LLM provider API keys at rest in Postgres. Do not rotate it after credentials are saved or they become unreadable.",
                      "defaultValue": "{{ENCRYPTION_KEY_SECRET}}"
                    },
                    "SESSION_EXPIRE_TIME_SECONDS": {
                      "description": "Login session lifetime in seconds (upstream default, 7 days).",
                      "defaultValue": "604800"
                    },
                    "POSTGRES_API_SERVER_POOL_SIZE": {
                      "description": "SQLAlchemy pool size per engine. Onyx defaults to 40 and the API server opens a sync AND an async engine, which would reach the stock max_connections=100 of the Postgres image. 20 plus 10 overflow per engine leaves headroom.",
                      "defaultValue": "20"
                    },
                    "POSTGRES_API_SERVER_POOL_OVERFLOW": {
                      "description": "SQLAlchemy overflow connections per engine (upstream default).",
                      "defaultValue": "10"
                    },
                    "ENABLE_PAID_ENTERPRISE_EDITION_FEATURES": {
                      "description": "Enterprise Edition features need a paid Onyx license. Leave false for the community build.",
                      "defaultValue": "false"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "89f9183b-09e2-4bd0-a338-71a3cac20165": {
                  "icon": "https://raw.githubusercontent.com/onyx-dot-app/onyx/v4.7.7/web/public/logo.png",
                  "name": "Onyx",
                  "deploy": {
                    "startCommand": "sh -c 'echo IyEvYmluL3NoCiMgT255eCBmcm9udCBkb29yIGZvciBSYWlsd2F5LgojCiMgVXBzdHJlYW0ncyBkZXBsb3ltZW50L2RhdGEvbmdpbngvYXBwLmNvbmYudGVtcGxhdGUgY2Fubm90IGJlIHVzZWQgYXMtaXMgaGVyZToKIyAgICogaXQgZGVjbGFyZXMgYHVwc3RyZWFtIGFwaV9zZXJ2ZXIgeyBzZXJ2ZXIgYXBpX3NlcnZlcjo4MDgwOyB9YCwgYW5kIG5naW54CiMgICAgIHJlc29sdmVzIHVwc3RyZWFtIGJsb2NrcyBvbmNlIGF0IGNvbmZpZyBsb2FkIGFuZCB0aGVuIGNhY2hlcyB0aGUgYWRkcmVzcwojICAgICBmb3JldmVyLiBSYWlsd2F5IHByaXZhdGUgSVBzIGNoYW5nZSBvbiBldmVyeSByZWRlcGxveSwgYW5kIHRoZSBuYW1lIGRvZXMKIyAgICAgbm90IHJlc29sdmUgYXQgYWxsIHVudGlsIHRoZSB0YXJnZXQgc2VydmljZSBoYXMgZGVwbG95ZWQsIHNvIG5naW54IGVpdGhlcgojICAgICBjcmFzaC1sb29wcyB3aXRoICJob3N0IG5vdCBmb3VuZCBpbiB1cHN0cmVhbSIgb3IgcGlucyBhIHN0YWxlIGFkZHJlc3MuCiMgICAqIGl0IGxpc3RlbnMgb24gYSBoYXJkY29kZWQgcG9ydCA4MCBhbmQgSVB2NCBvbmx5LgojCiMgU28gdGhpcyBzY3JpcHQgcmVuZGVycyBhbiBlcXVpdmFsZW50IGNvbmZpZyBhdCBib290IHdpdGggYSBydW50aW1lIGByZXNvbHZlcmAKIyBwbHVzIHZhcmlhYmxlcyBpbiBwcm94eV9wYXNzIChyZS1yZXNvbHZlZCBwZXIgcmVxdWVzdCksIGFuZCBsaXN0ZW5zIG9uICRQT1JUCiMgb24gYm90aCBJUHY0IGFuZCBJUHY2LiBSb3V0ZSBtYXAgbWF0Y2hlcyB1cHN0cmVhbSBhcHAuY29uZi50ZW1wbGF0ZS4Kc2V0IC1ldQoKUE9SVD0iJHtQT1JUOi04MH0iCkFQST0iJHtPTllYX0FQSV9IT1NUOj9PTllYX0FQSV9IT1NUIG11c3QgYmUgPGhvc3Q+Ojxwb3J0PiBvZiB0aGUgT255eCBBUEkgc2VydmljZX0iCldFQj0iJHtPTllYX1dFQl9IT1NUOj9PTllYX1dFQl9IT1NUIG11c3QgYmUgPGhvc3Q+Ojxwb3J0PiBvZiB0aGUgT255eCBXZWIgc2VydmljZX0iCkNUPSIke05HSU5YX1BST1hZX0NPTk5FQ1RfVElNRU9VVDotMzAwfSIKU1Q9IiR7TkdJTlhfUFJPWFlfU0VORF9USU1FT1VUOi0zMDB9IgpSVD0iJHtOR0lOWF9QUk9YWV9SRUFEX1RJTUVPVVQ6LTMwMH0iCkJPRFk9IiR7TkdJTlhfQ0xJRU5UX01BWF9CT0RZX1NJWkU6LTVHfSIKCk5TPSIkKGF3ayAnL15uYW1lc2VydmVyLyB7IHByaW50ICQyOyBleGl0IH0nIC9ldGMvcmVzb2x2LmNvbmYpIgpjYXNlICIkTlMiIGluICo6KikgTlM9IlskTlNdIiA7OyBlc2FjCgpIRFJTPSdwcm94eV9zZXRfaGVhZGVyIEhvc3QgJGhvc3Q7IHByb3h5X3NldF9oZWFkZXIgWC1SZWFsLUlQICRyZW1vdGVfYWRkcjsgcHJveHlfc2V0X2hlYWRlciBYLUZvcndhcmRlZC1Gb3IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7IHByb3h5X3NldF9oZWFkZXIgWC1Gb3J3YXJkZWQtUHJvdG8gJG9ueXhfcHJvdG87IHByb3h5X3NldF9oZWFkZXIgWC1Gb3J3YXJkZWQtSG9zdCAkaG9zdDsgcHJveHlfc2V0X2hlYWRlciBYLUZvcndhcmRlZC1Qb3J0ICRzZXJ2ZXJfcG9ydDsnClRNTz0icHJveHlfY29ubmVjdF90aW1lb3V0ICR7Q1R9czsgcHJveHlfc2VuZF90aW1lb3V0ICR7U1R9czsgcHJveHlfcmVhZF90aW1lb3V0ICR7UlR9czsiCgpjYXQgPiAvZXRjL25naW54L2NvbmYuZC9kZWZhdWx0LmNvbmYgPDxOR0lOWApzZXJ2ZXJfdG9rZW5zIG9mZjsKbG9nX2Zvcm1hdCBvbnl4X21haW4gJ1wkcmVtb3RlX2FkZHIgLSBcJHJlbW90ZV91c2VyIFtcJHRpbWVfbG9jYWxdICJcJHJlcXVlc3QiIFwkc3RhdHVzIFwkYm9keV9ieXRlc19zZW50ICJcJGh0dHBfcmVmZXJlciIgIlwkaHR0cF91c2VyX2FnZW50IiBydD1cJHJlcXVlc3RfdGltZSc7CnJlc29sdmVyICROUyB2YWxpZD0zMHM7CnJlc29sdmVyX3RpbWVvdXQgNXM7Cm1hcCBcJGh0dHBfdXBncmFkZSBcJGNvbm5lY3Rpb25fdXBncmFkZSB7IGRlZmF1bHQgdXBncmFkZTsgJycgY2xvc2U7IH0KbWFwIFwkaHR0cF94X2ZvcndhcmRlZF9wcm90byBcJG9ueXhfcHJvdG8geyBkZWZhdWx0IFwkaHR0cF94X2ZvcndhcmRlZF9wcm90bzsgJycgXCRzY2hlbWU7IH0Kc2VydmVyIHsKICAgIGxpc3RlbiAkUE9SVCBkZWZhdWx0X3NlcnZlcjsKICAgIGxpc3RlbiBbOjpdOiRQT1JUIGRlZmF1bHRfc2VydmVyOwogICAgc2VydmVyX25hbWUgXzsKICAgIGFjY2Vzc19sb2cgL3Zhci9sb2cvbmdpbngvYWNjZXNzLmxvZyBvbnl4X21haW47CiAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAkQk9EWTsKICAgIGNsaWVudF9oZWFkZXJfYnVmZmVyX3NpemUgMTZrOwogICAgbGFyZ2VfY2xpZW50X2hlYWRlcl9idWZmZXJzIDQgNjRrOwogICAgc2V0IFwkb255eF9hcGkgIiRBUEkiOwogICAgc2V0IFwkb255eF93ZWIgIiRXRUIiOwoKICAgIGxvY2F0aW9uID0gL25naW54LWhlYWx0aCB7IGFjY2Vzc19sb2cgb2ZmOyBhZGRfaGVhZGVyIENvbnRlbnQtVHlwZSB0ZXh0L3BsYWluOyByZXR1cm4gMjAwICJvayI7IH0KCiAgICBsb2NhdGlvbiB+IF4vYXBpLyguKilcJCB7CiAgICAgICAgJEhEUlMKICAgICAgICBwcm94eV9odHRwX3ZlcnNpb24gMS4xOwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSBcJGh0dHBfdXBncmFkZTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gXCRjb25uZWN0aW9uX3VwZ3JhZGU7CiAgICAgICAgcHJveHlfYnVmZmVyaW5nIG9mZjsKICAgICAgICBwcm94eV9yZWRpcmVjdCBvZmY7CiAgICAgICAgJFRNTwogICAgICAgIHByb3h5X3Bhc3MgaHR0cDovL1wkb255eF9hcGkvXCQxXCRpc19hcmdzXCRhcmdzOwogICAgfQoKICAgIGxvY2F0aW9uID0gL29wZW5hcGkuanNvbiB7CiAgICAgICAgJEhEUlMKICAgICAgICBwcm94eV9odHRwX3ZlcnNpb24gMS4xOwogICAgICAgIHByb3h5X3JlZGlyZWN0IG9mZjsKICAgICAgICAkVE1PCiAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vXCRvbnl4X2FwaS9vcGVuYXBpLmpzb25cJGlzX2FyZ3NcJGFyZ3M7CiAgICB9CgogICAgbG9jYXRpb24gfiBeL2F1dGgvc2FtbCgvLiopP1wkIHsKICAgICAgICAkSERSUwogICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgcHJveHlfYnVmZmVyaW5nIG9mZjsKICAgICAgICBwcm94eV9yZWRpcmVjdCBvZmY7CiAgICAgICAgJFRNTwogICAgICAgIHByb3h5X3Bhc3MgaHR0cDovL1wkb255eF9hcGlcJHJlcXVlc3RfdXJpOwogICAgfQoKICAgIGxvY2F0aW9uIH4gXi9zY2ltKC8uKik/XCQgewogICAgICAgICRIRFJTCiAgICAgICAgcHJveHlfaHR0cF92ZXJzaW9uIDEuMTsKICAgICAgICBwcm94eV9idWZmZXJpbmcgb2ZmOwogICAgICAgIHByb3h5X3JlZGlyZWN0IG9mZjsKICAgICAgICAkVE1PCiAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vXCRvbnl4X2FwaVwkcmVxdWVzdF91cmk7CiAgICB9CgogICAgbG9jYXRpb24gLyB7CiAgICAgICAgJEhEUlMKICAgICAgICBwcm94eV9odHRwX3ZlcnNpb24gMS4xOwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSBcJGh0dHBfdXBncmFkZTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gXCRjb25uZWN0aW9uX3VwZ3JhZGU7CiAgICAgICAgcHJveHlfcmVkaXJlY3Qgb2ZmOwogICAgICAgICRUTU8KICAgICAgICBwcm94eV9wYXNzIGh0dHA6Ly9cJG9ueXhfd2ViXCRyZXF1ZXN0X3VyaTsKICAgIH0KfQpOR0lOWAoKZWNobyAib255eC1uZ2lueDogbGlzdGVuaW5nIG9uICRQT1JUOyAvYXBpIC0+ICRBUEk7IC8gLT4gJFdFQiAocmVzb2x2ZXIgJE5TKSIKZXhlYyAvZG9ja2VyLWVudHJ5cG9pbnQuc2ggbmdpbnggLWcgImRhZW1vbiBvZmY7Igo= | base64 -d > /tmp/railway-start.sh && exec sh /tmp/railway-start.sh'",
                    "healthcheckPath": "/nginx-health",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 5
                  },
                  "source": {
                    "image": "nginx:1.25.5-alpine"
                  },
                  "variables": {
                    "PORT": {
                      "description": "nginx listen port. Railway's healthcheck and the public domain probe $PORT, so keep this equal to the domain target port.",
                      "defaultValue": "80"
                    },
                    "ONYX_API_HOST": {
                      "description": "host:port of the Onyx API service on the private network. The start script renders it into nginx as the /api upstream and re-resolves it per request (upstream's app.conf.template hardcodes api_server:8080 inside an upstream block, which nginx resolves once at boot and which does not exist here).",
                      "defaultValue": "${{onyx-api.RAILWAY_PRIVATE_DOMAIN}}:8080"
                    },
                    "ONYX_WEB_HOST": {
                      "description": "host:port of the Onyx Web (Next.js) service on the private network. Everything that is not /api, /openapi.json, /scim or /auth/saml is proxied here.",
                      "defaultValue": "${{onyx-web.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "NGINX_PROXY_READ_TIMEOUT": {
                      "description": "Upstream read timeout in seconds (upstream default). Chat responses stream for as long as the model takes.",
                      "defaultValue": "300"
                    },
                    "NGINX_PROXY_SEND_TIMEOUT": {
                      "description": "Upstream send timeout in seconds (upstream default).",
                      "defaultValue": "300"
                    },
                    "NGINX_CLIENT_MAX_BODY_SIZE": {
                      "description": "Maximum upload size (upstream default). Lower it to cap user file uploads at the proxy.",
                      "defaultValue": "5G"
                    },
                    "NGINX_PROXY_CONNECT_TIMEOUT": {
                      "description": "Upstream connect timeout in seconds (upstream default). Long LLM streams need a generous value.",
                      "defaultValue": "300"
                    },
                    "ENABLE_ALPINE_PRIVATE_NETWORKING": {
                      "description": "Alpine (musl) image: required for *.railway.internal DNS resolution from this container.",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {
                      "onyx-dom": {
                        "port": 80
                      }
                    }
                  }
                },
                "e1be10b3-1849-4ff6-ba65-d58ffdf08e91": {
                  "icon": "https://raw.githubusercontent.com/onyx-dot-app/onyx/v4.7.7/web/public/logo.png",
                  "name": "onyx-web",
                  "deploy": {
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 5
                  },
                  "source": {
                    "image": "onyxdotapp/onyx-web-server:v4.7.7"
                  },
                  "variables": {
                    "PORT": {
                      "description": "Port the Next.js standalone server binds. Must match the port in the Onyx service's ONYX_WEB_HOST.",
                      "defaultValue": "3000"
                    },
                    "HOSTNAME": {
                      "description": "Next.js standalone binds this. '::' listens on both address families; the image would otherwise set it to the container id.",
                      "defaultValue": "::"
                    },
                    "INTERNAL_URL": {
                      "description": "Server-side base URL the web app uses to reach the API for SSR and for the /openapi.json and /api/docs rewrites. Must include the port.",
                      "defaultValue": "http://${{onyx-api.RAILWAY_PRIVATE_DOMAIN}}:8080"
                    },
                    "WEB_FRAME_PROTECTION_ENABLED": {
                      "description": "Emits a frame-ancestors CSP so other sites cannot iframe Onyx. Set to false only if you intentionally embed Onyx.",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "Onyx",
      "method": "GET",
      "path": "/nginx-health",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 4,
    "needs_volume": true
  },
  "generated_at": "2026-09-21T04:14:46.774Z",
  "generator_version": "0.1.0"
}
