- Web App (Next.js): Deployed to Vercel
- Worker (Node.js + FFmpeg/LibreOffice): Deployed to Railway via Docker
- Database (PostgreSQL): Managed PostgreSQL (e.g., Railway, Supabase, Neon)
- Cache/Queue (Redis): Managed Redis (e.g., Railway, Upstash)
- Storage (Cloudflare R2): S3-compatible object storage
- Connect your GitHub repository to Vercel
- Set the Root Directory to
apps/web - Set the Framework Preset to
Next.js - Set the Build Command to:
cd ../.. && pnpm install && pnpm db:generate && pnpm --filter @fluxfile/web build - Set the Install Command to:
pnpm install
Set these in the Vercel dashboard:
DATABASE_URL=postgresql://...
REDIS_URL=redis://...
R2_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET_NAME=fluxfile
BETTER_AUTH_SECRET=<random-secret>
BETTER_AUTH_URL=https://fluxfile.aspekts.dev
RESEND_API_KEY=re_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
SENTRY_DSN=https://...@sentry.io/...
NODE_ENV=production
- Add
fluxfile.aspekts.devas a custom domain in Vercel - Configure DNS to point to Vercel's nameservers
The .github/workflows/deploy-web.yml workflow automatically deploys to Vercel on pushes to main that affect web app or package files.
The worker runs as a Docker container with FFmpeg, LibreOffice, and other conversion tools pre-installed.
- Create a new Railway project
- Add a service from the Docker image
- Point to the
docker/Dockerfile.workerin the repository
Set these in Railway:
DATABASE_URL=postgresql://...
REDIS_URL=redis://...
R2_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET_NAME=fluxfile
WORKER_ID=worker-railway-01
WORKER_CONCURRENCY_AUDIO=5
WORKER_CONCURRENCY_VIDEO=2
WORKER_CONCURRENCY_DOCUMENT=5
WORKER_CONCURRENCY_IMAGE=20
NODE_ENV=production
To handle more conversions, scale horizontally by adding more worker instances. Each worker automatically picks jobs from the shared Redis queue. Assign unique WORKER_ID values to each instance.
The .github/workflows/deploy-worker.yml workflow builds the Docker image, pushes to GHCR, and deploys to Railway on pushes to main that affect worker or package files.
- Add a PostgreSQL plugin to your Railway project
- Copy the
DATABASE_URLfrom Railway's variables
- Create a project at neon.tech
- Copy the connection string
- Create a project at supabase.com
- Copy the connection string from Settings > Database
After setting DATABASE_URL, run:
pnpm db:generate
pnpm db:migrate
pnpm db:seed # Only for initial setup- Add a Redis plugin to your Railway project
- Copy the
REDIS_URL
- Create a database at upstash.com
- Copy the Redis URL (use the
redis://format, not REST)
- Go to Cloudflare Dashboard > R2
- Create a bucket named
fluxfile - Create an API token with read/write permissions
- Note down:
- Account ID (from Cloudflare dashboard)
- Access Key ID (from API token)
- Secret Access Key (from API token)
- Set
R2_ENDPOINTtohttps://<account-id>.r2.cloudflarestorage.com
Configure CORS on the R2 bucket to allow uploads from your domain:
[
{
"AllowedOrigins": ["https://fluxfile.aspekts.dev"],
"AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]- Create a Sentry project
- Set
SENTRY_DSNin both web and worker environments
- Web app: Vercel handles health checks automatically
- Worker: Docker
HEALTHCHECKinstruction included in Dockerfile
- All environment variables set in Vercel and Railway
- Database migrations applied
- R2 bucket created with CORS configured
- Custom domain configured and DNS propagated
- Stripe webhooks configured for
fluxfile.aspekts.dev/api/webhooks/stripe - Resend domain verified for
fluxfile.aspekts.dev - Sentry configured for error monitoring
- Worker instances scaled appropriately
- SSL/TLS verified on all endpoints
- Tested a full conversion flow end-to-end