Server Operator Guide

Use this guide for production mail-server operations that sit below the web app: Postfix routing, logs, queues, service health, backups, DNS, and S/MIME runtime readiness.

Scope

The web app manages tenants, users, aliases, S/MIME identities, archives, support requests, and UI workflows. The server operator is responsible for the mail stack that actually accepts and delivers mail.

AreaOperator responsibility
PostfixInbound SMTP, authenticated submission, alias maps, queue health, DKIM/milter integration, and delivery logs.
DovecotIMAP login, mailbox storage, Maildir ownership, and local passdb behavior.
DNSMX, SPF, DKIM, DMARC, PTR, MTA-STS, and TLS-RPT correctness for hosted domains.
SecretsRoot-owned application secrets, DKIM private keys, S/MIME master key material, MFA secret access, and backup passphrases.
EvidenceMetadata-only mail events, Postfix logs, service status, deployment backups, and restore notes.

Daily Checks

systemctl --user status email-reseller
systemctl is-active postfix dovecot opendkim clamav-milter
mailq
curl -fsS http://localhost:3000/health

In the app, Super Admins can open the Security or mail-controls areas to review the server's reported mail-layer controls. Treat failed mail-stack services as production issues even when the web app is still running.

Alias Routing

Aliases exist in two places: the app database and the mail stack. The portal can show an alias under Active Aliases while Postfix still lacks the production route. Both must be correct.

On home-directory based mailbox servers, every hosted mailbox and alias should have a full-address route in /etc/postfix/virtual. Do not rely on local-part fallback for hosted domains: addresses such as support@example.com can otherwise deliver to the wrong Unix mailbox when multiple domains use the same local part.

The sync tool refuses shared physical mailbox targets for multiple active users. Aliases may point to the same owning mailbox, but two tenant users must not both collapse to one Unix/Dovecot mailbox such as support.

cd /home/jason/email-servers/emailresellerserver
node scripts/sync_postfix_virtual_from_db.js
sudo node scripts/sync_postfix_virtual_from_db.js --apply
postmap -q support@visasvista.com hash:/etc/postfix/virtual
postmap -q jason@mucache.app hash:/etc/postfix/virtual
postmap -q no-reply@mucache.app hash:/etc/postfix/virtual

no-reply addresses should not normally route into a human mailbox. For hosted domains where bounces should be suppressed, the full-address lookup should return no virtual route so the local no-reply alias can discard it.

For ongoing protection, configure the app's route-sync hook so alias and mailbox changes update Postfix immediately and fail loudly if the sync cannot run.

sudo bash scripts/install_mail_route_sync_hook.sh jason /home/jason/email-servers/emailresellerserver
systemctl --user restart email-reseller

jason ALL=(root) NOPASSWD: /usr/bin/node /home/jason/email-servers/emailresellerserver/scripts/sync_postfix_virtual_from_db.js --apply

MAIL_ROUTE_SYNC_SCRIPT="sudo -n /usr/bin/node /home/jason/email-servers/emailresellerserver/scripts/sync_postfix_virtual_from_db.js --apply"
MAIL_ROUTE_SYNC_CWD=/home/jason/email-servers/emailresellerserver
MAIL_ROUTE_SYNC_TIMEOUT=30000

A healthy alias test should show Postfix delivery with the alias in orig_to and the mailbox destination in to.

grep -E 'orig_to=<jason@mucache.app>|to=<support@mucache.app>' /var/log/mail.log
Do not rely only on the web UI alias list when validating inbound mail. Send a real test message, check Postfix logs, and confirm the destination mailbox receives it.

Mail Event Logs

Mail events are metadata-only records for send/receive operations. They are meant to answer whether mail was accepted, queued, rejected, delivered, or routed through an alias without storing message bodies or attachments.

Import Recent Postfix Events

cd /home/jason/email-servers/emailresellerserver
node scripts/import-mail-events.js --since-minutes=1440 /var/log/mail.log

Query Recent Events

