192 lines
5.6 KiB
Markdown
192 lines
5.6 KiB
Markdown
# MailAdmin MVP
|
|
|
|
Erste Version einer Admin-Webapp für dein DMS/SES/S3/SQS/DynamoDB-Mail-System.
|
|
|
|
Die App ist bewusst **node-orientiert** gebaut: Sie läuft auf `node1`, `node2`, usw. und entdeckt die Domains dynamisch aus dem lokalen Docker Mailserver. Dadurch ist sie geeignet für dein Szenario, bei dem Domains neu hinzukommen oder zwischen Nodes umziehen.
|
|
|
|
## Was diese Version bereits kann
|
|
|
|
- Login mit eigenem Admin-User
|
|
- PostgreSQL als Admin-Datenbank
|
|
- dynamische Domain-Erkennung über `docker exec mailserver setup email list`
|
|
- Domains pro Node speichern: `node1`, `node2`, ...
|
|
- Mailboxen anzeigen
|
|
- Mailbox anlegen
|
|
- Mailbox löschen
|
|
- Passwort zurücksetzen
|
|
- Speicherverbrauch pro Inbox scannen
|
|
- Forward- und Auto-Reply-Regeln in DynamoDB bearbeiten
|
|
- Blocklisten in DynamoDB bearbeiten
|
|
- Audit Log für Admin-Aktionen
|
|
- Frontend wird vom Backend direkt ausgeliefert
|
|
- Docker Compose Deployment auf dem Mailserver
|
|
|
|
## Warum dynamische Domains berücksichtigt sind
|
|
|
|
Die Domainliste ist **nicht hart codiert**. Beim Start und bei jedem manuellen Resync liest die App die DMS-Accounts aus:
|
|
|
|
```bash
|
|
docker exec mailserver setup email list
|
|
```
|
|
|
|
Daraus werden Domains und Mailboxen abgeleitet und in Postgres gespiegelt.
|
|
|
|
Wenn eine Domain später auf einen anderen Node umzieht, passiert Folgendes:
|
|
|
|
- auf dem alten Node werden die lokalen Mailboxen nach einem Resync als `missing_on_node` markiert
|
|
- auf dem neuen Node wird dieselbe Domain beim Resync als `active` mit `current_node=node2` erkannt
|
|
- die App-Codebasis bleibt identisch; nur `.env` unterscheidet `NODE_NAME=node1` oder `NODE_NAME=node2`
|
|
|
|
## Struktur
|
|
|
|
```text
|
|
mailadmin-mvp/
|
|
backend/
|
|
src/
|
|
server.ts Express App, API, static frontend
|
|
config.ts zentrale Konfiguration über Env Vars
|
|
db.ts Postgres Pool + Migration + Initial Admin
|
|
routes/
|
|
auth.ts Login/Logout/Me
|
|
domains.ts Domains dynamisch vom DMS syncen/anzeigen
|
|
mailboxes.ts Mailbox CRUD, Usage, Rules, Blocklist
|
|
audit.ts Audit Log API
|
|
services/
|
|
dms.ts DMS Docker Integration + Usage Scan
|
|
sync.ts Sync DMS -> Postgres
|
|
dynamodb.ts email-rules + email-blocked-senders
|
|
audit.ts Audit helper
|
|
utils/
|
|
email.ts Email/domain/local-part helpers
|
|
shell.ts sicherer execFile wrapper
|
|
migrations/001_init.sql PostgreSQL Schema
|
|
Dockerfile Backend + Frontend Image
|
|
frontend/
|
|
index.html Single Page App
|
|
app.js UI Logik ohne Build-Step
|
|
styles.css einfache Admin-Oberfläche
|
|
deploy/
|
|
caddy/ Caddy-Hinweise
|
|
scripts/ Snippet-Hilfe für update-caddy-certs.sh
|
|
docker-compose.yml App + Postgres
|
|
.env.example Beispiel-Konfiguration
|
|
```
|
|
|
|
## Installation auf node1
|
|
|
|
```bash
|
|
cd /home/aknuth/git/email-amazon
|
|
unzip mailadmin-mvp.zip
|
|
cd mailadmin-mvp
|
|
cp .env.example .env
|
|
nano .env
|
|
```
|
|
|
|
Wichtige Werte in `.env`:
|
|
|
|
```env
|
|
MAILADMIN_DB_PASSWORD=ein-sicheres-passwort
|
|
MAILADMIN_JWT_SECRET=sehr-langes-random-secret
|
|
MAILADMIN_ADMIN_EMAIL=admin@bayarea-cc.com
|
|
MAILADMIN_ADMIN_PASSWORD=StartPassword123!
|
|
NODE_NAME=node1
|
|
NODE_HOSTNAME=node1.email-srvr.com
|
|
DMS_CONTAINER=mailserver
|
|
AWS_REGION=us-east-2
|
|
AWS_ACCESS_KEY_ID=...
|
|
AWS_SECRET_ACCESS_KEY=...
|
|
```
|
|
|
|
Start:
|
|
|
|
```bash
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Logs:
|
|
|
|
```bash
|
|
docker logs -f mailadmin
|
|
```
|
|
|
|
## Installation auf node2
|
|
|
|
Gleicher Code, andere `.env`:
|
|
|
|
```env
|
|
NODE_NAME=node2
|
|
NODE_HOSTNAME=node2.email-srvr.com
|
|
```
|
|
|
|
Die Domainliste wird auch dort aus dem lokalen DMS gelesen.
|
|
|
|
## Caddy: mailadmin.{DOMAIN}
|
|
|
|
Dein bestehendes `update-caddy-certs.sh` generiert bereits dynamisch Domain-Blöcke. Ergänze im Domain-Loop zusätzlich diesen Block:
|
|
|
|
```caddy
|
|
# MailAdmin UI
|
|
mailadmin.DOMAIN_HERE {
|
|
encode gzip
|
|
reverse_proxy mailadmin:3000
|
|
}
|
|
```
|
|
|
|
Im Script sieht das ungefähr so aus:
|
|
|
|
```bash
|
|
OUTPUT="${OUTPUT}# MailAdmin UI\n"
|
|
OUTPUT="${OUTPUT}mailadmin.${domain} {\n"
|
|
OUTPUT="${OUTPUT} encode gzip\n"
|
|
OUTPUT="${OUTPUT} reverse_proxy mailadmin:3000\n"
|
|
OUTPUT="${OUTPUT}}\n\n"
|
|
```
|
|
|
|
Danach:
|
|
|
|
```bash
|
|
cd /home/aknuth/git/email-amazon/caddy
|
|
./update-caddy-certs.sh
|
|
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
|
|
```
|
|
|
|
## Wichtige Sicherheitshinweise
|
|
|
|
Diese MVP-Version mountet `/var/run/docker.sock`, damit der Backend-Container `docker exec mailserver ...` ausführen kann. Das ist praktisch, aber mächtig. Für die nächste Version wäre ein kleiner dedizierter Local-Agent mit begrenzten Operationen sicherer.
|
|
|
|
Das Admin-Passwort wird nur beim ersten Start erstellt. Wenn du `MAILADMIN_ADMIN_PASSWORD` später änderst, wird der vorhandene User nicht überschrieben. Das ist Absicht.
|
|
|
|
## API Kurzüberblick
|
|
|
|
```text
|
|
POST /api/auth/login
|
|
POST /api/auth/logout
|
|
GET /api/auth/me
|
|
|
|
GET /api/domains?resync=true
|
|
POST /api/domains/resync
|
|
|
|
GET /api/mailboxes?domain=example.com
|
|
POST /api/mailboxes
|
|
DELETE /api/mailboxes/:email
|
|
POST /api/mailboxes/:email/password
|
|
POST /api/mailboxes/usage/rescan
|
|
|
|
GET /api/mailboxes/:email/rules
|
|
PUT /api/mailboxes/:email/rules
|
|
|
|
GET /api/mailboxes/:email/blocklist
|
|
PUT /api/mailboxes/:email/blocklist
|
|
|
|
GET /api/audit
|
|
```
|
|
|
|
## Nächste sinnvolle Ausbaustufen
|
|
|
|
1. Domain-Detailseite mit DNS/SES/S3/SQS/Caddy Status
|
|
2. Admin-User Verwaltung im UI
|
|
3. Quotas pro Mailbox
|
|
4. Soft-Delete mit Retention statt hartem Löschen
|
|
5. Outbound Reporting über Postfix Logs und später SES Events
|
|
6. Node-Migration Workflow: Domain gezielt von node1 auf node2 markieren und prüfen
|