Deployment
Deployment
Docker, self-hosted, and environment setup
Overview
Deploy Mail Panda on any platform that supports Node.js. The application uses SQLite as its database, so there is no external database to provision or manage. You can run it as a standalone Node.js process, inside a Docker container, or on any platform that supports Next.js applications.
Environment Variables
Create a .env.local file in the project root with the following variables. Only NEXT_PUBLIC_APP_URL is strictly required for production — the rest are optional depending on your setup.
# App URL (required for production)
NEXT_PUBLIC_APP_URL=https://mail.yourdomain.com
# Resend API key for production email delivery
# Leave empty to use the built-in SMTP server
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxx
# Anthropic API key for AI features (subject generation, smart send times)
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxxxxxx
# DKIM signing for improved deliverability
DKIM_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----...
DKIM_SELECTOR=default
DKIM_DOMAIN=yourdomain.com
# Stripe for billing (optional)
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
# Session secret (auto-generated if not set)
SESSION_SECRET=a-random-secret-stringDocker
The recommended way to deploy in production is with Docker. Below is a minimal Dockerfile and a docker-compose configuration.
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
ENV NODE_ENV=production
EXPOSE 3000
CMD ["npm", "start"]version: "3.8"
services:
mailpanda:
build: .
ports:
- "3000:3000"
volumes:
- mailpanda-data:/app/data
env_file:
- .env.local
restart: unless-stopped
volumes:
mailpanda-data:The mailpanda-data volume persists the SQLite database between container restarts. Run docker compose up -d to start the service in the background.
Self-Hosted
For a traditional self-hosted deployment without Docker, clone the repository and run the production build directly. SQLite is embedded, so no external database setup is needed.
git clone https://github.com/mailpanda/mailpanda.git
cd mailpanda
npm install
npm run build
npm startThe application will start on port 3000 by default. Use a process manager like pm2 or systemd to keep the process running and restart it on failures.
Deploy Anywhere
Mail Panda runs on any backend that supports Node.js 18+. No external database is required — SQLite is embedded and the entire state lives in a single file.
- VPS — Ubuntu, Debian, or any Linux server with Node.js installed
- Docker — single container with a volume mount for SQLite persistence
- Railway / Render / Fly.io — connect your repo, set environment variables, deploy
- Kubernetes — use the included Dockerfile and mount a PersistentVolumeClaim for
/app/db
# Example: systemd service file
[Unit]
Description=Mail Panda
After=network.target
[Service]
Type=simple
User=mailpanda
WorkingDirectory=/opt/mailpanda
ExecStart=/usr/bin/node server.js
Restart=on-failure
Environment=NODE_ENV=production
Environment=PORT=3000
[Install]
WantedBy=multi-user.targetProduction Tips
Follow these recommendations to harden your production deployment:
- Reverse proxy — Place nginx or Caddy in front of the Node.js process to handle TLS termination, HTTP/2, and static file caching.
- DKIM signing — Configure DKIM keys for your sending domain to improve email deliverability and reduce spam classification.
- Database backups — Set up daily backups of the SQLite database file. A simple cron job that copies the
data/mailpanda.dbfile to a backup location is sufficient. - Firewall rules — Only expose ports 80 and 443 publicly. Keep port 3000 accessible only to your reverse proxy.
- Log monitoring — Forward application logs to a centralized logging service to detect issues early.
Default Admin
Self-hosted deployments (no STRIPE_SECRET_KEY) come with a default admin account created on first launch:
Email: admin@mailpanda.io
Password: password123Change this immediately after your first login. Navigate to Settings in the dashboard to update the admin password. You can also create additional user accounts from the sign-up page.
SaaS deployments (with Stripe enabled) do not seed a default admin. Users create accounts through the /signup page instead. The seed logic lives in db/seed.ts.