# Limristem eMail — Go-live checklist

Use this before promoting a host from lab to production. Defaults assume Debian 13, package install under `/opt/limristem-mail`, version ≥ 0.1.1 with dynamic limits (including fail2ban).

---

## 1. Pre-install / infrastructure

| # | Check | Notes |
|---|--------|--------|
| 1.1 | Public DNS A/AAAA for mail hostname | Matches `LIMRISTEM_MAIL_HOSTNAME` |
| 1.2 | Reverse DNS (PTR) for public IPv4 (and IPv6 if used) | Must match mail hostname for reputation |
| 1.3 | Ports open: 25, 80, 443, 465, 587, 993 (and 22 only if needed) | Prefer nftables via panel/CLI firewall |
| 1.4 | Outbound 25 not blocked by provider | Test with `nc -vz mx.example.com 25` |
| 1.5 | Time sync (chrony/systemd-timesyncd) | Required for TLS, MFA TOTP, logs |
| 1.6 | Hostname and FQDN set | `hostnamectl` |
| 1.7 | Adequate disk for Maildir + backups | Monitor `/var/mail/vhosts` and backup dir |

---

## 2. Install & base security

| # | Check | How |
|---|--------|-----|
| 2.1 | Fresh install or upgrade from signed package | Stable channel: Ed25519 `signing_key_id=stable` |
| 2.2 | No private signing keys on the server | Only `keys/public/*.pub` in package |
| 2.3 | Strong secrets in env | DB, Redis, Rspamd, panel CSRF, admin hashes (argon2 only) |
| 2.4 | `LIMRISTEM_MAIL_MFA_REQUIRED=yes` | Production default; enroll panel/API MFA before go-live |
| 2.5 | Web panel disabled or HTTPS-only + MFA | `LIMRISTEM_MAIL_ENABLE_WEB_PANEL` |
| 2.6 | Firewall enabled with minimal ports | `limristem-mail firewall show` |
| 2.7 | Fail2ban active with mail jails | `fail2ban-client status` → sshd, dovecot, postfix, postfix-sasl, nginx-*, limristem-mail-auth, recidive |
| 2.8 | Auto-updates policy decided | Off by default; if on, pin channel stable vs nightly |

```bash
sudo fail2ban-client status
sudo fail2ban-client status dovecot
sudo systemctl is-active postfix dovecot rspamd redis-server mariadb nginx limristem-mail fail2ban
```

---

## 3. TLS & mail identity

