Deploy KP Rück to Railway with separate services for database, backend, and frontend. This guide also applies broadly to other Docker-compatible PaaS providers.
- Railway account: https://railway.app
- Railway CLI (optional):
npm install -g @railway/cli
Railway will deploy three separate services:
- PostgreSQL - Managed database
- Backend - FastAPI application
- Frontend - Next.js application
- Go to https://railway.app/new
- Click "Deploy from GitHub repo"
- Select your
kp-rueckrepository - Railway will create a new project
- In your Railway project, click "New"
- Select "Database" → "PostgreSQL"
- Railway will provision a PostgreSQL instance
- Note: Railway automatically creates
DATABASE_URLvariable
-
Click "New" → "GitHub Repo" → Select
kp-rueck -
Configure the service:
- Name:
backend - Root Directory:
/backend - Build Command: (Auto-detected from Dockerfile)
- Start Command:
./start.sh
- Name:
-
Add Volume for Photo Storage:
- Go to backend service → Settings → Volumes
- Click "New Volume"
- Mount path:
/mnt/data - Size: 5GB+ (adjust based on expected photo storage needs)
-
Add environment variables:
DATABASE_URL=${{Postgres.DATABASE_URL}} CORS_ORIGINS=https://your-frontend-url.railway.app PHOTOS_DIR=/mnt/data/photos SECRET_KEY=<openssl rand -hex 32> AUTH_SECRET_KEY=<openssl rand -hex 32> ADMIN_SEED_PASSWORD=<strong initial admin password> EDITOR_PASSWORD=<strong shared editor password, or disable this user after first login> PORT=8000 -
Click "Deploy"
-
Click "New" → "GitHub Repo" → Select
kp-rueck -
Configure the service:
- Name:
frontend - Root Directory:
/frontend - Build Command: (Auto-detected from Dockerfile)
- Start Command:
node server.js
- Name:
-
Add environment variables:
NEXT_PUBLIC_API_URL=https://your-backend-url.railway.app PORT=3000 -
Click "Deploy"
After frontend deploys, copy its URL and update backend's CORS_ORIGINS:
CORS_ORIGINS=https://your-frontend-url.railway.app
# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Initialize project
railway init
# Link to project
railway link
# Deploy backend
cd backend
railway up
# Deploy frontend
cd ../frontend
railway up
# Add database
railway add --database postgresql| Variable | Value | Description |
|---|---|---|
DATABASE_URL |
${{Postgres.DATABASE_URL}} |
Auto-linked from PostgreSQL service |
CORS_ORIGINS |
https://your-frontend.railway.app |
Frontend URL for CORS |
PHOTOS_DIR |
/mnt/data/photos |
Photo storage directory. Must point inside the mounted Railway volume |
SECRET_KEY |
Generated 32-byte hex string | Signs public check-in, Reko, viewer, and alarm-intake tokens |
AUTH_SECRET_KEY |
Generated 32-byte hex string | Signs login access and refresh JWTs |
ADMIN_SEED_PASSWORD |
Strong password, 12+ characters | Required for the initial admin user when the database is first seeded |
EDITOR_PASSWORD |
Strong password, 12+ characters | Password for the seeded shared editor account. Set this explicitly or disable the account after first login |
PORT |
8000 |
Port (Railway sets automatically) |
Important: The PHOTOS_DIR environment variable must point to the volume mount path. Without this, photos will be stored in ephemeral container storage and lost on restart.
Generate secrets locally with:
openssl rand -hex 32SECRET_KEY and AUTH_SECRET_KEY protect different token families in the backend. They can be generated the same way, but should be stored as separate Railway variables.
| Variable | Value | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
https://your-backend.railway.app |
Backend API URL |
PORT |
3000 |
Port (Railway sets automatically) |
The backend's start.sh script automatically:
- Creates database tables
- Seeds initial data (on first run)
- Frontend: https://your-frontend.railway.app
- Backend API: https://your-backend.railway.app/docs
- Health Check: https://your-backend.railway.app/health
View logs in Railway dashboard:
- Click on each service
- Navigate to "Deployments" tab
- Click "View Logs"
Each service has a railway.json file:
Backend (backend/railway.json):
{
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "Dockerfile"
},
"deploy": {
"startCommand": "uv run uvicorn app.main:app --host 0.0.0.0 --port $PORT",
"healthcheckPath": "/health"
}
}Frontend (frontend/railway.json):
{
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "Dockerfile"
},
"deploy": {
"startCommand": "node server.js"
}
}Railway automatically handles:
- Database → Backend: Use
${{Postgres.DATABASE_URL}}reference - Backend → Frontend: Set
NEXT_PUBLIC_API_URLto backend URL - Service Discovery: Internal networking between services
- Go to service settings
- Click "Settings" → "Domains"
- Click "Generate Domain" or add custom domain
- Update CORS and API URL environment variables accordingly
Railway allows horizontal scaling:
- Go to service settings
- Adjust "Replicas" count
- Backend and Frontend can scale independently
Railway PostgreSQL includes:
- Automatic daily backups
- Point-in-time recovery
- Manual snapshot creation
If the Railway database contains stale data with incorrect enum values, you can reset it:
- Go to your Railway project
- Click on the PostgreSQL service
- Go to "Data" tab
- Click "Reset Database" (this will delete all data and tables)
- Redeploy the backend service to trigger automatic re-seeding
# Connect to Railway project
railway link
# Open Railway shell for backend service
railway run bash
# Inside the shell, reset database
PGPASSWORD=$PGPASSWORD psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
# Exit shell
exit
# Trigger redeployment to re-seed
railway up- Open Railway dashboard
- Navigate to PostgreSQL service → "Data" tab
- Run SQL query:
DROP SCHEMA public CASCADE; CREATE SCHEMA public;
- Redeploy backend service
After reset, the backend's start.sh script will automatically:
- Run Alembic migrations to recreate tables
- Seed initial data with correct values
- Check
DATABASE_URLis set correctly - Verify PostgreSQL service is running
- Check logs for connection errors
- Verify
NEXT_PUBLIC_API_URLis set - Check backend CORS settings
- Ensure backend service is deployed and healthy
- Check Dockerfile syntax
- Verify all dependencies are listed
- Review build logs in Railway dashboard
Railway pricing (as of 2024):
- Hobby Plan: $5/month + usage
- PostgreSQL: ~$5-10/month
- Compute: Pay for what you use
- Bandwidth: Generous free tier
The backend supports photo uploads for Reko (reconnaissance) reports. Photos require persistent storage to survive container restarts.
-
Attach Volume to Backend Service:
- Railway Dashboard → Backend Service → Settings → Volumes
- Click "New Volume"
- Mount path:
/mnt/data - Size: 5GB+ (recommended)
-
Set Environment Variable:
PHOTOS_DIR=/mnt/data/photos
-
Verify Setup:
- Check backend logs during startup for:
Photo storage directory: /mnt/data/photos Photos directory ready: /mnt/data/photos
- Check backend logs during startup for:
- Average photo after compression: ~200KB
- Max photos per report: 20
- Max size per report: ~4MB
Storage needs:
- 100 reports: ~400MB
- 1,000 reports: ~4GB
- 10,000 reports: ~40GB
Photos disappear after restart:
- Verify
PHOTOS_DIR=/mnt/data/photosis set - Check volume is mounted at
/mnt/data - Review backend startup logs
Upload fails:
- Check volume has available space
- Verify mount path is correct
- Review backend error logs
Detailed Documentation:
See docs/PHOTO_STORAGE.md for comprehensive photo storage documentation, including:
- API endpoints
- Testing procedures
- Security considerations
- Performance optimization
- Set strong PostgreSQL password
- Enable Railway's built-in DDoS protection
- Set up custom domain with SSL
- Configure backend environment variables:
DATABASE_URL,CORS_ORIGINS,PHOTOS_DIR,SECRET_KEY,AUTH_SECRET_KEY,ADMIN_SEED_PASSWORD,EDITOR_PASSWORD - Configure frontend environment variables:
NEXT_PUBLIC_API_URLand, if needed,NEXT_PUBLIC_WS_URL - Attach volume for photo storage (
/mnt/data) - Set
PHOTOS_DIR=/mnt/data/photosenvironment variable - Verify backend startup logs show
Photo storage directory: /mnt/data/photosandPhotos directory ready: /mnt/data/photos - Enable automatic deployments from
mainbranch - Set up monitoring and alerts
- Configure backups retention policy
- Review and optimize resource allocation
- Railway Docs: https://docs.railway.app
- Railway Discord: https://discord.gg/railway
- GitHub Issues: https://github.com/railwayapp/railway/issues