Records the host's service inventory, setup runbook, mail account list, sync plan, package diff vs. clean install, and hardening TODOs, including today's SSH hardening (key-only, no root login) and the fail2ban sshd findtime fix for a low-and-slow brute-force evasion pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RdTyvEJkfNLDVAWt8WQ6X9
123 lines
5.5 KiB
Markdown
123 lines
5.5 KiB
Markdown
# alpha.jayfield.org — Adding Email Accounts (How-To)
|
|
|
|
Accounts, aliases, and domains for the mail stack (Postfix + Dovecot) all
|
|
live in one place: the `vmail` MySQL database on this host. There's no
|
|
admin UI — everything below is a `mysql` insert plus one hash-generation
|
|
command. See `SETUP.md` §3 for how this schema was built in the first
|
|
place; this doc is just the day-to-day "add a mailbox" recipe.
|
|
|
|
**No service restart is ever needed for account changes.** Postfix and
|
|
Dovecot query MySQL live on every delivery/login (`auth_cache_size` is
|
|
unset/disabled on this host — verified in `/etc/dovecot/conf.d/10-auth.conf`)
|
|
so a new row is usable immediately.
|
|
|
|
## 1. Prerequisite: the domain must already exist
|
|
|
|
```bash
|
|
sudo mysql vmail -e "SELECT * FROM domains;"
|
|
```
|
|
Currently just `jayfield.org`. If you ever need a second domain, insert it
|
|
here first (`INSERT INTO vmail.domains (domain) VALUES ('newdomain.tld');`)
|
|
— but note that's the *easy* part; a real second domain also needs its own
|
|
DNS zone/MX/SPF/DMARC records and DKIM selector (see `SETUP.md` §2/§3), a
|
|
TLS cert covering it, and its own `mynetworks`/`inet_interfaces`
|
|
consideration. Out of scope for just adding a mailbox — this doc assumes
|
|
`jayfield.org`.
|
|
|
|
## 2. Generate the password hash
|
|
|
|
Never put a plaintext password in the `accounts` table — hash it first:
|
|
```bash
|
|
sudo doveadm pw -s SHA512-CRYPT
|
|
```
|
|
(You'll be prompted twice, interactively — don't pass the password as a
|
|
CLI argument, it'd land in shell history.) Copy the full
|
|
`{SHA512-CRYPT}$6$...` output; that's the exact string that goes in the
|
|
`password` column.
|
|
|
|
You may see `Error: net_connect_unix(/run/dovecot/stats-writer) failed:
|
|
Permission denied` printed before the hash — that's `doveadm` trying to
|
|
report stats, unrelated to the hash it prints right after; harmless, not a
|
|
sign the hash is wrong.
|
|
|
|
## 3. Insert the account
|
|
|
|
```bash
|
|
sudo mysql vmail -e "INSERT INTO accounts (username, domain, password, quota, enabled, sendonly) VALUES ('newuser', 'jayfield.org', '{SHA512-CRYPT}\$6\$...', 2048, 1, 0);"
|
|
```
|
|
- `quota` is in **MB** (existing accounts use `2048` = 2GB — match that
|
|
unless there's a reason not to).
|
|
- `enabled = 1` — required for the account to authenticate or receive mail
|
|
at all. Setting it to `0` disables the account without deleting it (see
|
|
§6).
|
|
- `sendonly = 0` — normal mailbox: can send *and* receive. Set to `1` only
|
|
for a send-only address that should never accept incoming mail (see §5).
|
|
|
|
That's it — no mailbox directory to create by hand. Dovecot auto-creates
|
|
`/var/vmail/mailboxes/jayfield.org/<user>/mail/` (owned `vmail:vmail`,
|
|
`700`) the first time the account logs in or receives mail.
|
|
|
|
## 4. Client configuration (no webmail — this stack is IMAP/SMTP only)
|
|
|
|
| Setting | Value |
|
|
|---|---|
|
|
| IMAP (recommended) | `mail.jayfield.org` : `993`, implicit TLS |
|
|
| IMAP (STARTTLS) | `mail.jayfield.org` : `143` |
|
|
| SMTP submission | `mail.jayfield.org` : `587`, STARTTLS + SASL (PLAIN) auth required |
|
|
| Username | `<user>@jayfield.org` (full address, not just the local part) |
|
|
| Password | the plaintext password you hashed in §2 |
|
|
| Port 25 | **not for clients** — server-to-server only, no SASL, no relay (`reject_unauth_destination`) |
|
|
|
|
`disable_plaintext_auth = yes` is set — clients must actually negotiate TLS
|
|
first; a client configured for plaintext IMAP/SMTP on the wrong port will
|
|
just fail to auth, not silently send credentials in the clear.
|
|
|
|
## 5. Send-only accounts (`sendonly = 1`)
|
|
|
|
Postfix's `recipient-access.cf` query rejects any inbound mail to a
|
|
`sendonly=1` address at `RCPT TO` time (`450`/`550` before it's even
|
|
accepted), while the account can still authenticate via SASL on `587` and
|
|
send outbound. Use this for something like a monitoring/alerting sender
|
|
address that should never actually receive replies.
|
|
|
|
## 6. Aliases (forward one address to another mailbox)
|
|
|
|
Aliases don't need their own mailbox or password — they're a pure
|
|
redirect, resolved at `RCPT TO` time via `aliases.cf`:
|
|
```bash
|
|
sudo mysql vmail -e "INSERT INTO aliases (source_username, source_domain, destination_username, destination_domain, enabled) VALUES ('sales', 'jayfield.org', 'jens', 'jayfield.org', 1);"
|
|
```
|
|
This host already has `postmaster`/`hostmaster`/`webmaster`/`wlan` →
|
|
`jens` as standing aliases (RFC-required roles + a house one) — check
|
|
`SELECT * FROM aliases;` before adding a new one to avoid duplicates.
|
|
|
|
## 7. Disabling / removing an account
|
|
|
|
Prefer disabling over deleting — it's reversible and doesn't touch the
|
|
Maildir:
|
|
```bash
|
|
sudo mysql vmail -e "UPDATE accounts SET enabled = 0 WHERE username = 'olduser' AND domain = 'jayfield.org';"
|
|
```
|
|
This blocks both authentication and inbound delivery immediately (both
|
|
`accounts.cf` and `recipient-access.cf` filter on `enabled = true`). The
|
|
actual mail data stays on disk at
|
|
`/var/vmail/mailboxes/jayfield.org/olduser/` until you decide to remove it
|
|
by hand — nothing auto-deletes it.
|
|
|
|
## 8. Verify a new account end-to-end
|
|
|
|
Don't trust the INSERT alone — confirm both directions actually work,
|
|
same discipline as `SETUP.md` §7:
|
|
|
|
```bash
|
|
# IMAP auth works
|
|
doveadm auth test newuser@jayfield.org
|
|
|
|
# Watch a real inbound + outbound test the same way §7 of SETUP.md describes:
|
|
# send TO newuser@jayfield.org from an external provider, confirm in
|
|
# /var/log/mail.log:
|
|
# dovecot: lmtp(newuser@jayfield.org)<...>: sieve: msgid=<...>: stored mail into mailbox 'INBOX'
|
|
# then send FROM the new account via a real mail client on 587, confirm:
|
|
# postfix/submission/smtpd[...]: sasl_method=PLAIN, sasl_username=newuser@jayfield.org
|
|
```
|