| # | Check | How |
|---|--------|-----|
| 3.1 | Valid TLS cert (Let's Encrypt preferred) | Panel SSL or `manage-ssl.sh` |
| 3.2 | SMTP submission requires TLS | Ports 587/465 |
| 3.3 | IMAPS 993 works | `openssl s_client -connect host:993` |
| 3.4 | Primary domain + MX point to this host | DNS plan from panel/CLI |
| 3.5 | SPF published | `v=spf1 mx a:<hostname> -all` (or include) |
| 3.6 | DKIM published and signing works | Domain DKIM in panel; test outbound |
| 3.7 | DMARC policy (start p=none, then quarantine/reject) | `_dmarc` TXT |
| 3.8 | Optional MTA-STS / TLS-RPT | If enabled in env |

---

## 4. Service limits (verify before traffic)

All of these are dynamic: **CLI**, **API** (`GET/PATCH /admin/limits`), **panel** Settings → Limits.

### 4.1 Inventory of managed limits

| Key group | Purpose | Default (typical) |
|-----------|---------|-------------------|
| `message-size-limit` | Max message size (bytes) | `52428800` (50 MiB) |
| `smtp-recipient-limit` | Max recipients per message | `100` |
| `smtp-client-connection-count-limit` | Concurrent SMTP conns/client | `50` |
| `postfix-client-connection-rate-limit` | Conn rate per time unit | `30` |
| `postfix-client-message-rate-limit` | Msg rate per time unit | `100` |
| `postfix-rate-time-unit` | Anvil time unit | `60s` |
| `send-rate-burst` | Auth user burst | `20` |
| `send-rate-per-minute` | Auth user / min | `10` |
| `send-rate-per-hour` | Auth user / hour | `100` |
| `send-rate-per-day` | Auth user / day | `500` |
| `send-rate-per-week` | Auth user / week | `2000` |
| `send-rate-per-month` | Auth user / month | `5000` |
| `api-auth-fail-limit` | Panel/API fails before block | `5` |
| `api-auth-window-seconds` | Fail window | `300` |
| `api-auth-block-seconds` | Block duration | `900` |
| `rspamd-action-*` | Greylist / add-header / reject scores | 4 / 6 / 15 |
| `rspamd-greylist-delay` / `expire` | Greylist timing | `5m` / `35d` |
| `dkim-rotation-*` / `auto-rotate-default` | DKIM lifecycle | 90d / 14d / no |
| `fail2ban-default-*` | DEFAULT maxretry / findtime / bantime | 5 / 10m / 1h |
| `fail2ban-sshd-*` | SSH jail | 5 / 10m / 1h |
| `fail2ban-dovecot-*` | IMAP/POP auth | 8 / 15m / 1h |
| `fail2ban-postfix-*` | SMTP generic | 8 / 10m / 1h |
| `fail2ban-postfix-sasl-*` | SASL submission | 5 / 10m / 1h |
| `fail2ban-nginx-http-auth-*` | Nginx auth | 5 / 10m / 1h |
| `fail2ban-nginx-botsearch-*` | Bot probes | 10 / 10m / 1h |
| `fail2ban-limristem-mail-auth-*` | Panel/API jail | 8 / 15m / 2h |
| `fail2ban-recidive-*` | Repeat offenders | 3 / 1d / 1w |

```bash
# Show all limits (JSON)
sudo /opt/limristem-mail/limristem-mail limits show --json | jq .

# Tune examples
sudo /opt/limristem-mail/limristem-mail limits set message-size-limit 52428800
sudo /opt/limristem-mail/limristem-mail limits set smtp-recipient-limit 50
sudo /opt/limristem-mail/limristem-mail limits set send-rate-per-hour 200
sudo /opt/limristem-mail/limristem-mail limits set fail2ban-dovecot-maxretry 10
sudo /opt/limristem-mail/limristem-mail limits set fail2ban-limristem-mail-auth-bantime 4h
sudo /opt/limristem-mail/limristem-mail limits apply

# API
curl -u admin:$PASS https://mail.example.com/admin/limits
curl -u admin:$PASS -X PATCH -H 'Content-Type: application/json' \
  -d '{"key":"fail2ban-sshd-maxretry","value":"3"}' \
  https://mail.example.com/admin/limits
```

| # | Check | Notes |
|---|--------|--------|
| 4.2 | Message size fits business needs | Attachments vs abuse |
| 4.3 | Send rates fit legit bulk vs abuse | Per-mailbox overrides possible (0 = inherit) |
| 4.4 | Recipient limit not too high | Reduce for shared hosts |
| 4.5 | Fail2ban thresholds not too aggressive for NAT users | Or not too loose for public IP |
| 4.6 | After changes, jail file updated | `grep maxretry /etc/fail2ban/jail.d/limristem-mail.local` |
| 4.7 | Postfix reflects size/recipients | `postconf message_size_limit smtpd_recipient_limit` |

---

## 5. Accounts & access

| # | Check | How |
|---|--------|-----|
| 5.1 | First admin mailbox + domain created | Panel or API |
| 5.2 | App passwords for clients if required | `require_app_password` |
| 5.3 | Panel/API MFA enrolled for all admins | Fail-closed when MFA required |
| 5.4 | No default/weak passwords | Argon2 hashes only in env |
| 5.5 | API admin password rotated | Panel API tab or `manage-api-credentials.sh` |
| 5.6 | Sudoers constrained for limristem-mail | Only manage-*.sh helpers |

---

## 6. Backup & restore

| # | Check | How |
|---|--------|-----|
| 6.1 | Backup timer enabled and schedule OK | `systemctl status limristem-mail-backup.timer` |
| 6.2 | Local path + retention set | `limristem-mail backup show` |
| 6.3 | Remote storage tested (if used) | Panel storage test / rclone |
| 6.4 | Secrets not stored in plaintext where avoidable | Backup storage encryption keys |
| 6.5 | **Test restore** on a spare host or dry path | `restore.sh --restore-files --restore-db` |
| 6.6 | Document RPO/RTO | Who runs restore |

---

## 7. Deliverability smoke tests

| # | Check | How |
|---|--------|-----|
| 7.1 | Send authenticated mail to Gmail/Outlook | Check spam folder |
| 7.2 | Headers show DKIM pass, SPF pass | “Show original” |
| 7.3 | Receive inbound to mailbox | IMAP/Maildir |
| 7.4 | Queue not stuck | `limristem-mail queue list` / `postqueue -p` |
| 7.5 | Rspamd scores sensible | Soft-reject on over-quota send |
| 7.6 | Optional: mail-tester.com / MX Toolbox | Score ≥ 9/10 target |

---

## 8. Monitoring & ops readiness

| # | Check | Notes |
|---|--------|--------|
| 8.1 | journald/log shipping for postfix, dovecot, fail2ban, limristem-mail | |
| 8.2 | Disk/space alerts | Maildir growth |
| 8.3 | Certificate expiry alert | LE renew path |
| 8.4 | Ban list review process | `limristem-mail bans list` |
| 8.5 | Deliverability report timer (optional) | env + systemd |
| 8.6 | On-call knows MFA recovery / break-glass | Document emergency `MFA_ALLOW_BASIC` only temporary |
| 8.7 | Update channel + rollback plan | Stable package + previous version tarball |

---

## 9. Final go / no-go

- [ ] DNS + PTR + SPF/DKIM/DMARC correct  
- [ ] TLS valid on 443/465/587/993  
- [ ] MFA required and enrolled  
- [ ] Firewall + fail2ban jails green  
- [ ] Limits reviewed (size, recipients, send rates, fail2ban)  
- [ ] Backup run + restore tested  
- [ ] Inbound/outbound smoke OK  
- [ ] No private update-signing keys on the server  
- [ ] Operators can use CLI, API, and panel for limits/bans  

**Sign-off:** _________________  **Date:** _________________
