Railway runs Stay Sidekick’s five services in separate containers connected via a private internal network. Only theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/sdurutr436/stay-sidekick/llms.txt
Use this file to discover all available pages before exploring further.
nginx service is exposed publicly — all other services communicate over Railway’s private .railway.internal DNS. TLS is terminated at Railway’s edge automatically, so the nginx container itself only listens on port 80 and never manages certificates.
Architecture
nginx loads nginx.railway.conf instead of nginx.conf, activated by the RAILWAY=true environment variable.
Step-by-step deployment
Create a new Railway project
Log in to railway.app, click New Project, and select Deploy from GitHub repo. Authorize Railway to access your GitHub account and select the
stay-sidekick repository.Add all five services
Railway creates one service from the repository by default. Add the remaining four:
For the Database Plugin, click + New → Database → Add PostgreSQL. Railway provisions a managed PostgreSQL 16 instance and makes its connection details available as variables.
| Service name | Type |
|---|---|
nginx | GitHub repo |
frontend | GitHub repo |
web | GitHub repo |
backend | GitHub repo |
postgres | Database Plugin (PostgreSQL) |
Configure Root Directory for each service
Each service needs to know which subdirectory contains its Dockerfile. Set the Root Directory in each service’s Settings tab:
For the
| Service | Root Directory | Notes |
|---|---|---|
nginx | nginx/ | |
frontend | frontend/ | |
web | (leave empty) | Must use the repo root — see warning below |
backend | backend/ |
web service, Railway reads railway.toml from the repo root which points to web/Dockerfile:Activate the Railway nginx configuration
In the This build argument causes the nginx Dockerfile to copy
nginx service’s Variables tab, add:nginx.railway.conf instead of nginx.conf. The Railway configuration uses .railway.internal hostnames to reach the other services over the private network and sets a low DNS TTL to handle service redeployments gracefully.Add backend environment variables
In the
backend service’s Variables tab, add all required variables. Refer to the Environment Variables reference for the complete list. At a minimum, the following must be set to non-placeholder values:| Variable | Notes |
|---|---|
FLASK_ENV | Set to production |
SECRET_KEY | ≥ 32 random characters |
JWT_SECRET_KEY | ≥ 32 random characters |
FERNET_KEY | Generate with Fernet (see env vars page) |
ALLOWED_ORIGINS | The public HTTPS URL of your nginx service |
FRONTEND_BASE_URL | Same as ALLOWED_ORIGINS |
GOOGLE_REDIRECT_URI | https://your-domain/api/contactos/google/callback |
Set DATABASE_URL as a variable reference
In the Railway resolves this reference at deploy time using the connection string from the PostgreSQL plugin. If Railway ever rotates the database credentials, the reference updates automatically without any manual intervention.
backend service’s Variables tab, add DATABASE_URL as a Railway variable reference — not a hardcoded string:Always use
${{ Postgres.DATABASE_URL }} as a variable reference rather than copying the raw connection string. Hardcoded connection strings break silently when Railway rotates credentials during maintenance.Enable Wait for CI on each service
In each service’s Settings tab, enable Wait for CI (or PR Checks). This prevents Railway from deploying a broken build if any GitHub Actions workflow (
ci-python, ci-angular, ci-web) fails on the same commit.Trigger the first deploy
Click Deploy in each service’s dashboard panel, or push a commit to
main. Railway builds each Dockerfile in parallel. Monitor progress in the Deployments tab of each service.After all five services report a green status, verify the API health endpoint through the nginx public domain:HTTPS and TLS
Railway terminates TLS at its edge for any service that has a public domain assigned. From the perspective of the nginx container, all traffic arrives as plain HTTP on port 80 — nocertbot, no ssl_certificate directives, no port 443 listener.
Security headers (Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy) are added by nginx on every response regardless of where TLS is terminated, so they are present end-to-end.
To assign a public domain to the nginx service, go to its Settings tab and click Generate Domain (Railway subdomain) or Custom Domain (your own).
nginx.railway.conf
When thenginx service is built with RAILWAY=true, the Dockerfile copies nginx.railway.conf into the image. This configuration differs from the local nginx.conf in two important ways:
- Upstream hostnames point to
*.railway.internalprivate DNS names (e.g.frontend.railway.internal,backend.railway.internal) instead of the Docker Compose service names. - DNS resolver TTL is kept deliberately short so that nginx picks up new IP addresses quickly after a service is redeployed. Without this, nginx caches the old IP until the worker restarts, causing
502 Bad Gatewayerrors during rolling updates.
502 Bad Gateway on Railway, confirm that:
- All service names in
nginx.railway.confmatch the Railway service names exactly (they are case-sensitive). - The
nginxservice has been redeployed after any rename of a dependent service.

