Skip to content

Deploy to Railway

Railway handles infrastructure so you can focus on collecting feedback. One click gives you Quackback, PostgreSQL, and a storage bucket with automatic SSL and no server management.

Prerequisites

  • A Railway account (free tier available)
  • A domain or subdomain for your instance (e.g., feedback.yourcompany.com)

One-Click Deploy

Click the button below to deploy Quackback to Railway:

Deploy on Railway

The template provisions three services:

ServicePurpose
QuackbackThe application server, including background jobs
PostgreSQLDatabase with the pgvector extension (pgvector/pgvector image)
BucketRailway's S3-compatible storage for file uploads

The template sets TRUSTED_PROXY_HOPS=1, because Railway's edge proxies every request. If you turn on Railway's CDN in front of the service, change it to 2.

Manual Setup

If you prefer to configure each service yourself:

1. Create a New Project

  1. Go to railway.app/new
  2. Click Empty Project

2. Add PostgreSQL

  1. Click + New → Docker Image and enter pgvector/pgvector:pg17
  2. Add a volume mounted at /var/lib/postgresql/data
  3. Set POSTGRES_DB, POSTGRES_USER, and POSTGRES_PASSWORD

Quackback requires PostgreSQL 14+ with pgvector 0.5.0+ and pg_trgm. The pgvector/pgvector image includes both. Connect over Railway's private network directly, not through a transaction-mode pooler: realtime updates use LISTEN/NOTIFY.

3. Add a bucket

  1. Click + New → Bucket
  2. Railway provisions S3-compatible storage for uploads

4. Deploy Quackback

  1. Click + New → Docker Image
  2. Enter ghcr.io/quackbackio/quackback:latest (or pin a release tag)

5. Configure Environment Variables

In the Quackback service settings, add these variables:

DATABASE_URL=postgresql://quackback:${{postgres.POSTGRES_PASSWORD}}@${{postgres.RAILWAY_PRIVATE_DOMAIN}}:5432/quackback
 
# Authentication, 32+ characters (generate with: openssl rand -base64 32)
SECRET_KEY=your-32-character-minimum-secret-key
 
# Public URL (set after assigning a domain)
BASE_URL=https://feedback.yourcompany.com
 
# Railway's edge is one proxy hop (use 2 if Railway's CDN is enabled)
TRUSTED_PROXY_HOPS=1
 
# Storage bucket
S3_ENDPOINT=${{Bucket.ENDPOINT}}
S3_BUCKET=${{Bucket.BUCKET}}
S3_REGION=${{Bucket.REGION}}
S3_ACCESS_KEY_ID=${{Bucket.ACCESS_KEY_ID}}
S3_SECRET_ACCESS_KEY=${{Bucket.SECRET_ACCESS_KEY}}
S3_FORCE_PATH_STYLE=true

6. Set the health check

Go to the Quackback service → Settings → Deploy and set the health check path to /api/health/ready. The first start after an upgrade runs migrations, so allow a generous timeout (the template uses 300 seconds).

7. Add a Domain

  1. Go to the Quackback service → Settings → Networking
  2. Click Generate Domain for a Railway subdomain, or Custom Domain for your own
  3. If using a custom domain, add a CNAME record pointing to Railway
  4. Update BASE_URL to match

Railway provides automatic SSL for all domains. No certificate configuration needed.

Email Configuration

Without email, OTP codes are printed to Railway logs. For production, configure exactly one sending provider: SMTP, Amazon SES, or Resend. If more than one is set, the app refuses to start and names the conflicting variables.

# SMTP
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USER=your-username
EMAIL_SMTP_PASS=your-password
EMAIL_FROM=Quackback <feedback@yourcompany.com>
 
# Or Amazon SES (all three keys required)
# EMAIL_SES_ACCESS_KEY_ID=AKIA...
# EMAIL_SES_SECRET_ACCESS_KEY=...
# EMAIL_SES_REGION=us-east-1
 
# Or Resend
# EMAIL_RESEND_API_KEY=re_xxxxxxxxxxxx

See Email for details.

File Storage

The template's Railway bucket stores uploads. Files are served through the app at /api/storage, so the bucket can stay private. To use another provider instead (AWS S3, Cloudflare R2, Backblaze B2), point the S3_* variables at it. See File storage.

Upgrades

Migrations run on every startup, so schema changes apply when the new image starts.

To upgrade a template deployment:

  1. Back up the PostgreSQL volume and the bucket
  2. Change the Quackback service's image tag to the new release (or redeploy to pull latest)
  3. Watch the deploy logs until migrations finish and the health check passes

Upgrading from 0.13? Follow Upgrade from 0.13 to 0.14. Remove the old Redis service and REDIS_URL variable, and add TRUSTED_PROXY_HOPS=1.

Monitoring

Logs

View real-time logs in the Railway dashboard:

  1. Go to your Quackback service
  2. Click Deployments → select the active deployment
  3. Click View Logs

Health Check

Railway can restart the service if it becomes unhealthy:

  1. Go to Settings → Deploy
  2. Set the health check path to /api/health/ready (checks database, migrations, and background workers). Use /api/health/live instead if you only want to confirm the process is up.

Cost

Railway bills based on usage. A typical Quackback instance costs $5 to $20 a month depending on traffic:

ResourceEstimate
Quackback (512 MB RAM)~$5/mo
PostgreSQL~$5/mo
BucketDepends on stored files

Railway's free trial includes $5 of usage. After that, the Hobby plan starts at $5/month with $5 of included usage.

Troubleshooting

Deploy Fails

Check the build logs for errors. Common causes:

  • Missing environment variables: make sure DATABASE_URL, SECRET_KEY, and BASE_URL are set
  • More than one email provider configured: the log names the conflicting variables

Database Connection Failed

  1. Verify the PostgreSQL service is running
  2. Check that DATABASE_URL references the correct service
  3. Try restarting the Quackback service

"Port Already in Use"

Railway assigns a port via the PORT environment variable. Quackback reads this automatically. Do not hardcode a port.

Next Steps