Files
firefrost-operations-manual/docs/tasks/mailcow-email-server-on-nc1/deployment-plan.md
Claude a289e2041e docs: Mailcow deliverability — 10/10 mail-tester score achieved
PTR record set by Breezehost: 38.68.14.188 → mail.firefrostgaming.com
DMARC rua tag added (postmaster@firefrostgaming.com)
All checks passing: SPF, DKIM, DMARC, PTR, blacklists clean
Perfect score achieved March 16, 2026
2026-03-17 00:11:08 +00:00

8.4 KiB

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

apt update && apt upgrade -y

Install Docker if not present

curl -fsSL https://get.docker.com | sh

Verify Docker

docker --version
docker compose version

Phase 2: Mailcow Installation (30 min)

Clone Mailcow

cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized

Generate configuration

./generate_config.sh

When prompted:

  • Hostname: mail.firefrostgaming.com
  • Timezone: America/Chicago

Review generated config

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)

docker compose pull

Start Mailcow

docker compose up -d

Verify all containers running

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


Phase 5: Ghost SMTP Configuration (15 min)

SSH to Ghost VPS

ssh architect@64.50.188.14

Update Ghost mail config

cd /var/www/firefrost
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

ghost config --mail.from "'Firefrost Gaming' <noreply@firefrostgaming.com>"

Restart Ghost

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


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:

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:

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 💙🔥❄️