Railway Deployment
Deploy to Railway for managed hosting.
Railway Setup
1. Install Railway CLI
# macOS
brew install railway
# Or using npm
npm install -g @railway/cli
# Login
railway login
# Verify
railway whoami
2. Initialize Project
# Create new project
railway init
# Or link existing
railway link
3. Add Database
# Add PostgreSQL
railway add postgresql
# Add Redis
railway add redis
Environment Variables
Required Variables
Set these in Railway dashboard (Settings β Variables):
# Database (auto-populated by Railway)
DATABASE_URL=postgresql://... # Auto-configured
# Only set this if your Railway PostgreSQL endpoint rejects SSL upgrade attempts
# DATABASE_SSL_MODE=disable
# JWT
JWT_SECRET=your-secure-jwt-secret-min-32-chars
# Optional startup behavior
DATABASE_REQUIRED_ON_STARTUP=false
# Site URLs
NEXT_PUBLIC_SITE_URL=https://your-app.railway.app
# Frontend -> API routing
# For a single Railway service, NEXT_PUBLIC_API_URL can stay public.
# For split frontend/backend Railway services, prefer the backend private domain here.
INTERNAL_API_URL=http://your-backend.railway.internal:8080
# Optional public API URL if you intentionally expose the backend directly.
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
# Email (optional)
RESEND_API_KEY=re_your_resend_api_key
Railway JSON Config
The API service uses a Dockerfile-based deployment and a liveness health check:
{
"$schema": "https://railway.app/railway.schema.json",
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "infrastructure/docker/Dockerfile.backend"
},
"deploy": {
"numReplicas": 1,
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 10,
"healthcheckPath": "/health",
"healthcheckTimeout": 60
}
}
/health is a liveness endpoint and returns 200 even while the app is still retrying database startup. Use /ready to confirm the database is connected before sending traffic that depends on PostgreSQL.
Database Setup
1. Create Database
In Railway dashboard:
- Go to your project
- Click "New" β "Database" β "PostgreSQL"
- Note the connection string
2. Initialize the Schema
# The API currently bootstraps its tables on startup.
# You can still run ad hoc database commands with Railway CLI if needed.
3. Seed Data (Optional)
railway run python -m src.api.seed
Deploy
1. Deploy to Railway
# Deploy the linked service
railway up
# Or with environment
railway up --environment production
2. View Deployment
# Open in browser
railway open
# View logs
railway logs
# Follow logs
railway logs -f
3. Verify Deployment
# Get deployment URL
railway url
# Test health endpoint
curl https://your-app.railway.app/health
Custom Domain
1. Add Domain
In Railway dashboard:
- Go to project β Settings β Domains
- Add custom domain (e.g., mutx.dev)
- Note the CNAME record
2. Configure DNS
Add CNAME record:
Type: CNAME
Name: mutx.dev
Value: your-app.railway.app
3. SSL
Railway automatically provisions Let's Encrypt SSL.
Multiple Services
For a more complete setup, create multiple Railway services:
Service 1: Frontend (Next.js)
{
"name": "frontend",
"build": {
"builder": "NIXPACKS"
},
"deploy": {
"numReplicas": 2,
"startCommand": "npm run start"
}
}
Service 2: API (FastAPI)
Use the checked-in backend Dockerfile:
infrastructure/docker/Dockerfile.backend
Railway service configs in this repo already point at the canonical backend and frontend Dockerfiles under infrastructure/docker/.
Production Promotion
MUTX v1.3 treats Railway as the production host for:
mutx.devapp.mutx.devapi.mutx.dev
The repo now includes a production-promotion lane for Railway so web/app rollout does not depend on a local operator shell.
GitHub Actions secrets
Set these repository secrets before using the Railway promotion workflow:
RAILWAY_TOKENRAILWAY_PROJECT_IDRAILWAY_FRONTEND_SERVICE_IDRAILWAY_API_SERVICE_IDRAILWAY_ENVIRONMENT_ID
Optional repository variables or workflow inputs:
MUTX_SITE_URLMUTX_APP_URLMUTX_API_URLMUTX_DOCS_RELEASE_URL
Promotion flow
bash scripts/promote-railway-production.sh
bash scripts/verify-production-release.sh
Live production note
Live production project: zooming-youth.
Live Railway production currently runs the backend without an explicit healthcheckPath/healthcheckTimeout in the deployed service manifest, even though repo-side examples may show those fields. Do not change backend Railway healthcheck behavior casually from repo config alone.
Live Railway production currently serves these custom domains:
- frontend custom domains:
mutx.dev,app.mutx.dev - backend custom domain:
api.mutx.dev
Live Railway production also uses this backend preDeployCommand:
python -m pip install -q psycopg2-binary alembic && python -m alembic upgrade head
Treat the backend preDeployCommand as production-critical until Railway and repo config are intentionally reconciled. Use live Railway service manifests as the source of truth before changing production deployment behavior.
The verification step should confirm:
https://mutx.devhttps://mutx.dev/download/macoshttps://app.mutx.dev/loginhttps://app.mutx.dev/registerhttps://app.mutx.dev/dashboardhttps://api.mutx.dev/healthhttps://api.mutx.dev/readyhttps://docs.mutx.dev/docs/v1.3
Create railway.json for API:
{
"name": "api",
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "api/Dockerfile"
},
"deploy": {
"numReplicas": 2,
"startCommand": "uvicorn src.api.main:app --host 0.0.0.0 --port 8000"
}
}
Troubleshooting
Build Failed
# Check build logs
railway logs --type build
Service Not Starting
# Check runtime logs
railway logs --type runtime
# Common issues:
# - Missing environment variables
# - Port not exposed
# - Build command incorrect
Database Connection
# Verify DATABASE_URL
railway variables | grep DATABASE
# Optional: disable SSL if the proxy rejects SSL upgrades
railway variables set DATABASE_SSL_MODE=disable
Custom Domain Not Working
# Verify DNS propagation
dig yourdomain.com
# Check Railway domain status
railway domain list
Maintenance
Update Deployment
# Deploy new version
git push railway main
# Or trigger manually
railway up
Rollback
In Railway dashboard:
- Go to Deployments
- Find previous deployment
- Click "Redeploy"
Scale
In Railway dashboard:
- Go to Settings β Scaling
- Adjust replicas (max 20 on Pro plan)
Quick Reference
# Login
railway login
# Initialize
railway init
# Deploy
railway up
# View logs
railway logs
# Add service
railway add postgresql
# Variables
railway variables
# Custom domain
railway domain add yourdomain.com
