Deployment
Production hosting for CallMineAI. Assumes you've completed Installation and Configuration.
Build for production
npm ci
npx prisma db push # or: npm run db:migrate
npm run build # prisma generate + next build
npm start # serves on PORT (default 3000)
Recommended production .env:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
NEXT_PUBLIC_APP_URL=https://your-domain.com
AUTH_SECRET=<32+ random chars>
CRON_SECRET=<32+ random chars>
HTTPS is mandatory
Twilio (and SIP/WhatsApp) webhooks require a publicly reachable HTTPS URL. Set APP_URL to your HTTPS domain so the callback URLs resolve correctly.
Keep the app alive (PM2 or systemd)
npm start is a long-running Node process. Supervise it.
PM2:
pm2 start "npm start" --name callmineai --cwd /path/to/callmineai
pm2 start "npm run worker" --name callmineai-worker --cwd /path/to/callmineai
pm2 save && pm2 startup
systemd (/etc/systemd/system/callmineai.service):
[Unit]
Description=CallMineAI (Next.js)
After=network.target mysql.service
[Service]
Type=simple
WorkingDirectory=/path/to/callmineai
EnvironmentFile=/path/to/callmineai/.env
ExecStart=/usr/bin/npm start
Restart=always
User=www-data
[Install]
WantedBy=multi-user.target
Scheduled tasks
The dialer needs the scheduled tasks running. Pick one of the three:
1. The bundled worker — one supervised process, no cron config:
npm run worker
2. Crontab — POST the endpoints directly:
* * * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/dispatch > /dev/null
*/5 * * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/reap-stuck > /dev/null
0 2 * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/grant-monthly > /dev/null
0 3 * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/sync-subscriptions > /dev/null
3. A hosted scheduler — cron-job.org, Upstash QStash, GitHub Actions, or any service that can send an HTTP request on a schedule. Configure each job as POST with the X-Cron-Secret header, same URLs as above.
Vercel Cron needs a small change
Vercel Cron issues a GET and authenticates with Authorization: Bearer $CRON_SECRET. /api/cron/[task] exports POST only and reads X-Cron-Secret, so a vercel.json crons entry returns 405/401 as shipped. On Vercel, use an external scheduler (option 3) or add a GET export + bearer check to src/app/api/cron/[task]/route.js.
Verify it's wired
POST /api/cron/heartbeat with the same secret returns 200 when the schedule can reach the app. Without a running schedule, campaigns queue calls but nothing dials — see Campaigns & Calls.
Reverse proxy
Next.js serves HTTP itself; terminate TLS in front of it. Nginx example:
server {
listen 443 ssl;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Serverless notes (Vercel)
The app runs on Vercel with two caveats:
- Uploads — KB documents and KYC files write to
storage/appon local disk. Serverless filesystems are ephemeral, so point uploads at object storage (or run on a VPS) before going live. - Database connections — use a pooled
DATABASE_URLso Prisma does not exhaust MySQL connections across lambdas.
Go-live checklist
- [ ]
APP_ENV=production,APP_DEBUG=false - [ ]
npm run buildsucceeds;npm start(or Vercel) serving - [ ] HTTPS enabled;
APP_URLandNEXT_PUBLIC_APP_URLset to the HTTPS domain - [ ]
AUTH_SECRETandCRON_SECRETare long random values, not the defaults - [ ]
APP_KEYcopied verbatim if the database holds Laravel-encrypted credentials - [ ] Scheduled tasks running (worker, crontab or Vercel Cron) and
heartbeatreturns200 - [ ] Twilio status/recording callback URLs publicly reachable
- [ ] Changed the default seed passwords
- [ ] ElevenLabs key added + voices synced; OpenAI key set
- [ ] Payment gateways configured (if selling subscriptions)
- [ ] A backup strategy for the database and
storage/
After deploying updates
git pull
npm ci
npx prisma db push # only when the schema changed
npm run build
pm2 restart callmineai callmineai-worker