Add Docker Compose configuration for Warmbox with Nginx Proxy Manager integration. Introduce new npm-specific compose file and update existing services to utilize Docker networks without host port exposure. Enhance documentation for deployment instructions and clarify setup for Cloudflare Tunnel and Nginx Proxy Manager.
This commit is contained in:
parent
cc355b32d5
commit
f98cc61cf7
5 changed files with 247 additions and 151 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
# Replace warmbox.yourdomain.com with your hostname.
|
# Replace warmbox.yourdomain.com with your hostname (e.g. warmbox.jonnyn.com).
|
||||||
# Caddy obtains Let's Encrypt certificates automatically.
|
# Only use this profile if Nginx Proxy Manager is NOT already bound to 80/443.
|
||||||
|
|
||||||
warmbox.yourdomain.com {
|
warmbox.jonnyn.com {
|
||||||
encode gzip
|
encode gzip
|
||||||
reverse_proxy warmbox:3000
|
reverse_proxy warmbox:3000
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
docker-compose.npm.yml
Normal file
14
docker-compose.npm.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Use with: docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d --build
|
||||||
|
#
|
||||||
|
# Attaches Warmbox to your existing Nginx Proxy Manager network so NPM can proxy
|
||||||
|
# warmbox.jonnyn.com → http://warmbox:3000
|
||||||
|
|
||||||
|
services:
|
||||||
|
warmbox:
|
||||||
|
networks:
|
||||||
|
- warmbox_internal
|
||||||
|
- npm_network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
npm_network:
|
||||||
|
external: true
|
||||||
|
|
@ -9,19 +9,32 @@ services:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
volumes:
|
volumes:
|
||||||
- warmbox-data:/data
|
- warmbox-data:/data
|
||||||
ports:
|
# No host ports — reach Warmbox via Docker network only (NPM or Cloudflare Tunnel).
|
||||||
# Bind to localhost only when using the Caddy profile (recommended).
|
# For LAN debugging only, temporarily add: ports: ["127.0.0.1:3001:3000"]
|
||||||
# For LAN testing without Caddy, change to "3000:3000".
|
|
||||||
- "127.0.0.1:3000:3000"
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'node', '-e', "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
test: ['CMD', 'node', '-e', "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
|
networks:
|
||||||
|
- warmbox_internal
|
||||||
|
|
||||||
# Optional HTTPS reverse proxy — requires a public DNS name pointing at this host.
|
# Cloudflare Tunnel connector — shares warmbox_internal with the app.
|
||||||
# Start with: docker compose --profile caddy up -d
|
cloudflared:
|
||||||
|
profiles: [cloudflare]
|
||||||
|
image: cloudflare/cloudflared:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
warmbox:
|
||||||
|
condition: service_healthy
|
||||||
|
command: tunnel run
|
||||||
|
environment:
|
||||||
|
TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN}
|
||||||
|
networks:
|
||||||
|
- warmbox_internal
|
||||||
|
|
||||||
|
# Standalone Caddy — only if you do NOT already run Nginx Proxy Manager on 80/443.
|
||||||
caddy:
|
caddy:
|
||||||
profiles: [caddy]
|
profiles: [caddy]
|
||||||
image: caddy:2-alpine
|
image: caddy:2-alpine
|
||||||
|
|
@ -36,23 +49,14 @@ services:
|
||||||
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
|
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
- caddy-data:/data
|
- caddy-data:/data
|
||||||
- caddy-config:/config
|
- caddy-config:/config
|
||||||
|
networks:
|
||||||
# Optional Cloudflare Tunnel — HTTPS without opening router ports (great for home servers).
|
- warmbox_internal
|
||||||
# 1. Create a tunnel in Cloudflare Zero Trust → copy token
|
|
||||||
# 2. Set CLOUDFLARE_TUNNEL_TOKEN in .env
|
|
||||||
# 3. docker compose --profile cloudflare up -d
|
|
||||||
cloudflared:
|
|
||||||
profiles: [cloudflare]
|
|
||||||
image: cloudflare/cloudflared:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
depends_on:
|
|
||||||
warmbox:
|
|
||||||
condition: service_healthy
|
|
||||||
command: tunnel run
|
|
||||||
environment:
|
|
||||||
TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN}
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
warmbox-data:
|
warmbox-data:
|
||||||
caddy-data:
|
caddy-data:
|
||||||
caddy-config:
|
caddy-config:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
warmbox_internal:
|
||||||
|
name: warmbox_internal
|
||||||
|
|
|
||||||
|
|
@ -6,186 +6,261 @@ Warmbox is a **long-running worker** (cron dispatcher, rescuer, SMTP/IMAP). It n
|
||||||
- Outbound SMTP/IMAP from the server
|
- Outbound SMTP/IMAP from the server
|
||||||
- A public HTTPS URL for the dashboard and OAuth callbacks
|
- 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 — no background jobs, no SQLite, no mail sockets.
|
||||||
|
|
||||||
**Not suitable:** Netlify, GitHub Pages, Vercel static — no background jobs, no SQLite, no mail sockets.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick comparison
|
## Your setup (`warmbox.jonnyn.com`)
|
||||||
|
|
||||||
| Option | Best for | Pros | Cons |
|
You already have:
|
||||||
|--------|----------|------|------|
|
|
||||||
| **Ubuntu + Docker + Cloudflare Tunnel** | Home server (your preference) | Free, persistent, full control | You maintain the box |
|
- DNS **A** record → home public IP
|
||||||
| Ubuntu + Docker + Caddy | Home server with public IP + domain | Simple TLS | Open ports 80/443 on router |
|
- **Nginx Proxy Manager** (NPM) on Docker network `npm_network`
|
||||||
| 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 |
|
**Recommended for you: Option B — Nginx Proxy Manager** (simplest; reuses what you have).
|
||||||
|
|
||||||
|
Use **Option A — Cloudflare Tunnel** only if you want HTTPS without opening ports 80/443, or if your ISP blocks inbound traffic.
|
||||||
|
|
||||||
|
Do **not** run Caddy (Option C) alongside NPM — both want ports 80 and 443.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Prepare the Ubuntu server
|
## 1. Prepare the 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
|
```bash
|
||||||
|
cd ~/warmbox # or wherever you cloned the repo
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
nano .env
|
nano .env
|
||||||
```
|
```
|
||||||
|
|
||||||
Set these **before first start**:
|
Required in `.env`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generate once — keep forever (changing it breaks encrypted mailbox passwords)
|
ENCRYPTION_KEY=<64 hex chars — openssl rand -hex 32>
|
||||||
openssl rand -hex 32 # → ENCRYPTION_KEY
|
API_KEY=<openssl rand -hex 24>
|
||||||
|
PUBLIC_BASE_URL=https://warmbox.jonnyn.com
|
||||||
# Dashboard login password
|
AI_API_KEY=sk-or-v1-...
|
||||||
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.
|
Keep `ENCRYPTION_KEY` forever. If migrating from your Mac, copy the same key and `prisma/dev.db`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Choose how the world reaches your server
|
## 2. Fix: “port 3000 already allocated”
|
||||||
|
|
||||||
### Option A — Cloudflare Tunnel (recommended for home)
|
Warmbox listens on **port 3000 inside its container**. That does **not** conflict with `homepage` using host port `3000` — unless you publish Warmbox to the host with a `ports:` mapping.
|
||||||
|
|
||||||
No port forwarding. Works behind CGNAT.
|
**NPM and Cloudflare Tunnel only need Docker network access** (`warmbox:3000`). No host port is required.
|
||||||
|
|
||||||
1. [Cloudflare Zero Trust](https://one.dash.cloudflare.com/) → **Networks** → **Tunnels** → Create tunnel
|
### Verify your compose file on the server
|
||||||
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
|
```bash
|
||||||
# In docker-compose.yml change ports to "3000:3000"
|
cd /srv/docker-configs/warmbox
|
||||||
docker compose up -d --build
|
grep -n ports docker-compose.yml docker-compose.npm.yml 2>/dev/null
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml config | grep -A2 published
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `http://SERVER_LAN_IP:3000` — not suitable for OAuth or remote access.
|
- **Correct:** no `published` / `ports` for the `warmbox` service (empty grep for warmbox ports).
|
||||||
|
- **Wrong:** lines like `"3000:3000"` or `"127.0.0.1:3000:3000"` under `warmbox` — **delete the entire `ports:` block** for that service.
|
||||||
|
|
||||||
|
Pull the latest repo (or remove `ports:` manually), then:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml down
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional: direct LAN access on a different host port
|
||||||
|
|
||||||
|
Only if you want to hit Warmbox without NPM (debugging). This uses host **3001**, not 3000:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3001:3000"
|
||||||
|
```
|
||||||
|
|
||||||
|
NPM still uses forward port **3000** (container port), not 3001.
|
||||||
|
|
||||||
|
### Find what uses host port 3000
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps --format '{{.Names}} {{.Ports}}' | grep '0.0.0.0:3000'
|
||||||
|
```
|
||||||
|
|
||||||
|
In your case `homepage` owns host 3000 — leave it alone; Warmbox does not need that port.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. First login
|
## Option B — Nginx Proxy Manager (recommended for your home server)
|
||||||
|
|
||||||
1. Open `https://warmbox.yourdomain.com`
|
Traffic path:
|
||||||
2. Login with your `API_KEY`
|
|
||||||
3. Leave **Base URL** blank (dashboard and API are same origin in production)
|
|
||||||
|
|
||||||
---
|
```text
|
||||||
|
Internet → warmbox.jonnyn.com (DNS A → home IP) → NPM :443 → warmbox:3000 (Docker)
|
||||||
|
```
|
||||||
|
|
||||||
## 5. Update OAuth redirect URIs
|
### Step 1 — Start Warmbox on `npm_network`
|
||||||
|
|
||||||
Replace `localhost` with your public URL in:
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml ps
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml logs -f warmbox
|
||||||
|
curl -s http://warmbox:3000/health # run from any container on npm_network, or skip
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2 — NPM proxy host
|
||||||
|
|
||||||
|
In Nginx Proxy Manager UI:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|--------|--------|
|
||||||
|
| Domain names | `warmbox.jonnyn.com` |
|
||||||
|
| Scheme | `http` |
|
||||||
|
| Forward hostname / IP | `warmbox` |
|
||||||
|
| Forward port | `3000` (container port — not your host port 3000 used by homepage) |
|
||||||
|
| Cache assets | off |
|
||||||
|
| Block common exploits | on |
|
||||||
|
| Websockets support | on |
|
||||||
|
|
||||||
|
**SSL** tab:
|
||||||
|
|
||||||
|
- Request a new SSL Certificate (Let's Encrypt)
|
||||||
|
- Force SSL + HTTP/2
|
||||||
|
|
||||||
|
If you use **Cloudflare orange cloud** (proxied) on the A record, set Cloudflare SSL mode to **Full** or **Full (strict)** so NPM’s certificate works.
|
||||||
|
|
||||||
|
### Step 3 — Login
|
||||||
|
|
||||||
|
1. Open `https://warmbox.jonnyn.com`
|
||||||
|
2. API key = your `API_KEY` from `.env`
|
||||||
|
3. Leave **Base URL** blank
|
||||||
|
|
||||||
|
### Step 4 — OAuth redirect URIs
|
||||||
|
|
||||||
| Integration | Redirect URI |
|
| Integration | Redirect URI |
|
||||||
|-------------|----------------|
|
|-------------|----------------|
|
||||||
| Google Postmaster | `https://warmbox.yourdomain.com/api/integrations/google/callback` |
|
| Google Postmaster | `https://warmbox.jonnyn.com/api/integrations/google/callback` |
|
||||||
| Microsoft Outlook | `https://warmbox.yourdomain.com/api/integrations/microsoft/callback` |
|
| Microsoft Outlook | `https://warmbox.jonnyn.com/api/integrations/microsoft/callback` |
|
||||||
|
|
||||||
Re-connect integrations in **Settings** after deploy.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Migrate local data (optional)
|
## Option A — Cloudflare Tunnel
|
||||||
|
|
||||||
If you already configured mailboxes and campaigns locally:
|
Use this if you prefer **no inbound ports** on your router (tunnel only).
|
||||||
|
|
||||||
|
Traffic path:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Browser → Cloudflare edge → cloudflared (Docker) → warmbox:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Important DNS note
|
||||||
|
|
||||||
|
For tunnel-only access, let the **tunnel** own the hostname. In Cloudflare Zero Trust → your tunnel → **Public Hostname**:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|--------|--------|
|
||||||
|
| Subdomain | `warmbox` |
|
||||||
|
| Domain | `jonnyn.com` |
|
||||||
|
| Type | HTTP |
|
||||||
|
| URL | `warmbox:3000` |
|
||||||
|
|
||||||
|
Cloudflare usually creates a CNAME for you. You can **remove the A record** for `warmbox` if everything goes through the tunnel (avoids split routing).
|
||||||
|
|
||||||
|
### Step 1 — `.env`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# On your Mac — stop local dev server first
|
CLOUDFLARE_TUNNEL_TOKEN=eyJh... # from Zero Trust → Tunnels → your tunnel → Docker install
|
||||||
|
PUBLIC_BASE_URL=https://warmbox.jonnyn.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2 — Start (no NPM override file)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile cloudflare up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
`cloudflared` and `warmbox` share the `warmbox_internal` network — hostname `warmbox` resolves inside that network.
|
||||||
|
|
||||||
|
### Step 3 — Verify
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile cloudflare ps
|
||||||
|
docker compose --profile cloudflare logs -f cloudflared
|
||||||
|
docker compose --profile cloudflare logs -f warmbox
|
||||||
|
curl -s https://warmbox.jonnyn.com/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tunnel + NPM together?
|
||||||
|
|
||||||
|
Pick **one** public entry for `warmbox.jonnyn.com`:
|
||||||
|
|
||||||
|
- **NPM only:** A record → home IP, no tunnel hostname for the same subdomain.
|
||||||
|
- **Tunnel only:** tunnel hostname, no A record to home IP for that subdomain.
|
||||||
|
|
||||||
|
Running both for the same hostname causes confusing SSL or routing issues.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Option C — Caddy (standalone, no NPM)
|
||||||
|
|
||||||
|
Only if NPM is **not** using 80/443 on this host.
|
||||||
|
|
||||||
|
1. Edit `deploy/Caddyfile` — set `warmbox.jonnyn.com`
|
||||||
|
2. DNS A record → home public IP; forward router 80/443 to the server
|
||||||
|
3. Start:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile caddy up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skip this** if Nginx Proxy Manager is already on the server.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migrate local database (optional)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mac
|
||||||
scp prisma/dev.db user@home-server:/tmp/warmbox.db
|
scp prisma/dev.db user@home-server:/tmp/warmbox.db
|
||||||
|
|
||||||
# On Ubuntu — before first start OR with stack stopped:
|
# Server — stack stopped
|
||||||
docker compose down
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml down
|
||||||
docker volume create warmbox_warmbox-data 2>/dev/null || true
|
|
||||||
docker run --rm -v warmbox_warmbox-data:/data -v /tmp:/backup alpine \
|
docker run --rm -v warmbox_warmbox-data:/data -v /tmp:/backup alpine \
|
||||||
cp /backup/warmbox.db /data/warmbox.db
|
cp /backup/warmbox.db /data/warmbox.db
|
||||||
docker compose --profile cloudflare up -d
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy the **same** `ENCRYPTION_KEY` and `API_KEY` (or set a new API_KEY and use that to log in).
|
Use the **same** `ENCRYPTION_KEY` as on your Mac.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Operations
|
## Day-to-day commands
|
||||||
|
|
||||||
|
**NPM deployment:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Logs
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml logs -f warmbox
|
||||||
docker compose logs -f warmbox
|
docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d --build
|
||||||
|
|
||||||
# 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
|
**Cloudflare deployment:**
|
||||||
|
|
||||||
- [ ] Container `restart: unless-stopped` (default in compose)
|
```bash
|
||||||
- [ ] `warmbox-data` volume backed up
|
docker compose --profile cloudflare logs -f warmbox
|
||||||
- [ ] `ENCRYPTION_KEY` saved in your password manager
|
docker compose --profile cloudflare up -d --build
|
||||||
- [ ] 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
|
|
||||||
|
|
||||||
---
|
**Backup:**
|
||||||
|
|
||||||
## 8. Security notes (single-tenant MVP)
|
```bash
|
||||||
|
docker compose exec warmbox sh -c 'cp /data/warmbox.db /data/warmbox-$(date +%F).db'
|
||||||
- **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`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -193,10 +268,11 @@ curl -s https://warmbox.yourdomain.com/health
|
||||||
|
|
||||||
| Symptom | Fix |
|
| Symptom | Fix |
|
||||||
|---------|-----|
|
|---------|-----|
|
||||||
| Login fails | Check `API_KEY` in `.env` matches what you enter; restart container after `.env` change |
|
| `port 3000 already allocated` | Use updated compose (no host ports); `docker compose down`; find conflict with `docker ps \| grep 3000` |
|
||||||
| OAuth redirect error | `PUBLIC_BASE_URL` must match browser URL; update provider redirect URI |
|
| NPM 502 Bad Gateway | Warmbox not on `npm_network`; wrong forward host (`warmbox` not `localhost`); check `docker compose logs warmbox` |
|
||||||
| Jobs not sending | `docker compose logs warmbox` — verify cron lines; confirm SMTP/IMAP from server IP isn't blocked |
|
| Tunnel 502 / error | Public hostname URL must be `http://warmbox:3000`; both containers on `warmbox_internal`; check `logs cloudflared` |
|
||||||
| `ENCRYPTION_KEY` error on decrypt | Wrong key vs database — restore original key or re-add mailboxes |
|
| Login fails | `API_KEY` in `.env` must match login; restart after `.env` change |
|
||||||
| Container unhealthy | `docker compose logs warmbox` — migration or port conflict |
|
| OAuth redirect error | `PUBLIC_BASE_URL=https://warmbox.jonnyn.com` exactly; update Google/Microsoft redirect URIs |
|
||||||
|
| SSL errors with Cloudflare proxy | Cloudflare SSL mode **Full** or **Full (strict)** when NPM terminates TLS |
|
||||||
|
|
||||||
See also [self-host-hardening.md](./self-host-hardening.md) for operator workflows.
|
See also [self-host-hardening.md](./self-host-hardening.md).
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
"build": "npm run build -w @warmbox/shared && npm run build -w @warmbox/api && npm run build -w @warmbox/web",
|
"build": "npm run build -w @warmbox/shared && npm run build -w @warmbox/api && npm run build -w @warmbox/web",
|
||||||
"start": "npm run start -w @warmbox/api",
|
"start": "npm run start -w @warmbox/api",
|
||||||
"docker:up": "docker compose up -d --build",
|
"docker:up": "docker compose up -d --build",
|
||||||
|
"docker:up:npm": "docker compose -f docker-compose.yml -f docker-compose.npm.yml up -d --build",
|
||||||
|
"docker:up:cloudflare": "docker compose --profile cloudflare up -d --build",
|
||||||
"docker:logs": "docker compose logs -f warmbox",
|
"docker:logs": "docker compose logs -f warmbox",
|
||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
"db:generate": "prisma generate",
|
"db:generate": "prisma generate",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue