HomeSelf-host
Self-host rightnow-ai
rightnow-ai runs only on hardware you control. This guide covers both supported ways: Docker Compose on your own computer, and the same stack on a Linux VPS with Caddy for HTTPS.
The interactive walkthrough needs JavaScript. Every command is also written out below.
Before you begin
| Section | Check |
|---|---|
| Docker | Docker Desktop (Windows, macOS) or Docker Engine with the Compose plugin (Linux) |
| git | To clone the repository and pull upgrades |
| Secrets | openssl, or the generator in the walkthrough above |
| VPS only | 1 vCPU / 2 GB RAM to start, a domain with an A record, inbound ports 22, 80 and 443 |
| Gmail, Microsoft | Your own Google OAuth client and Microsoft Entra app (guides linked below) |
Run it on your laptop
git clone https://github.com/AnalyticDog13/rightnow-ai.git
cd rightnow-ai
cp .env.example .envIn .env, set ENCRYPTION_KEY and BETTER_AUTH_SECRET (openssl rand -base64 32 each) and a SETUP_TOKEN of 16 or more characters. Leave MODE=local and APP_URL=http://localhost:3000.
scripts/start.sh
# Windows (PowerShell): powershell -ExecutionPolicy Bypass -File scripts\start.ps1 · the first build takes a few minutesOpen http://localhost:3000/sign-up and create the owner account with your SETUP_TOKEN. Sign-up closes after the first owner; everyone else joins by invite. Always open the app at the exact host in APP_URL (localhost, not 127.0.0.1), or every form submission is rejected.
While the laptop sleeps
Nothing sends or syncs while the machine is asleep. On wake, a mailbox may send only after a sync in the last 5 minutes (SYNC_MAX_STALENESS_SEC=300), so replies, bounces and unsubscribes are seen first. Missed sends go out late inside their schedule window, or wait for the next window, never as a burst. A send that was in flight is never resent automatically: it is looked for in the Sent folder, and held if it isn't found twice, 15 minutes apart.
Tracking needs a public address
On localhost, recipients cannot reach your tracking or one-click unsubscribe links, so emails carry a mailto-only unsubscribe and open and click tracking is off. Run on a VPS (or behind a tunnel, for tests only) for tracking.
Dry-run mode
Set MAIL_PROVIDER_FAKE=1 in .env to replace Gmail, Microsoft and IMAP/SMTP with an in-process fake mailbox. You can connect accounts, launch a campaign and watch the whole pipeline run without contacting a provider. The app refuses this flag when MODE=vps.
Run it on a VPS
The same Compose file runs on the server; MODE=vps adds the caddy service, which gets a Let's Encrypt certificate automatically.
- A Linux VPS with Docker Engine, the Compose plugin and git (1 vCPU / 2 GB RAM is enough to start).
- Point an
Arecord (andAAAAwith IPv6) for your domain at the server and wait until it resolves. - Allow inbound 22, 80 and 443 only. Postgres is not published and the web port is bound to 127.0.0.1.
ufw allow 22,80,443/tcp && ufw enable
git clone https://github.com/AnalyticDog13/rightnow-ai.git && cd rightnow-ai
cp .env.example .envMODE=vps
DOMAIN=app.example.com
APP_URL=https://app.example.com
ENCRYPTION_KEY=<openssl rand -base64 32>
BETTER_AUTH_SECRET=<openssl rand -base64 32>
SETUP_TOKEN=<16+ random characters>
POSTGRES_PASSWORD=<openssl rand -hex 24> # set before the first startThen run scripts/start.sh, open https://app.example.com/sign-up and create the owner with your SETUP_TOKEN.
Private hosts. Webhook URLs, the AI base URL and the email-verifier URL must be public by default. ALLOW_PRIVATE_HTTP_HOSTS=1 lets them reach your private network (for example a local Ollama server). Cloud metadata and link-local addresses stay blocked whatever the setting.
Connect Gmail and Microsoft
Gmail and Google Workspace
- Create a Google Cloud project and enable the Gmail API.
- Configure the OAuth consent screen and set it to "In production": an app left in "Testing" gets refresh tokens that expire after 7 days.
- Create a Web application OAuth client with the redirect URI
${APP_URL}/api/v1/oauth/google/callback. - Put
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETin.envand restart. - In the app: Email Accounts, then Connect Google. Full guide: GOOGLE_SETUP.md.
Microsoft 365 and Outlook.com
- Register an app in Microsoft Entra for organizational and personal accounts.
- Add the Web redirect URI
${APP_URL}/api/v1/oauth/microsoft/callback. - Create a client secret and note its expiry date.
- Add the delegated Graph permissions
Mail.Send,Mail.ReadWrite,offline_accessandUser.Read. - Put
MS_CLIENT_ID,MS_CLIENT_SECRETandMS_TENANT=commonin.env. Full guide: MICROSOFT_SETUP.md.
Any other provider connects over IMAP/SMTP with a host, username and password (an app password where the provider requires one). Before the first real campaign from a provider, run its one-time live check: npx tsx scripts/live-verify.ts --account <id> --to <another address of yours>. Campaign sending from a provider stays off until it passes.
Sending limits per mailbox
The daily limit you set is never allowed above half of the provider's rolling 24-hour cap. Calendar-day counting is only safe against a rolling window with that margin. Larger values are saved at the maximum and the page tells you so.
| Account type | Provider cap (default / highest you can set) | Highest daily limit | Minimum gap |
|---|---|---|---|
| Google Workspace | 1500 / 2000 | 750 | none |
| Gmail (gmail.com) | 400 / 500 | 200 | none |
| Microsoft 365 | 5000 / 10000 | 2500 | 3 s |
| Outlook.com, Hotmail, Live | 250 / 300 | 125 | 3 s |
| SMTP | 100 / 10000 | 50 | none |
New accounts start at 30 a day (or the maximum, if lower). Counts follow the account's own timezone.
Backups, restore and upgrades
| Task | Command |
|---|---|
| Start | scripts/start.sh |
| Stop (data is kept) | scripts/stop.sh |
| Backup | scripts/backup.sh writes backups/rightnow-<timestamp>.dump |
| Restore | scripts/restore.sh backups/rightnow-<timestamp>.dump (replaces current data; asks for yes) |
| Upgrade | scripts/upgrade.sh: backs up, then git pull, rebuild, migrations, restart |
Windows uses the matching .ps1 scripts. Data lives in the Docker volume pgdata; the scripts never delete it.
Back up ENCRYPTION_KEY with your database. Your mailbox logins are encrypted with it; a backup restored without the same key cannot read them.
A restore pauses every active campaign. Messages sent after the dump was taken are recognised from the Sent folders and not sent again. Resume the campaigns only after every mailbox shows a sync completed since the restore.
On a VPS, back up nightly with cron and copy backups/ off the server, keeping the key somewhere separate:
0 3 * * * cd /home/you/rightnow-ai && mkdir -p backups && scripts/backup.sh >> backups/cron.log 2>&1 && find backups -name '*.dump' -mtime +14 -deleteMoving from a laptop to a VPS
- Stop the local stack and keep it stopped: two installs must never sync or send from one mailbox.
- On the laptop, run
scripts/backup.sh. - Copy the dump and your
ENCRYPTION_KEYto the server out of band. - Set up the VPS as above with the same
ENCRYPTION_KEY; do not start it yet. - Run
scripts/restore.sh <dump>(it pauses active campaigns), then start the stack. - Sign in, check
/api/readyzand each mailbox's state, and download one attachment by hand. - Add the new domain's redirect URIs in Google and Microsoft and reconnect any mailbox that needs attention.
- Switch DNS and tracking-domain CNAMEs only after these checks pass.
- Never restart the local install afterwards: it would send the same mail a second time.
Why not Vercel, Netlify or serverless?
rightnow-ai needs a PostgreSQL database and a background worker that runs all the time to sync mailboxes, warm up and send on schedule. The Compose stack has five services: postgres (data and the job queue), migrate (applies database migrations, then exits), web (the app and REST API), worker (sync, scheduling, sending, warm-up) and, with MODE=vps, caddy (HTTPS). Vercel and Netlify run short-lived functions and static files, so they cannot host the worker or the database. Only this documentation site is static.