cd /home/jason/email-servers/emailresellerserver
node -e "const db=require('./src/database/db');(async()=>{const r=await db.query('SELECT event_time,direction,source,queue_id,envelope_from,envelope_to,original_recipient,status,dsn FROM mail_events ORDER BY event_time DESC LIMIT 20');console.table(r.rows);})().finally(()=>db.pool.end())"

The importer is safe to rerun. It deduplicates events by source line hash. Webmail and outbound API sends are recorded by the app when SMTP acceptance succeeds or when the send attempt fails.

Queues

mailq
postqueue -p
postcat -q QUEUE_ID

Use postcat only when a deeper investigation requires it. Queue inspection can expose message content, so keep it limited and avoid copying message bodies into tickets or logs.

Services

ServiceHealthy stateWhat to check when unhealthy
email-resellerUser service active and /health returns OK.Application logs, database credentials, migrations, and restored .env.
postfixActive, listening on port 25, queue moving.MX delivery, relay restrictions, virtual maps, milters, and logs.
dovecotActive, IMAPS on 993, auth works.Passdb, Maildir ownership, TLS files, and auth logs.
opendkimActive and signing configured domains.Signing table, key table, private-key permissions, and selector DNS.
clamav-milterActive and listening where Postfix expects it.Stale processes, milter socket/port, ClamAV daemon status, and timeout behavior.

DNS

dig MX mucache.app
dig TXT mucache.app
dig TXT default._domainkey.mucache.app
dig TXT _dmarc.mucache.app
dig -x SERVER_IP

Preserve domain-specific production records in docs when onboarding a new domain. Current domain-specific runbooks include docs/PASSAGEWATCHTV_MAIL_SETUP.md for passagewatchtv.com.

For customer-facing DNS steps, use the Tenant Domain Setup Guide. Operators should also confirm PTR/rDNS with the IP provider because tenants usually cannot change it themselves.

WebAuthn / YubiKey Login

Security-key login uses browser WebAuthn/FIDO2. Users enroll a YubiKey from the portal MFA settings, and the server stores only credential public-key metadata for later challenge verification.

WEBAUTHN_RP_NAME=Secure Mail Portal
WEBAUTHN_RP_ID=mail.visasvista.com
WEBAUTHN_ORIGIN=https://mail.visasvista.com
WEBAUTHN_CHALLENGE_TTL_MINUTES=5
WEBAUTHN_RP_ID must be the browser host domain without scheme or port. WEBAUTHN_ORIGIN must exactly match the HTTPS origin users visit. If the portal hostname changes, users may need to enroll keys again for the new relying party.
A real YubiKey setup test requires an interactive browser prompt and user touch. API smoke tests can confirm challenge creation and validation plumbing, but they cannot manufacture a valid hardware signature.

Break-Glass Admin Recovery

Use this only when a Super Admin is locked out because MFA, WebAuthn, or YubiKey login is unavailable. Recovery requires SSH access to the production server; it is not exposed as a public web action.

Keep SSH tunnel recovery settings in a private .env.recovery.local file or an operator-managed .env. The Windows ssh_tunnel_admin.bat helper reads those files and should not contain real usernames, hosts, ports, admin emails, keys, or passwords.

Open a Local SSH Tunnel

ssh_tunnel_admin.bat
ssh_tunnel_admin.bat --show
ssh -N -L 9898:localhost:3000 your-ssh-alias

Then open http://localhost:9898 from the operator workstation. Keep the SSH session open while testing login.

Inspect Super Admin Recovery State

cd /home/your-ssh-user/email-servers/emailresellerserver
node scripts/break-glass-admin.js --list
node scripts/break-glass-admin.js --email=admin@example.com --dry-run

Recover a Locked Super Admin

cd /home/your-ssh-user/email-servers/emailresellerserver
node scripts/break-glass-admin.js \
  --email=admin@example.com \
  --disable-webauthn \
  --invalidate-sessions \
  --confirm=admin@example.com

