# Mailcow Deployment Plan — Billing VPS

**Status:** ✅ DEPLOYED — March 15, 2026 (ahead of April 1 target)
**Deployed By:** Chronicler #31
**Location:** Billing VPS (38.68.14.188)
**Time Estimate:** 2-3 hours
**SSH Login:** root@38.68.14.188
**Last Updated:** March 14, 2026 — The Navigator (Chronicler #30)

---

## Why Billing VPS (Not NC1)

Decision made March 14, 2026. Key reasons:
- Clean IP reputation — only Paymenter on this server, never associated with game traffic
- Email and billing are natural partners (transactional emails, invoices, subscription confirmations)
- Sufficient resources: ~13GB free disk, ~60% free RAM
- Frostwall not needed — IP separation solved by server choice, not GRE tunnels
- NC1 shares IP with game servers = email reputation risk

---

## Pre-Deployment Checklist

- [ ] Verify Billing VPS disk space: `df -h /`
- [ ] Verify Billing VPS RAM: `free -h`
- [ ] Confirm Docker is installed: `docker --version`
- [ ] Confirm Docker Compose is installed: `docker compose version`
- [ ] Note current mail.firefrostgaming.com IP (31.56.20.252 — Plesk/Breezehost)
- [ ] Run pending system updates: `apt update && apt upgrade -y`

---

## Phase 1: System Preparation (15 min)

### Update the server first
```bash
apt update && apt upgrade -y
```

### Install Docker if not present
```bash
curl -fsSL https://get.docker.com | sh
```

### Verify Docker
```bash
docker --version
docker compose version
```

---

## Phase 2: Mailcow Installation (30 min)

### Clone Mailcow
```bash
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
```

### Generate configuration
```bash
./generate_config.sh
```

When prompted:
- **Hostname:** `mail.firefrostgaming.com`
- **Timezone:** `America/Chicago`

### Review generated config
```bash
cat mailcow.conf
```

Verify these key settings:
```
MAILCOW_HOSTNAME=mail.firefrostgaming.com
TZ=America/Chicago
DBPASS=<auto-generated — save this>
DBROOT=<auto-generated — save this>
```

### Pull Docker images (this takes a while)
```bash
docker compose pull
```

### Start Mailcow
```bash
docker compose up -d
```

### Verify all containers running
```bash
docker compose ps
```

All containers should show "Up". Key ones:
- mailcow-postfix (SMTP)
- mailcow-dovecot (IMAP)
- mailcow-nginx (web UI)
- mailcow-rspamd (spam filter)
- mailcow-clamd (antivirus)

---

## Phase 3: DNS Configuration (15 min — instant with Cloudflare)

### Update these DNS records in Cloudflare:

**Change MX record:**
```
firefrostgaming.com  MX  10  mail.firefrostgaming.com
```
(Already exists — no change needed)

**Update A record for mail subdomain:**
```
OLD: mail.firefrostgaming.com  A  31.56.20.252  (Plesk)
NEW: mail.firefrostgaming.com  A  38.68.14.188  (Billing VPS)
```

**Add DKIM record** (get from Mailcow admin after startup):
- Go to Mailcow admin → Configuration → ARC/DKIM Keys
- Copy the DKIM public key
- Add as TXT record: `dkim._domainkey.firefrostgaming.com`

**Verify existing records (already configured):**
```
SPF:   firefrostgaming.com  TXT  "v=spf1 +a +mx +a:plesk.breezehost.io -all"
DMARC: _dmarc.firefrostgaming.com  TXT  "v=DMARC1; p=quarantine; adkim=s; aspf=s"
```

**Update SPF after Mailcow is live:**
```
OLD: "v=spf1 +a +mx +a:plesk.breezehost.io -all"
NEW: "v=spf1 mx a:mail.firefrostgaming.com -all"
```

---

## Phase 4: Mailcow Admin Setup (20 min)

### Access Mailcow admin panel
```
https://mail.firefrostgaming.com
```
Default credentials: admin / moohoo (CHANGE IMMEDIATELY)

### Change admin password
- Go to Access → Edit → Change password
- Store in Vaultwarden

### Create initial mailboxes

**Priority order:**

1. `frostystyle@firefrostgaming.com` — Michael (Owner)
2. `gingerfury@firefrostgaming.com` — Meg (Emissary)
3. `unicorn20089@firefrostgaming.com` — Holly (Lead Builder)
4. `hello@firefrostgaming.com` — General contact
5. `support@firefrostgaming.com` — Support tickets
6. `noreply@firefrostgaming.com` — Automated emails

**For each mailbox:**
- Mailboxes → Add Mailbox
- Set quota (1GB per staff mailbox is plenty)
- Generate strong password, store in Vaultwarden

### Create aliases
- `michael@firefrostgaming.com` → frostystyle@firefrostgaming.com
- `meg@firefrostgaming.com` → gingerfury@firefrostgaming.com
- `holly@firefrostgaming.com` → unicorn20089@firefrostgaming.com
- `admin@firefrostgaming.com` → frostystyle@firefrostgaming.com

---

## Phase 5: Ghost SMTP Configuration (15 min)

### SSH to Ghost VPS
```bash
ssh architect@64.50.188.14
```

### Update Ghost mail config
```bash
cd /var/www/firefrost
```

```bash
ghost config --mail SMTP \
  --mailservice custom \
  --mailhost mail.firefrostgaming.com \
  --mailport 587 \
  --mailsecure false \
  --mailuser noreply@firefrostgaming.com \
  --mailpass YOUR_NOREPLY_PASSWORD
```

### Set from address
```bash
ghost config --mail.from "'Firefrost Gaming' <noreply@firefrostgaming.com>"
```

### Restart Ghost
```bash
ghost restart
```

### Test email
- Go to Ghost admin → Settings → Email newsletter
- Send a test email to verify

---

## Phase 6: Resend Holly's Invite (5 min)

Once Ghost SMTP is working:
- Ghost Admin → Settings → Staff → Invited tab
- Holly's invite should still be there
- Resend invite — this time it will actually send

If the old invite expired, delete it and create a new one for `unicorn20089@firefrostgaming.com`.

---

## Phase 7: Deliverability Testing (15 min)

### Test with mail-tester.com
1. Go to https://mail-tester.com
2. Send an email to the address shown
3. Check your score (aim for 9+/10)

**✅ RESULT (March 16, 2026): 10/10 — PERFECT SCORE**
- SPF: ✅ Pass
- DKIM: ✅ Valid
- DMARC: ✅ Pass (p=quarantine, rua added)
- PTR/rDNS: ✅ 38.68.14.188 → mail.firefrostgaming.com (set by Breezehost)
- Blacklists: ✅ Clean
- SpamAssassin: ✅ Pass

### Test with Gmail
- Send test email to a Gmail account
- Check if it lands in inbox (not spam)
- Check email headers for SPF/DKIM/DMARC pass

### Check blacklists
- https://mxtoolbox.com/blacklists.aspx
- Enter mail.firefrostgaming.com
- Verify not on any blacklists

---

## Phase 8: Nginx SSL (if needed — 15 min)

Mailcow handles its own SSL via Let's Encrypt internally. Should work automatically.

If SSL cert doesn't auto-provision:
```bash
cd /opt/mailcow-dockerized
docker compose exec acme-mailcow /scripts/acme.sh
```

---

## Post-Deployment Tasks

- [ ] Store all mailbox passwords in Vaultwarden
- [ ] Update tasks.md — mark Mailcow complete
- [ ] Update Ghost Servers page footer with support@firefrostgaming.com
- [ ] Update Billing VPS footer (Citadel Editor) with contact email
- [ ] Notify Holly her email is ready (via Discord)
- [ ] Notify Meg her email is ready
- [ ] Update Paymenter email settings to use Mailcow SMTP
- [ ] Configure Mailcow backups (daily, retention 30 days)

---

## Paymenter SMTP Configuration (bonus — while on Billing VPS)

While Mailcow is being set up on the same server:

Go to Paymenter Admin → Settings → Mail:
- Driver: SMTP
- Host: localhost (same server!)
- Port: 587
- Username: noreply@firefrostgaming.com
- Password: noreply mailbox password
- Encryption: TLS
- From: noreply@firefrostgaming.com
- From Name: Firefrost Gaming

Local SMTP = fastest possible delivery for billing emails.

---

## Known Issues / Gotchas

**SPF record needs updating** — current SPF includes plesk.breezehost.io which will be irrelevant after migration. Update after Mailcow is confirmed working.

**DNS propagation** — Cloudflare is near-instant for DNS changes, but mail servers around the world cache MX records. Give it 24 hours before declaring full success.

**ClamAV memory** — ClamAV (antivirus) uses ~500MB RAM on startup. If Billing VPS RAM is tight, can disable it: set `SKIP_CLAMD=y` in mailcow.conf before first start.

**Port 25 may be blocked** — Some VPS providers block outbound port 25. Check with Breezehost if sending fails. Alternative: use port 587 for all outbound.

---

## Success Criteria

- [ ] Mailcow running on Billing VPS
- [ ] mail.firefrostgaming.com resolving to 38.68.14.188
- [ ] All staff mailboxes created
- [ ] Ghost sending email via Mailcow SMTP
- [ ] Holly's invite delivered successfully
- [ ] Mail-tester.com score 9+/10
- [ ] Gmail delivery confirmed (inbox, not spam)
- [ ] SPF, DKIM, DMARC all passing
- [ ] Credentials stored in Vaultwarden

---

**Target Date:** April 1, 2026
**Estimated Time:** 2-3 hours
**Prepared By:** The Navigator (Chronicler #30)
**For:** Chronicler #31 and beyond

**Fire + Frost + Foundation = Where Love Builds Legacy** 💙🔥❄️
