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:
The template provisions three services:
| Service | Purpose |
|---|---|
| Quackback | The application server, including background jobs |
| PostgreSQL | Database with the pgvector extension (pgvector/pgvector image) |
| Bucket | Railway'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
- Go to railway.app/new
- Click Empty Project
2. Add PostgreSQL
- Click + New → Docker Image and enter
pgvector/pgvector:pg17 - Add a volume mounted at
/var/lib/postgresql/data - Set
POSTGRES_DB,POSTGRES_USER, andPOSTGRES_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
- Click + New → Bucket
- Railway provisions S3-compatible storage for uploads
4. Deploy Quackback
- Click + New → Docker Image
- 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=true6. 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
- Go to the Quackback service → Settings → Networking
- Click Generate Domain for a Railway subdomain, or Custom Domain for your own
- If using a custom domain, add a CNAME record pointing to Railway
- Update
BASE_URLto 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_xxxxxxxxxxxxSee 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:
- Back up the PostgreSQL volume and the bucket
- Change the Quackback service's image tag to the new release (or redeploy to pull
latest) - 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:
- Go to your Quackback service
- Click Deployments → select the active deployment
- Click View Logs
Health Check
Railway can restart the service if it becomes unhealthy:
- Go to Settings → Deploy
- Set the health check path to
/api/health/ready(checks database, migrations, and background workers). Use/api/health/liveinstead 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:
| Resource | Estimate |
|---|---|
| Quackback (512 MB RAM) | ~$5/mo |
| PostgreSQL | ~$5/mo |
| Bucket | Depends 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, andBASE_URLare set - More than one email provider configured: the log names the conflicting variables
Database Connection Failed
- Verify the PostgreSQL service is running
- Check that
DATABASE_URLreferences the correct service - 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
- Configuration Reference - All environment variables
- Reverse Proxy - Custom proxy configurations
- Docker Deployment - Alternative deployment with Docker