Compare commits
11 Commits
b2dfb76a7e
...
contabo
| Author | SHA1 | Date | |
|---|---|---|---|
| 4422fba707 | |||
| 649a55eecd | |||
| 1936646b20 | |||
| 528497094b | |||
| fedd2d4f34 | |||
| 119f8b1152 | |||
| 5b0a087a78 | |||
| 29a34ce4e5 | |||
| 0540b1083c | |||
| 0ecaa2ce11 | |||
| 25c26e4f79 |
@@ -27,7 +27,12 @@ CERTS_BASE_PATH=${CERTS_BASE_PATH:-"/etc/mail/certs"}
|
|||||||
|
|
||||||
# Node-Hostname: Fallback-Cert für DMS (kein Wildcard, direktes Cert)
|
# Node-Hostname: Fallback-Cert für DMS (kein Wildcard, direktes Cert)
|
||||||
# Muss mit dem 'hostname' in docker-compose.yml übereinstimmen.
|
# Muss mit dem 'hostname' in docker-compose.yml übereinstimmen.
|
||||||
NODE_HOSTNAME=${NODE_HOSTNAME:-"node1.email-srvr.com"}
|
if [ -z "$NODE_HOSTNAME" ]; then
|
||||||
|
echo "❌ NODE_HOSTNAME ist nicht gesetzt!"
|
||||||
|
echo "Beispiel:"
|
||||||
|
echo " DMS_CONTAINER=mailserver NODE_HOSTNAME=node2.email-srvr.com ./setup-dms-tls.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "============================================================"
|
echo "============================================================"
|
||||||
echo " 🔐 DMS TLS SNI Setup (Multi-Domain)"
|
echo " 🔐 DMS TLS SNI Setup (Multi-Domain)"
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ aws s3api put-public-access-block \
|
|||||||
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
|
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
|
||||||
|
|
||||||
# Lebenszyklus-Konfiguration hinzufügen
|
# Lebenszyklus-Konfiguration hinzufügen
|
||||||
echo "Lebenszyklus-Konfiguration hinzufügen (E-Mails werden nach 90 Tagen gelöscht)..."
|
echo "Lebenszyklus-Konfiguration hinzufügen (E-Mails werden nach 7 Tagen gelöscht)..."
|
||||||
aws s3api put-bucket-lifecycle-configuration \
|
aws s3api put-bucket-lifecycle-configuration \
|
||||||
--bucket ${S3_BUCKET_NAME} \
|
--bucket ${S3_BUCKET_NAME} \
|
||||||
--lifecycle-configuration '{
|
--lifecycle-configuration '{
|
||||||
@@ -43,7 +43,7 @@ aws s3api put-bucket-lifecycle-configuration \
|
|||||||
"ID": "DeleteOldEmails",
|
"ID": "DeleteOldEmails",
|
||||||
"Status": "Enabled",
|
"Status": "Enabled",
|
||||||
"Expiration": {
|
"Expiration": {
|
||||||
"Days": 14
|
"Days": 7
|
||||||
},
|
},
|
||||||
"Filter": {
|
"Filter": {
|
||||||
"Prefix": ""
|
"Prefix": ""
|
||||||
@@ -76,6 +76,14 @@ aws s3api put-bucket-policy \
|
|||||||
]
|
]
|
||||||
}'
|
}'
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Cost Allocation Tags setzen
|
||||||
|
# ------------------------
|
||||||
|
echo "Setze Cost Allocation Tag (BucketName)..."
|
||||||
|
aws s3api put-bucket-tagging \
|
||||||
|
--bucket ${S3_BUCKET_NAME} \
|
||||||
|
--tagging "TagSet=[{Key=BucketName,Value=${S3_BUCKET_NAME}}]"
|
||||||
|
|
||||||
echo "S3 Bucket $S3_BUCKET_NAME wurde erfolgreich erstellt und konfiguriert."
|
echo "S3 Bucket $S3_BUCKET_NAME wurde erfolgreich erstellt und konfiguriert."
|
||||||
echo "Bucket-ARN: arn:aws:s3:::$S3_BUCKET_NAME"
|
echo "Bucket-ARN: arn:aws:s3:::$S3_BUCKET_NAME"
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,14 @@
|
|||||||
# Standard: mail.${DOMAIN_NAME}
|
# Standard: mail.${DOMAIN_NAME}
|
||||||
# Override: export MAIL_FROM_SUBDOMAIN="mailfrom" (nur der Prefix, ohne Domain)
|
# Override: export MAIL_FROM_SUBDOMAIN="mailfrom" (nur der Prefix, ohne Domain)
|
||||||
#
|
#
|
||||||
|
# Lambda Deployment:
|
||||||
|
# Standard: Überspringt den Deploy (SKIP_LAMBDA_DEPLOY=true)
|
||||||
|
# Override: export SKIP_LAMBDA_DEPLOY="false" (um Lambda neu auszurollen)
|
||||||
|
#
|
||||||
# Beispiel:
|
# Beispiel:
|
||||||
# export DOMAIN_NAME="buddelectric.net"
|
# export DOMAIN_NAME="buddelectric.net"
|
||||||
# export MAIL_FROM_SUBDOMAIN="mailfrom" # → mailfrom.buddelectric.net
|
# export MAIL_FROM_SUBDOMAIN="mailfrom" # → mailfrom.buddelectric.net
|
||||||
|
# export SKIP_LAMBDA_DEPLOY="false" # → Lambda wird aktualisiert
|
||||||
# ./awsses.sh
|
# ./awsses.sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -18,17 +23,20 @@ set -e
|
|||||||
if ! command -v jq &> /dev/null; then echo "Fehler: 'jq' fehlt."; exit 1; fi
|
if ! command -v jq &> /dev/null; then echo "Fehler: 'jq' fehlt."; exit 1; fi
|
||||||
if [ -z "$DOMAIN_NAME" ]; then echo "Fehler: DOMAIN_NAME ist nicht gesetzt."; exit 1; fi
|
if [ -z "$DOMAIN_NAME" ]; then echo "Fehler: DOMAIN_NAME ist nicht gesetzt."; exit 1; fi
|
||||||
|
|
||||||
# Prüfen ob Python Code da ist
|
|
||||||
PYTHON_FILE="ses_sns_shim_global.py"
|
|
||||||
if [ ! -f "$PYTHON_FILE" ]; then
|
|
||||||
echo "Fehler: $PYTHON_FILE nicht gefunden!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- VARIABLEN ---
|
# --- VARIABLEN ---
|
||||||
AWS_REGION=${AWS_REGION:-"us-east-2"}
|
AWS_REGION=${AWS_REGION:-"us-east-2"}
|
||||||
EMAIL_PREFIX=${EMAIL_PREFIX:-""}
|
EMAIL_PREFIX=${EMAIL_PREFIX:-""}
|
||||||
CONFIGURATION_SET_NAME="relay-outbound"
|
CONFIGURATION_SET_NAME="relay-outbound"
|
||||||
|
SKIP_LAMBDA_DEPLOY=${SKIP_LAMBDA_DEPLOY:-"true"}
|
||||||
|
|
||||||
|
# Prüfen ob Python Code da ist (nur wenn auch deployt werden soll)
|
||||||
|
PYTHON_FILE="ses_sns_shim_global.py"
|
||||||
|
if [ "$SKIP_LAMBDA_DEPLOY" != "true" ]; then
|
||||||
|
if [ ! -f "$PYTHON_FILE" ]; then
|
||||||
|
echo "Fehler: $PYTHON_FILE nicht gefunden!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# MAIL FROM Subdomain (konfigurierbar)
|
# MAIL FROM Subdomain (konfigurierbar)
|
||||||
MAIL_FROM_SUBDOMAIN=${MAIL_FROM_SUBDOMAIN:-"mail"}
|
MAIL_FROM_SUBDOMAIN=${MAIL_FROM_SUBDOMAIN:-"mail"}
|
||||||
@@ -49,6 +57,7 @@ LAMBDA_ROLE_NAME="SesShimGlobalRole"
|
|||||||
echo "=========================================================="
|
echo "=========================================================="
|
||||||
echo " SES Setup (S3 -> Global Lambda Shim -> SQS) für $DOMAIN_NAME"
|
echo " SES Setup (S3 -> Global Lambda Shim -> SQS) für $DOMAIN_NAME"
|
||||||
echo " MAIL FROM: $MAIL_FROM_DOMAIN"
|
echo " MAIL FROM: $MAIL_FROM_DOMAIN"
|
||||||
|
echo " SKIP_LAMBDA: $SKIP_LAMBDA_DEPLOY"
|
||||||
echo "=========================================================="
|
echo "=========================================================="
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
@@ -113,8 +122,12 @@ echo " -> Permissions aktualisiert."
|
|||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# 4. Lambda Funktion erstellen/updaten (Global!)
|
# 4 & 5. Lambda Funktion + SES Permissions (optional)
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
if [ "$SKIP_LAMBDA_DEPLOY" = "true" ]; then
|
||||||
|
echo "[4/6] Global Lambda Shim deployen... (ÜBERSPRUNGEN)"
|
||||||
|
echo "[5/6] SES Permission für Lambda... (ÜBERSPRUNGEN)"
|
||||||
|
else
|
||||||
echo "[4/6] Global Lambda Shim deployen..."
|
echo "[4/6] Global Lambda Shim deployen..."
|
||||||
# Zip erstellen
|
# Zip erstellen
|
||||||
cp "$PYTHON_FILE" lambda_function.py
|
cp "$PYTHON_FILE" lambda_function.py
|
||||||
@@ -139,15 +152,13 @@ fi
|
|||||||
# Aufräumen
|
# Aufräumen
|
||||||
rm lambda.zip lambda_function.py
|
rm lambda.zip lambda_function.py
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 5. Permission: SES darf Lambda aufrufen (Global, einmalig)
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
echo "[5/6] SES Permission für Lambda..."
|
echo "[5/6] SES Permission für Lambda..."
|
||||||
aws lambda add-permission --function-name "$LAMBDA_NAME" \
|
aws lambda add-permission --function-name "$LAMBDA_NAME" \
|
||||||
--statement-id "AllowSESInvoke-Global" \
|
--statement-id "AllowSESInvoke-Global" \
|
||||||
--action "lambda:InvokeFunction" \
|
--action "lambda:InvokeFunction" \
|
||||||
--principal "ses.amazonaws.com" \
|
--principal "ses.amazonaws.com" \
|
||||||
--region "$AWS_REGION" 2>/dev/null || true
|
--region "$AWS_REGION" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# 6. SES Rule (S3 + Global Lambda)
|
# 6. SES Rule (S3 + Global Lambda)
|
||||||
|
|||||||
0
basic_setup/check_logins.py
Normal file → Executable file
0
basic_setup/check_logins.py
Normal file → Executable file
@@ -5,15 +5,22 @@
|
|||||||
# Setzt mail/imap/smtp/pop Subdomains für domain-spezifischen Mailserver-Zugang
|
# Setzt mail/imap/smtp/pop Subdomains für domain-spezifischen Mailserver-Zugang
|
||||||
#
|
#
|
||||||
# MIGRATIONS-FLAGS:
|
# MIGRATIONS-FLAGS:
|
||||||
# SKIP_CLIENT_DNS=true → Abschnitt 8 (imap/smtp/pop/webmail) + 10 (SRV) überspringen
|
# SKIP_CLIENT_DNS=true → Abschnitt 8 (mail/imap/smtp/pop/webmail) überspringen
|
||||||
# Nutzen: Client-Subdomains bleiben beim alten Provider
|
# Nutzen: Client-Subdomains bleiben komplett beim alten Provider
|
||||||
|
# SKIP_PROTOCOL_DNS=true → nur imap/smtp/pop überspringen, aber mail + webmail setzen
|
||||||
|
# Nutzen: Webmail/Autodiscover vorbereiten, Mailclients bleiben beim alten Provider
|
||||||
# SKIP_DMARC=true → Abschnitt 7 (DMARC) überspringen
|
# SKIP_DMARC=true → Abschnitt 7 (DMARC) überspringen
|
||||||
# Nutzen: Bestehenden DMARC-Record nicht anfassen
|
# Nutzen: Bestehenden DMARC-Record nicht anfassen
|
||||||
#
|
#
|
||||||
# Typischer Migrations-Ablauf:
|
# Typischer Migrations-Ablauf:
|
||||||
# Phase 0 (Vorbereitung): SKIP_CLIENT_DNS=true SKIP_DMARC=true → nur SES + SPF
|
# Phase 0a (Vorbereitung, Client-Records bleiben alt):
|
||||||
# Phase 1 (MX Cutover): MX umstellen (manuell)
|
# SKIP_CLIENT_DNS=true SKIP_DMARC=true → nur SES + SPF/DKIM/MailFrom
|
||||||
# Phase 2 (Client Switch): ohne SKIP Flags → alle Records setzen
|
# Phase 0b (Webmail vorbereiten, imap/smtp/pop bleiben alt):
|
||||||
|
# SKIP_CLIENT_DNS=false SKIP_PROTOCOL_DNS=true SKIP_DMARC=false
|
||||||
|
# Phase 1 (MX Cutover):
|
||||||
|
# MX manuell umstellen
|
||||||
|
# Phase 2 (Client Switch):
|
||||||
|
# SKIP_CLIENT_DNS=false SKIP_PROTOCOL_DNS=false → alle Client-Records setzen
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -23,6 +30,7 @@ DRY_RUN=${DRY_RUN:-"false"}
|
|||||||
|
|
||||||
# Migrations-Flags (NEU)
|
# Migrations-Flags (NEU)
|
||||||
SKIP_CLIENT_DNS=${SKIP_CLIENT_DNS:-"false"}
|
SKIP_CLIENT_DNS=${SKIP_CLIENT_DNS:-"false"}
|
||||||
|
SKIP_PROTOCOL_DNS=${SKIP_PROTOCOL_DNS:-"false"}
|
||||||
SKIP_DMARC=${SKIP_DMARC:-"false"}
|
SKIP_DMARC=${SKIP_DMARC:-"false"}
|
||||||
|
|
||||||
# IP des Mailservers - PFLICHT wenn keine CNAME-Kette gewünscht
|
# IP des Mailservers - PFLICHT wenn keine CNAME-Kette gewünscht
|
||||||
@@ -50,7 +58,8 @@ echo " 🌍 Region: $AWS_REGION"
|
|||||||
echo " 📬 Mail-Server Target: $TARGET_MAIL_SERVER"
|
echo " 📬 Mail-Server Target: $TARGET_MAIL_SERVER"
|
||||||
[ -n "$MAIL_SERVER_IP" ] && echo " 🖥️ Server IP: $MAIL_SERVER_IP"
|
[ -n "$MAIL_SERVER_IP" ] && echo " 🖥️ Server IP: $MAIL_SERVER_IP"
|
||||||
[ "$DRY_RUN" = "true" ] && echo " ⚠️ DRY RUN MODE - Keine Änderungen!"
|
[ "$DRY_RUN" = "true" ] && echo " ⚠️ DRY RUN MODE - Keine Änderungen!"
|
||||||
[ "$SKIP_CLIENT_DNS" = "true" ] && echo " ⏭️ SKIP: Client-Subdomains (imap/smtp/pop/webmail/SRV)"
|
[ "$SKIP_CLIENT_DNS" = "true" ] && echo " ⏭️ SKIP: alle Client-Subdomains (mail/imap/smtp/pop/webmail)"
|
||||||
|
[ "$SKIP_PROTOCOL_DNS" = "true" ] && echo " ⏭️ SKIP: Protokoll-Subdomains imap/smtp/pop bleiben unverändert"
|
||||||
[ "$SKIP_DMARC" = "true" ] && echo " ⏭️ SKIP: DMARC Record"
|
[ "$SKIP_DMARC" = "true" ] && echo " ⏭️ SKIP: DMARC Record"
|
||||||
echo "============================================================"
|
echo "============================================================"
|
||||||
|
|
||||||
@@ -255,14 +264,23 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# SCHRITT 6: Root Domain MX (nur Info, wird nicht geändert)
|
# SCHRITT 6: Root Domain MX
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
echo ""
|
echo ""
|
||||||
echo "--- 6. Root Domain MX (nur Info, wird nicht geändert) ---"
|
echo "--- 6. Root Domain MX ---"
|
||||||
CURRENT_MX=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=MX&name=$DOMAIN_NAME" \
|
# Prüfen, ob bereits MX-Records für die Root-Domain existieren
|
||||||
|
MX_COUNT=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=MX&name=$DOMAIN_NAME" \
|
||||||
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" \
|
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" \
|
||||||
| jq -r '.result[0].content // "keiner"')
|
| jq -r '.result | length')
|
||||||
echo " ℹ️ MX vorhanden: $CURRENT_MX (wird nicht geändert)"
|
|
||||||
|
if [ "$MX_COUNT" -eq 0 ]; then
|
||||||
|
echo " ℹ️ Kein MX-Record vorhanden. Setze initialen SES Inbound MX..."
|
||||||
|
ensure_record "MX" "$DOMAIN_NAME" "inbound-smtp.${AWS_REGION}.amazonaws.com" false 10
|
||||||
|
else
|
||||||
|
echo " ⛔ MX-Record(s) für @ bereits vorhanden ($MX_COUNT Eintrag/Einträge)."
|
||||||
|
echo " → Wird zum Schutz der alten Postfächer AUF KEINEN FALL automatisch geändert!"
|
||||||
|
echo " → Muss nach der Migration manuell umgestellt werden."
|
||||||
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# SCHRITT 7: DMARC
|
# SCHRITT 7: DMARC
|
||||||
@@ -283,11 +301,12 @@ echo ""
|
|||||||
echo "--- 8. Mailclient Subdomains (A + CNAME) ---"
|
echo "--- 8. Mailclient Subdomains (A + CNAME) ---"
|
||||||
if [ "$SKIP_CLIENT_DNS" = "true" ]; then
|
if [ "$SKIP_CLIENT_DNS" = "true" ]; then
|
||||||
echo " ⏭️ Übersprungen (SKIP_CLIENT_DNS=true)"
|
echo " ⏭️ Übersprungen (SKIP_CLIENT_DNS=true)"
|
||||||
echo " ℹ️ imap/smtp/pop/webmail bleiben beim alten Provider."
|
echo " ℹ️ mail/imap/smtp/pop/webmail bleiben beim alten Provider."
|
||||||
echo " ℹ️ Setze SKIP_CLIENT_DNS=false nach MX-Cutover + Client-Umstellung."
|
echo " ℹ️ Setze SKIP_CLIENT_DNS=false nach MX-Cutover + Client-Umstellung."
|
||||||
else
|
else
|
||||||
if [ -n "$MAIL_SERVER_IP" ]; then
|
if [ -n "$MAIL_SERVER_IP" ]; then
|
||||||
# A-Record für mail.<domain> direkt auf Server-IP
|
# A-Record für mail.<domain> direkt auf Server-IP
|
||||||
|
# Wichtig: mail muss DNS-only bleiben; Cloudflare Proxy funktioniert nicht für SMTP/IMAP/POP.
|
||||||
ensure_record "A" "mail.$DOMAIN_NAME" "$MAIL_SERVER_IP" false
|
ensure_record "A" "mail.$DOMAIN_NAME" "$MAIL_SERVER_IP" false
|
||||||
else
|
else
|
||||||
# CNAME auf externen Ziel-Host (nur wenn verschieden)
|
# CNAME auf externen Ziel-Host (nur wenn verschieden)
|
||||||
@@ -296,11 +315,19 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# imap, smtp, pop, webmail → CNAME auf mail.<domain>
|
# Webmail kann bereits vorbereitet werden, auch wenn imap/smtp/pop noch beim alten Provider bleiben.
|
||||||
|
ensure_record "CNAME" "webmail.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
||||||
|
|
||||||
|
if [ "$SKIP_PROTOCOL_DNS" = "true" ]; then
|
||||||
|
echo " ⏭️ Überspringe imap/smtp/pop (SKIP_PROTOCOL_DNS=true)"
|
||||||
|
echo " ℹ️ imap/smtp/pop bleiben unverändert beim alten Provider."
|
||||||
|
else
|
||||||
|
# imap/smtp/pop → CNAME auf mail.<domain>
|
||||||
|
# Wichtig: diese Records müssen DNS-only bleiben; Cloudflare Proxy funktioniert nicht für Mail-Protokolle.
|
||||||
ensure_record "CNAME" "imap.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
ensure_record "CNAME" "imap.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
||||||
ensure_record "CNAME" "smtp.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
ensure_record "CNAME" "smtp.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
||||||
ensure_record "CNAME" "pop.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
ensure_record "CNAME" "pop.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
||||||
ensure_record "CNAME" "webmail.$DOMAIN_NAME" "mail.$DOMAIN_NAME" false
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -318,7 +345,12 @@ if [ "$SKIP_CLIENT_DNS" = "true" ]; then
|
|||||||
echo ""
|
echo ""
|
||||||
echo " ⚠️ Client-Subdomains wurden NICHT geändert."
|
echo " ⚠️ Client-Subdomains wurden NICHT geändert."
|
||||||
echo " Nach MX-Cutover + Worker-Validierung erneut ausführen mit:"
|
echo " Nach MX-Cutover + Worker-Validierung erneut ausführen mit:"
|
||||||
echo " SKIP_CLIENT_DNS=false SKIP_DMARC=false ./cloudflareMigrationDns.sh"
|
echo " SKIP_CLIENT_DNS=false SKIP_PROTOCOL_DNS=false SKIP_DMARC=false ./cloudflareMigrationDns.sh"
|
||||||
|
elif [ "$SKIP_PROTOCOL_DNS" = "true" ]; then
|
||||||
|
echo ""
|
||||||
|
echo " ⚠️ imap/smtp/pop wurden NICHT geändert."
|
||||||
|
echo " Für den finalen Client-Cutover erneut ausführen mit:"
|
||||||
|
echo " SKIP_CLIENT_DNS=false SKIP_PROTOCOL_DNS=false SKIP_DMARC=false ./cloudflareMigrationDns.sh"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo " Mailclient-Konfiguration für Kunden:"
|
echo " Mailclient-Konfiguration für Kunden:"
|
||||||
|
|||||||
32
basic_setup/legacy/s3-retention.sh
Executable file
32
basic_setup/legacy/s3-retention.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Aktualisiere Lifecycle-Regeln (7 Tage) für alle E-Mail-Buckets..."
|
||||||
|
|
||||||
|
for BUCKET in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
|
||||||
|
|
||||||
|
# Prüfen, ob der Name auf '-emails' endet
|
||||||
|
if [[ "$BUCKET" == *-emails ]]; then
|
||||||
|
echo "⚙️ Setze 7-Tage-Regel für: $BUCKET"
|
||||||
|
|
||||||
|
aws s3api put-bucket-lifecycle-configuration \
|
||||||
|
--bucket "$BUCKET" \
|
||||||
|
--lifecycle-configuration '{
|
||||||
|
"Rules": [
|
||||||
|
{
|
||||||
|
"ID": "DeleteOldEmails",
|
||||||
|
"Status": "Enabled",
|
||||||
|
"Expiration": {
|
||||||
|
"Days": 7
|
||||||
|
},
|
||||||
|
"Filter": {
|
||||||
|
"Prefix": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
else
|
||||||
|
echo "⏭️ Überspringe (kein E-Mail-Bucket): $BUCKET"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Fertig! Alle E-Mail-Buckets löschen jetzt Objekte nach 7 Tagen."
|
||||||
31
basic_setup/legacy/sync-s3-tags.sh
Executable file
31
basic_setup/legacy/sync-s3-tags.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# sync-s3-tags.sh - Synchronisiert Bucket Tags welche fuer die Abrechung verwendet werden
|
||||||
|
echo "Passe Bucket-Tags an..."
|
||||||
|
|
||||||
|
for BUCKET in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
|
||||||
|
# Aktuellen Tag abfragen (Fehler unterdrücken)
|
||||||
|
TAG=$(aws s3api get-bucket-tagging --bucket "$BUCKET" --query 'TagSet[?Key==`BucketName`].Value' --output text 2>/dev/null)
|
||||||
|
|
||||||
|
# Prüfen, ob der Name auf '-emails' endet
|
||||||
|
if [[ "$BUCKET" == *-emails ]]; then
|
||||||
|
# Soll getaggt sein
|
||||||
|
if [ -z "$TAG" ] || [ "$TAG" == "None" ]; then
|
||||||
|
echo "➕ Setze fehlendes Tag für: $BUCKET"
|
||||||
|
aws s3api put-bucket-tagging \
|
||||||
|
--bucket "$BUCKET" \
|
||||||
|
--tagging "TagSet=[{Key=BucketName,Value=$BUCKET}]"
|
||||||
|
else
|
||||||
|
echo "✅ OK (bereits getaggt): $BUCKET"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Soll NICHT getaggt sein
|
||||||
|
if [ -n "$TAG" ] && [ "$TAG" != "None" ]; then
|
||||||
|
echo "🗑️ Entferne Tag von: $BUCKET"
|
||||||
|
aws s3api delete-bucket-tagging --bucket "$BUCKET"
|
||||||
|
else
|
||||||
|
echo "✅ OK (ohne Tag): $BUCKET"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Fertig! Alle '-emails' Buckets sind getaggt, bei allen anderen wurden die Tags entfernt."
|
||||||
158
basic_setup/mailadminDns.sh
Executable file
158
basic_setup/mailadminDns.sh
Executable file
@@ -0,0 +1,158 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# mailadminDns.sh
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Setzt AUSSCHLIESSLICH den DNS-Record fuer den mailadmin-Zugang.
|
||||||
|
# Faesst NICHTS anderes an (kein SES, SPF, DKIM, MX, keine anderen
|
||||||
|
# Subdomains). Kann gefahrlos auf bereits migrierten Domains laufen.
|
||||||
|
#
|
||||||
|
# Verwendet dieselbe ensure_record-Logik wie cloudflareMigrationDns.sh,
|
||||||
|
# damit das Verhalten (Create/Update/Skip-bei-identisch) identisch ist.
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# PFLICHT-VARIABLEN:
|
||||||
|
# DOMAIN_NAME Kundendomain, z.B. innungsapp.com
|
||||||
|
# CF_API_TOKEN Cloudflare API Token
|
||||||
|
#
|
||||||
|
# OPTIONALE VARIABLEN:
|
||||||
|
# MAILADMIN_HOST Subdomain-Label, Default: "mailadmin"
|
||||||
|
# -> ergibt mailadmin.<DOMAIN_NAME>
|
||||||
|
# MAILADMIN_TARGET CNAME-Ziel, Default: "mail.<DOMAIN_NAME>"
|
||||||
|
# Beispiele:
|
||||||
|
# mail.innungsapp.com (pro-Domain Modell)
|
||||||
|
# mailadmin.bayarea-cc.com (zentrales Modell)
|
||||||
|
# DRY_RUN "true" -> zeigt nur an, aendert nichts
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# BEISPIELE:
|
||||||
|
#
|
||||||
|
# # Standard: mailadmin.innungsapp.com -> mail.innungsapp.com
|
||||||
|
# DOMAIN_NAME=innungsapp.com CF_API_TOKEN=xxx ./mailadminDns.sh
|
||||||
|
#
|
||||||
|
# # Zentrales Modell: mailadmin.innungsapp.com -> mailadmin.bayarea-cc.com
|
||||||
|
# DOMAIN_NAME=innungsapp.com \
|
||||||
|
# MAILADMIN_TARGET=mailadmin.bayarea-cc.com \
|
||||||
|
# CF_API_TOKEN=xxx ./mailadminDns.sh
|
||||||
|
#
|
||||||
|
# # Erst testen ohne zu aendern
|
||||||
|
# DOMAIN_NAME=innungsapp.com CF_API_TOKEN=xxx DRY_RUN=true ./mailadminDns.sh
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# --- KONFIGURATION ---
|
||||||
|
DRY_RUN=${DRY_RUN:-"false"}
|
||||||
|
MAILADMIN_HOST=${MAILADMIN_HOST:-"mailadmin"}
|
||||||
|
MAILADMIN_TARGET=${MAILADMIN_TARGET:-"mail.${DOMAIN_NAME}"}
|
||||||
|
|
||||||
|
# --- CHECKS ---
|
||||||
|
if [ -z "$DOMAIN_NAME" ]; then echo "❌ Fehler: DOMAIN_NAME fehlt."; exit 1; fi
|
||||||
|
if [ -z "$CF_API_TOKEN" ]; then echo "❌ Fehler: CF_API_TOKEN fehlt."; exit 1; fi
|
||||||
|
if ! command -v jq &> /dev/null; then echo "❌ Fehler: 'jq' fehlt."; exit 1; fi
|
||||||
|
if ! command -v curl &> /dev/null; then echo "❌ Fehler: 'curl' fehlt."; exit 1; fi
|
||||||
|
|
||||||
|
RECORD_NAME="${MAILADMIN_HOST}.${DOMAIN_NAME}"
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo " 🔧 mailadmin DNS Setup"
|
||||||
|
echo " 🌐 Domain: $DOMAIN_NAME"
|
||||||
|
echo " 📍 Record: CNAME $RECORD_NAME → $MAILADMIN_TARGET"
|
||||||
|
[ "$DRY_RUN" = "true" ] && echo " ⚠️ DRY RUN MODE - Keine Änderungen!"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
# Schutz: CNAME auf sich selbst macht keinen Sinn
|
||||||
|
if [ "$RECORD_NAME" == "$MAILADMIN_TARGET" ]; then
|
||||||
|
echo "❌ Fehler: CNAME-Ziel ist identisch mit dem Record-Namen."
|
||||||
|
echo " $RECORD_NAME kann nicht auf sich selbst zeigen."
|
||||||
|
echo " Setze MAILADMIN_TARGET auf einen anderen Host."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. ZONE ID HOLEN
|
||||||
|
echo "🔍 Suche Cloudflare Zone ID..."
|
||||||
|
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN_NAME" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" | jq -r '.result[0].id')
|
||||||
|
|
||||||
|
if [ "$ZONE_ID" == "null" ] || [ -z "$ZONE_ID" ]; then
|
||||||
|
echo "❌ Zone nicht gefunden für $DOMAIN_NAME."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " ✅ Zone ID: $ZONE_ID"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# FUNKTION: ensure_record
|
||||||
|
# Identisch zur Logik in cloudflareMigrationDns.sh, reduziert auf
|
||||||
|
# die Typen die wir hier brauchen (CNAME).
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
ensure_record() {
|
||||||
|
local type=$1
|
||||||
|
local name=$2
|
||||||
|
local content=$3
|
||||||
|
local proxied=${4:-false}
|
||||||
|
|
||||||
|
echo " ⚙️ Prüfe $type $name..."
|
||||||
|
|
||||||
|
local search_res=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=$type&name=$name" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json")
|
||||||
|
|
||||||
|
local rec_id=$(echo "$search_res" | jq -r '.result[0].id')
|
||||||
|
local rec_content=$(echo "$search_res" | jq -r '.result[0].content')
|
||||||
|
|
||||||
|
[ -z "$rec_id" ] && rec_id="null"
|
||||||
|
[ -z "$rec_content" ] && rec_content="null"
|
||||||
|
|
||||||
|
local json_data=$(jq -n --arg t "$type" --arg n "$name" --arg c "$content" --argjson p "$proxied" \
|
||||||
|
'{type: $t, name: $n, content: $c, ttl: 3600, proxied: $p}')
|
||||||
|
|
||||||
|
if [ "$rec_id" == "null" ]; then
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
echo " [DRY] Würde ERSTELLEN: $type $name → $content"
|
||||||
|
else
|
||||||
|
local res=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" --data "$json_data")
|
||||||
|
if [ "$(echo $res | jq -r .success)" == "true" ]; then
|
||||||
|
echo " ✅ Erstellt: $type $name → $content"
|
||||||
|
else
|
||||||
|
echo " ❌ Fehler beim Erstellen: $(echo $res | jq -r '.errors[0].message')"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$rec_content" == "$content" ]; then
|
||||||
|
echo " 🆗 Identisch ($rec_content). Überspringe."
|
||||||
|
else
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
echo " [DRY] Würde UPDATEN: '$rec_content' → '$content'"
|
||||||
|
else
|
||||||
|
local res=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$rec_id" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" --data "$json_data")
|
||||||
|
if [ "$(echo $res | jq -r .success)" == "true" ]; then
|
||||||
|
echo " ✅ Aktualisiert: '$rec_content' → '$content'"
|
||||||
|
else
|
||||||
|
echo " ❌ Fehler beim Updaten: $(echo $res | jq -r '.errors[0].message')"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Der eigentliche Record
|
||||||
|
# proxied=false ist hier wichtig: der mailadmin laeuft hinter Caddy
|
||||||
|
# mit eigenem TLS-Zertifikat. Cloudflare-Proxy davor wuerde die
|
||||||
|
# Zertifikatskette stoeren bzw. doppeltes TLS-Terminieren.
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
echo ""
|
||||||
|
echo "--- mailadmin CNAME ---"
|
||||||
|
ensure_record "CNAME" "$RECORD_NAME" "$MAILADMIN_TARGET" false
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "============================================================"
|
||||||
|
echo "✅ Fertig."
|
||||||
|
echo ""
|
||||||
|
echo " mailadmin erreichbar unter: https://$RECORD_NAME"
|
||||||
|
echo ""
|
||||||
|
echo " ⚠️ Wichtig: Caddy muss ein Zertifikat für $RECORD_NAME"
|
||||||
|
echo " ausstellen. Stelle sicher, dass der Hostname in der"
|
||||||
|
echo " Caddy-Konfiguration enthalten ist."
|
||||||
|
echo "============================================================"
|
||||||
@@ -13,6 +13,7 @@ services:
|
|||||||
- 'host.docker.internal:host-gateway'
|
- 'host.docker.internal:host-gateway'
|
||||||
networks:
|
networks:
|
||||||
- mail_network
|
- mail_network
|
||||||
|
- mailadmin_network
|
||||||
volumes:
|
volumes:
|
||||||
- $PWD/Caddyfile:/etc/caddy/Caddyfile
|
- $PWD/Caddyfile:/etc/caddy/Caddyfile
|
||||||
- $PWD/mail_certs:/etc/caddy/mail_certs
|
- $PWD/mail_certs:/etc/caddy/mail_certs
|
||||||
@@ -29,3 +30,5 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
mail_network:
|
mail_network:
|
||||||
external: true
|
external: true
|
||||||
|
mailadmin_network:
|
||||||
|
external: true
|
||||||
|
|||||||
@@ -261,6 +261,13 @@ for domain in $DOMAINS; do
|
|||||||
OUTPUT="${OUTPUT} }\n"
|
OUTPUT="${OUTPUT} }\n"
|
||||||
OUTPUT="${OUTPUT}}\n\n"
|
OUTPUT="${OUTPUT}}\n\n"
|
||||||
|
|
||||||
|
# Mailadmin Block
|
||||||
|
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"
|
||||||
|
|
||||||
# Autodiscover / Autoconfig Block
|
# Autodiscover / Autoconfig Block
|
||||||
OUTPUT="${OUTPUT}# Autodiscover/Autoconfig für $domain\n"
|
OUTPUT="${OUTPUT}# Autodiscover/Autoconfig für $domain\n"
|
||||||
OUTPUT="${OUTPUT}autodiscover.${domain}, autoconfig.${domain} {\n"
|
OUTPUT="${OUTPUT}autodiscover.${domain}, autoconfig.${domain} {\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user