Skip to main content
For the fastest setup, see the Quick Start.
This guide covers production deployment on a VPS using Docker and Docker Compose.

Prerequisites

Requirements

  • VPS with Minimum 2GB RAM, 2 CPU cores, 20GB storage and linux distribution with minimum security
  • Domain name pointed to your VPS IP
  • SSH access to your VPS

Step-by-Step VPS Setup

1. Prepare Your VPS

Connect to your VPS and install:
  1. Docker Engine: Follow the official guide and the Post installation steps
  2. Node.js: Follow the official guide (required for the setup CLI)

2. Setup and Configure

The easiest way to get started is with the Inbox Zero CLI. You can either use it standalone or from within the cloned repo. Option A: Standalone (no clone needed)
npx @inbox-zero/cli setup
This downloads the Docker Compose file and .env template automatically. Option B: From the cloned repo
git clone https://github.com/elie222/inbox-zero.git
cd inbox-zero
npm install
npm run setup
The setup wizard will walk you through configuring Google OAuth, choosing an AI provider, and generating secrets. Optional: Automated Google Cloud Setup If you have the gcloud CLI installed, you can automate API enabling and Pub/Sub setup:
npx inbox-zero setup-google --project-id YOUR_PROJECT_ID --domain yourdomain.com
This command enables required APIs, creates the Pub/Sub topic and subscription, and guides you through OAuth credential creation. You can also copy .env.example to .env and set the values yourself. If doing this manually edit then you’ll need to configure:
  • Google OAuth: GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET
  • LLM Provider: Uncomment one provider block and add your API key
  • Optional: Microsoft OAuth, external Redis, etc.
For detailed configuration instructions, see the Environment Variables Reference. Note: If you only want to use Microsoft and not Google OAuth then add skipped for the the Google client id and secret. Note: The first section of .env.example variables that are commented out. If you’re using Docker Compose leave them commented - Docker Compose sets these automatically with the correct internal hostnames.

4. Deploy

Pull and start the services with your domain:
NEXT_PUBLIC_BASE_URL=https://yourdomain.com docker compose --profile all up -d
The pre-built Docker image is hosted at ghcr.io/elie222/inbox-zero:latest and will be automatically pulled. Important: The NEXT_PUBLIC_BASE_URL must be set as a shell environment variable when running docker compose up (as shown above). Setting it in apps/web/.env will not work because docker-compose.yml overrides it.

Using External Database Services (Optional)

The docker-compose.yml supports different deployment modes using profiles:
ProfileDescriptionUse when
--profile allIncludes Postgres and Redis containersDefault, simplest setup
--profile local-redisLocal Redis onlyUsing managed Postgres (RDS, Neon, Supabase)
--profile local-dbLocal Postgres onlyUsing managed Redis (Upstash, ElastiCache)
(no profile)No local databasesUsing managed services for both (production recommended)
For external services, set the appropriate environment variables in apps/web/.env:
  • External Postgres: Set DATABASE_URL and DIRECT_URL
  • External Redis: Set UPSTASH_REDIS_URL and UPSTASH_REDIS_TOKEN

5. Check Logs

Wait for the containers to start, then run the database migrations:
# Check that containers are running (STATUS should show "Up")
docker ps
# Check logs. This can take 30 seconds to complete
docker logs inbox-zero-services-web-1 -f

6. Access Your Application

Your application should now be accessible at:
  • http://your-server-ip:3000 (if accessing directly)
  • https://yourdomain.com (if you’ve set up a reverse proxy with SSL)
Note: For production deployments, you should set up a reverse proxy (like Nginx, Caddy, or use a cloud load balancer) to handle SSL/TLS termination and route traffic to your Docker container.

Scheduled Tasks

The Docker Compose setup includes a cron container that handles scheduled tasks automatically:
TaskFrequencyEndpointCron ExpressionDescription
Scheduled actionsEvery minute/api/cron/scheduled-actions* * * * *Executes delayed/scheduled actions when QStash is not configured
Email watch renewalEvery 6 hours/api/watch/all0 */6 * * *Renews Gmail/Outlook push notification subscriptions
Meeting briefsEvery 15 minutes/api/meeting-briefs*/15 * * * *Sends pre-meeting briefings to users with the feature enabled
Follow-up remindersEvery 30 minutes/api/follow-up-reminders*/30 * * * *Processes follow-up reminder notifications
If you’re not using Docker Compose you need to set up cron jobs manually:
# Scheduled actions - every minute (only needed when QStash is not configured)
* * * * * curl -s -X GET "https://yourdomain.com/api/cron/scheduled-actions" -H "Authorization: Bearer YOUR_CRON_SECRET"

# Email watch renewal - every 6 hours
0 */6 * * * curl -s -X GET "https://yourdomain.com/api/watch/all" -H "Authorization: Bearer YOUR_CRON_SECRET"

# Meeting briefs - every 15 minutes (optional, only if using meeting briefs feature)
*/15 * * * * curl -s -X GET "https://yourdomain.com/api/meeting-briefs" -H "Authorization: Bearer YOUR_CRON_SECRET"

# Follow-up reminders - every 30 minutes (optional, only if using follow-up reminders feature)
*/30 * * * * curl -s -X GET "https://yourdomain.com/api/follow-up-reminders" -H "Authorization: Bearer YOUR_CRON_SECRET"
Replace YOUR_CRON_SECRET with the value of CRON_SECRET from your .env file.

Optional: QStash for Advanced Features

Upstash QStash is a serverless message queue that enables scheduled and delayed actions. It’s optional but recommended for the full feature set. When QStash isn’t configured, we fall back to internal API calls and cron for scheduled actions. This works without QStash, but lacks built-in retries/deduping. Features that benefit from QStash:
FeatureWithout QStashWith QStash
Email digest✅ Works (sync, no retries)✅ Full support
Delayed/scheduled email actions✅ Works via cron fallback✅ Full support
AI categorization of senders*✅ Works (sync)✅ Works (async with retries)
Bulk inbox cleaning*✅ Works (sync, no throttling)✅ Full support
*Early access features - available on the Early Access page. Cost: QStash has a generous free tier and scales to zero when not in use. See QStash pricing. Setup: Add your QStash credentials to .env:
QSTASH_TOKEN=your-qstash-token
QSTASH_CURRENT_SIGNING_KEY=your-signing-key
QSTASH_NEXT_SIGNING_KEY=your-next-signing-key
Adding alternative scheduling backends (like Redis-based scheduling) for self-hosted users is on our roadmap.

Building from Source (Optional)

If you prefer to build the image yourself instead of using the pre-built one:
# Clone the repository
git clone https://github.com/elie222/inbox-zero.git
cd inbox-zero

# Install dependencies and configure environment (auto-generates secrets)
npm install
npm run setup
nano apps/web/.env

# Build and start
docker compose build
NEXT_PUBLIC_BASE_URL=https://yourdomain.com docker compose --profile all up -d
Note: Building from source requires significantly more resources (4GB+ RAM recommended) and takes longer than pulling the pre-built image. Having issues? See the Troubleshooting page for solutions to common problems.