Deployment
How to run SubsTrack in production (Docker, Vercel, and cron).
Deployment
SubsTrack can be self-hosted or run on a platform. You need: Node.js 20+, MongoDB, and (optionally) Resend and a Telegram bot.
Environment variables
Set at least:
MONGODB_URI— MongoDB connection stringNEXTAUTH_SECRET— random secret (e.g.openssl rand -base64 32)NEXTAUTH_URL— public URL of the app (e.g.https://substrack.example.com)RESEND_API_KEY— if using ResendEMAIL_FROM— sender addressCONFIRMATION_SECRET— for “I’ve paid” linksCRON_SECRET— for cron API routes
Optional: TELEGRAM_BOT_TOKEN, TELEGRAM_WEBHOOK_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET.
See Environment variables for the full list.
Docker (self-hosted)
From the repo root:
cp .env.example .env.local
# edit .env.local with your values
docker-compose up -d
This starts:
- app — Next.js on port 3000
- mongo — MongoDB on 27017
- cron — node-cron runner (billing, enqueue reminders/follow-ups, notification worker; same image, different command)
Build: docker-compose build. Logs: docker-compose logs -f app.
Manual (Node + MongoDB)
- Install Node 20+ and MongoDB.
- Clone the repo, run
npm ci, copy.env.exampleto.env.localand fill it. - Build:
npm run build. - Start app:
npm start(port 3000 by default). - Start cron (separate process):
npm run cron.
Use a process manager (systemd, PM2) to keep both running.
Vercel (or similar)
- Deploy the Next.js app (e.g. connect GitHub to Vercel).
- Set env vars in the dashboard; add
MONGODB_URI(e.g. Atlas). - The app runs as serverless; cron does not run inside Vercel. Options:
- External cron: Use Vercel Cron or an external service (cron-job.org, GitHub Actions) to call:
POST /api/cron/billing(daily)POST /api/cron/reminders(daily)POST /api/cron/follow-ups(e.g. every 3 days)POST /api/cron/notification-tasks(every 5 min) with thex-cron-secretheader.
- Separate worker: Run the cron runner (
npm run cron) on a small VPS or Railway; it will enqueue tasks and run the notification worker every 5 min.
- External cron: Use Vercel Cron or an external service (cron-job.org, GitHub Actions) to call:
Telegram
- Polling — Run the bot in a long-lived process (e.g. same server as the app or a separate container) that calls grammy’s polling. No public URL needed for the bot.
- Webhook — Set the bot webhook to
https://your-domain.com/api/telegram/webhookand ensure that route verifies the webhook secret. Then the Next.js app handles updates; no separate bot process.
HTTPS
Use HTTPS in production. Set NEXTAUTH_URL and APP_URL to the https:// URL. If you use a reverse proxy (Nginx, Caddy), terminate SSL there and proxy to the app.
Database
- MongoDB Atlas — Create a cluster, whitelist IPs or use VPC peering, set
MONGODB_URIin env. - Self-hosted MongoDB — Install and run MongoDB, create a database (e.g.
substrack), setMONGODB_URI=mongodb://host:27017/substrack.
No migrations required; Mongoose creates collections and indexes on first use.