warmbox/docs/deploy-ubuntu-docker.md

202 lines
6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 | ~$56/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.