If the account is also locked by authenticator-app MFA, add --disable-mfa. If the account was disabled, add --set-active. If the password is unknown, use node scripts/reset-admin-password.js --email=admin@example.com after reviewing the dry run.

After access is restored, immediately sign in through the tunnel, rotate the password if it was reset, enroll at least two YubiKeys or MFA factors, confirm normal HTTPS login, and record the recovery in the operator log. Do not leave a Super Admin account without MFA longer than necessary.

S/MIME Runtime

Server-side S/MIME signing requires SMIME_MASTER_KEY and an available openssl runtime. PKCS#12/PFX import also requires OpenSSL and the uploaded bundle must include the user's certificate plus matching private key.

openssl version
systemctl --user show email-reseller --property=Environment
YubiKey Manager on Windows 11, macOS, or Linux can inspect and configure FIDO2, OTP, and PIV functions. Current portal S/MIME uses imported PEM or exportable PKCS#12/PFX identities for server-side signing. Hardware-backed YubiKey S/MIME signing is planned separately so the private key can remain on the device.
Private keys generated on the device, or imported as non-exportable keys, cannot be extracted for the current server-side signing flow. Use an exportable PKCS#12 backup or PEM keypair only when policy allows server-held S/MIME keys.
For YubiKey-held certificates, users can export the public certificate with YubiKey Manager or ykman piv certificates export --format pem 9c jason@mail.visasvista.com.pem, using the certificate owner's email address in the filename, and add it as a recipient certificate. A local sidecar can safely help detect OpenSC/Yubico PIV tooling, enumerate PIV certificate slots, export the public certificate, and upload that public certificate to the portal. It must not attempt to extract a non-exportable private key.
Email-attached public certificates may be saved as recipient certificates, but private signing keys should not be imported from email attachments. Server-side signing identities should come only from intentional PEM or PKCS#12/PFX identity import workflows.

Archive Mounts

Network-share archive storage should be prepared by the server operator before tenant admins can choose it in the web interface. Mount approved shares under a controlled path such as /mnt/email-reseller-archives; do not let the web app accept arbitrary server paths or raw Samba credentials from users.

sudo mkdir -p /mnt/email-reseller-archives/customer-a
sudo mount -t cifs //fileserver/customer-a-archives /mnt/email-reseller-archives/customer-a \
  -o credentials=/etc/email-reseller/samba-customer-a.cred,uid=jason,gid=jason,dir_mode=0750,file_mode=0640,vers=3.0
findmnt /mnt/email-reseller-archives/customer-a
The first version of web-configured archive destinations should expose only operator-approved mount roots. Tenant admins may choose a destination within those roots, but the server operator remains responsible for Samba credentials, mount health, ownership, and free-space monitoring.
Archive files written to mounted shares must be encrypted before they leave the app storage workflow. Do not store archive encryption keys, S/MIME master keys, database backups, or Samba credential files on the same share as the encrypted user archives.

Backups

Use secure backups for disaster recovery. Standard deployments also create a pre-deploy backup under /home/jason/email-servers/backups.

cd /home/jason/email-servers/emailresellerserver
bash scripts/secure_backup.sh

Protect backup passphrases separately from backup archives. Secure backups may include database data, S/MIME/MFA secret access, Dovecot users, DKIM keys, mail-stack configuration, and optional Maildir contents.

Troubleshooting

SymptomFirst checks
Alias visible but mail missingCheck /etc/postfix/virtual, postmap -q, Postfix logs, and imported mail_events for orig_to.
External sender gets bounceCheck MX, local recipient table, virtual alias maps, and reject lines in /var/log/mail.log.
Outbound stuckCheck mailq, SMTP authentication, DKIM/milter status, DNS reputation, and remote deferral responses.
Users cannot log in by IMAPCheck Dovecot status, passdb entries, password sync, TLS, and client username format.
S/MIME unavailableCheck SMIME_MASTER_KEY, OpenSSL, certificate validity, and certificate email match.