202 lines
6 KiB
Markdown
202 lines
6 KiB
Markdown
# Deploy Warmbox on Ubuntu (Docker)
|
||
|
||
Warmbox is a **long-running worker** (cron dispatcher, rescuer, SMTP/IMAP). It needs:
|
||
|
||
- A persistent database (SQLite volume)
|
||
- Outbound SMTP/IMAP from the server
|
||
- A public HTTPS URL for the dashboard and OAuth callbacks
|
||
|
||
**Recommended for your case:** Ubuntu home server + Docker + **Cloudflare Tunnel** (free HTTPS, no router port forwarding).
|
||
|
||
**Not suitable:** Netlify, GitHub Pages, Vercel static — no background jobs, no SQLite, no mail sockets.
|
||
|
||
---
|
||
|
||
## Quick comparison
|
||
|
||
| Option | Best for | Pros | Cons |
|
||
|--------|----------|------|------|
|
||
| **Ubuntu + Docker + Cloudflare Tunnel** | Home server (your preference) | Free, persistent, full control | You maintain the box |
|
||
| Ubuntu + Docker + Caddy | Home server with public IP + domain | Simple TLS | Open ports 80/443 on router |
|
||
| Hetzner / DigitalOcean VPS + same Docker | No home server | Always on, static IP | ~$5–6/mo |
|
||
| Railway / Fly.io | Managed container | Easy deploy | Cost, less control for 30-day test |
|
||
|
||
---
|
||
|
||
## 1. Prepare the Ubuntu server
|
||
|
||
```bash
|
||
# SSH into your home server
|
||
sudo apt update && sudo apt upgrade -y
|
||
sudo apt install -y git docker.io docker-compose-v2
|
||
sudo usermod -aG docker $USER
|
||
# log out and back in so docker group applies
|
||
```
|
||
|
||
Clone the repo:
|
||
|
||
```bash
|
||
git clone https://github.com/YOUR_ORG/warmbox.git
|
||
cd warmbox
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Configure environment
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
nano .env
|
||
```
|
||
|
||
Set these **before first start**:
|
||
|
||
```bash
|
||
# Generate once — keep forever (changing it breaks encrypted mailbox passwords)
|
||
openssl rand -hex 32 # → ENCRYPTION_KEY
|
||
|
||
# Dashboard login password
|
||
openssl rand -hex 24 # → API_KEY
|
||
|
||
PUBLIC_BASE_URL=https://warmbox.yourdomain.com # your real public URL
|
||
AI_API_KEY=sk-or-v1-... # OpenRouter or compatible
|
||
```
|
||
|
||
**Migrating from local:** copy your existing `prisma/dev.db` to the server **and** use the **same** `ENCRYPTION_KEY` from your local `.env`. Otherwise mailbox credentials cannot be decrypted.
|
||
|
||
---
|
||
|
||
## 3. Choose how the world reaches your server
|
||
|
||
### Option A — Cloudflare Tunnel (recommended for home)
|
||
|
||
No port forwarding. Works behind CGNAT.
|
||
|
||
1. [Cloudflare Zero Trust](https://one.dash.cloudflare.com/) → **Networks** → **Tunnels** → Create tunnel
|
||
2. Name it `warmbox`, install connector via **Docker** — copy the token
|
||
3. In the tunnel **Public Hostname** tab, route `warmbox.yourdomain.com` → `http://warmbox:3000` (Docker network)
|
||
If cloudflared runs in the same compose file, use hostname `warmbox` and port `3000`.
|
||
4. Add to `.env`:
|
||
|
||
```bash
|
||
CLOUDFLARE_TUNNEL_TOKEN=eyJh...
|
||
PUBLIC_BASE_URL=https://warmbox.yourdomain.com
|
||
```
|
||
|
||
5. Start:
|
||
|
||
```bash
|
||
docker compose --profile cloudflare up -d --build
|
||
```
|
||
|
||
### Option B — Caddy on a public IP
|
||
|
||
1. Point DNS `warmbox.yourdomain.com` → your home public IP
|
||
2. Forward router ports **80** and **443** to the Ubuntu server
|
||
3. Edit `deploy/Caddyfile` with your domain
|
||
4. Start:
|
||
|
||
```bash
|
||
docker compose --profile caddy up -d --build
|
||
```
|
||
|
||
### Option C — LAN / direct port (testing only)
|
||
|
||
```bash
|
||
# In docker-compose.yml change ports to "3000:3000"
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Use `http://SERVER_LAN_IP:3000` — not suitable for OAuth or remote access.
|
||
|
||
---
|
||
|
||
## 4. First login
|
||
|
||
1. Open `https://warmbox.yourdomain.com`
|
||
2. Login with your `API_KEY`
|
||
3. Leave **Base URL** blank (dashboard and API are same origin in production)
|
||
|
||
---
|
||
|
||
## 5. Update OAuth redirect URIs
|
||
|
||
Replace `localhost` with your public URL in:
|
||
|
||
| Integration | Redirect URI |
|
||
|-------------|----------------|
|
||
| Google Postmaster | `https://warmbox.yourdomain.com/api/integrations/google/callback` |
|
||
| Microsoft Outlook | `https://warmbox.yourdomain.com/api/integrations/microsoft/callback` |
|
||
|
||
Re-connect integrations in **Settings** after deploy.
|
||
|
||
---
|
||
|
||
## 6. Migrate local data (optional)
|
||
|
||
If you already configured mailboxes and campaigns locally:
|
||
|
||
```bash
|
||
# On your Mac — stop local dev server first
|
||
scp prisma/dev.db user@home-server:/tmp/warmbox.db
|
||
|
||
# On Ubuntu — before first start OR with stack stopped:
|
||
docker compose down
|
||
docker volume create warmbox_warmbox-data 2>/dev/null || true
|
||
docker run --rm -v warmbox_warmbox-data:/data -v /tmp:/backup alpine \
|
||
cp /backup/warmbox.db /data/warmbox.db
|
||
docker compose --profile cloudflare up -d
|
||
```
|
||
|
||
Copy the **same** `ENCRYPTION_KEY` and `API_KEY` (or set a new API_KEY and use that to log in).
|
||
|
||
---
|
||
|
||
## 7. Operations
|
||
|
||
```bash
|
||
# Logs
|
||
docker compose logs -f warmbox
|
||
|
||
# Restart after code pull
|
||
git pull
|
||
docker compose --profile cloudflare up -d --build
|
||
|
||
# Backup database (run daily via cron)
|
||
docker compose exec warmbox sh -c 'cp /data/warmbox.db /data/warmbox-$(date +%F).db'
|
||
|
||
# Health check
|
||
curl -s https://warmbox.yourdomain.com/health
|
||
```
|
||
|
||
### 30-day warmup checklist
|
||
|
||
- [ ] Container `restart: unless-stopped` (default in compose)
|
||
- [ ] `warmbox-data` volume backed up
|
||
- [ ] `ENCRYPTION_KEY` saved in your password manager
|
||
- [ ] Campaign started and status **active**
|
||
- [ ] Settings → Jobs shows dispatcher/rescuer running (or check logs every few hours day 1)
|
||
- [ ] OAuth redirect URIs updated if using Postmaster / Microsoft
|
||
|
||
---
|
||
|
||
## 8. Security notes (single-tenant MVP)
|
||
|
||
- **Always set `API_KEY`** when exposed to the internet.
|
||
- Do not commit `.env` to git.
|
||
- Restrict dashboard access further with Cloudflare Access (optional) or VPN if desired.
|
||
- Mailbox app passwords live encrypted in SQLite — protect the volume and `ENCRYPTION_KEY`.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
| Symptom | Fix |
|
||
|---------|-----|
|
||
| Login fails | Check `API_KEY` in `.env` matches what you enter; restart container after `.env` change |
|
||
| OAuth redirect error | `PUBLIC_BASE_URL` must match browser URL; update provider redirect URI |
|
||
| Jobs not sending | `docker compose logs warmbox` — verify cron lines; confirm SMTP/IMAP from server IP isn't blocked |
|
||
| `ENCRYPTION_KEY` error on decrypt | Wrong key vs database — restore original key or re-add mailboxes |
|
||
| Container unhealthy | `docker compose logs warmbox` — migration or port conflict |
|
||
|
||
See also [self-host-hardening.md](./self-host-hardening.md) for operator workflows.
|