Debian + Postfix + Dovecot + Multidomain + SSL + IPv6 + OpenVPN + Multi-interfaces + SpamAssassin-lernen + Bind

Dieser Artikel beschreibt, wie man einen modernen E-Mail-Server einrichtet.
Postfix + Dovecot. SPF + DKIM + rDNS. Mit IPv6.
Mit TSL-Verschlüsselung. Unterstützt mehrere Domains — Teil mit echtem SSL-Zertifikat.
Mit Anti-Spam-Schutz und hohem Anti-Spam-Ranking bei anderen E-Mail-Servern.
Mit Unterstützung für mehrere physische Schnittstellen.
Mit OpenVPN, das über IPv4 verbunden ist und IPv6 bereitstellt.

Wenn Sie diese Technologien nicht erlernen möchten, aber einen solchen Server einrichten wollen — dann ist dieser Artikel für Sie.

Der Artikel versucht nicht, jedes Detail zu erklären. Er konzentriert sich darauf, was nicht standardmäßig oder wichtig aus Verbrauchersicht eingerichtet ist.

Die Motivation, einen E-Mail-Server einzurichten, ist mein lang gehegter Traum. Das mag dumm klingen, aber meiner Meinung nach ist das viel besser, als von einem neuen Auto meiner Lieblingsmarke zu träumen.

Die Motivation, IPv6 einzurichten, sind zwei. Ein IT-Spezialist muss ständig neue Technologien erlernen, um zu überleben. Ich möchte meinen bescheidenen Beitrag zur Bekämpfung von Zensur leisten.

Die Motivation zur Einrichtung von OpenVPN — nur um sicherzustellen, dass IPv6 auf der lokalen Maschine funktioniert.
Die Motivation, mehrere physische Schnittstellen einzurichten, besteht darin, dass ich auf meinem Server eine Schnittstelle habe, die "langsam, aber unbegrenzt" ist, und eine andere, die "schnell, aber mit Tarif" ist.

Die Motivation für die Konfiguration von Bind ist, dass mein Anbieter einen instabilen DNS-Server bereitstellt und auch Google manchmal ausfällt. Ich möchte einen stabilen DNS-Server für die persönliche Nutzung.

Die Motivation, einen Artikel zu schreiben, liegt darin, dass der Entwurf bereits vor 10 Monaten erstellt wurde, und ich ihn seitdem zweimal aufgerufen habe. Wenn der Autor dies regelmäßig benötigt, ist die Wahrscheinlichkeit groß, dass auch andere es brauchen.

Es gibt keine universelle Lösung für den Mailserver. Ich werde jedoch versuchen, eine Anleitung zu schreiben, wie: "Machen Sie es so, und wenn alles funktioniert, wie es soll, entfernen Sie das Überflüssige."

Ich habe einen Colocation-Server bei der Firma tech.ru. Es ist sinnvoll, diesen mit OVH, Hetzner und AWS zu vergleichen. Für diese Aufgabe ist die Zusammenarbeit mit tech.ru deutlich effektiver.

Auf dem Server ist Debian 9 installiert.

Der Server verfügt über 2 Schnittstellen `eno1` und `eno2`. Die erste ist unbegrenzt, die zweite schnell.

Es sind 3 statische IP-Adressen vorhanden: XX.XX.XX.X0, XX.XX.XX.X1 und XX.XX.XX.X2 auf der Schnittstelle `eno1` sowie XX.XX.XX.X5 auf der Schnittstelle `eno2`.

Es besteht ein Pool von IPv6-Adressen XXXX:XXXX:XXXX:XXXX::/64, der auf das Interface `eno1` zugewiesen ist, und auf meine Anfrage wurde XXXX:XXXX:XXXX:XXXX:1:2::/96 auf `eno2` zugewiesen.

Es gibt 3 Domains: `domain1.com`, `domain2.com`, `domain3.com`. Für `domain1.com` und `domain3.com` sind SSL-Zertifikate vorhanden.

Es gibt ein Google-Konto, mit dem ich das Postfach `vasya.pupkin@domain1.com` verknüpfen möchte (E-Mail-Empfang und -Versand direkt aus der Gmail-Oberfläche).
Ein Postfach `support@domain2.com` muss eingerichtet werden, dessen E-Mails ich in Gmail sehen möchte. Außerdem sollte ich gelegentlich etwas im Web-Interface im Namen von `support@domain2.com` versenden können.

Es muss ein Postfach `ivanov@domain3.com` eingerichtet werden, das Ivanov von seinem iPhone aus benutzen wird.

Gesendete E-Mails müssen allen aktuellen Anforderungen an den Antispam entsprechen.
Es muss das höchste mögliche Niveau der Verschlüsselung in öffentlichen Netzwerken gewährleistet sein.
IPv6-Unterstützung sollte sowohl für den E-Mail-Versand als auch für den -Empfang vorhanden sein.
Es sollte SpamAssassin installiert sein, der niemals E-Mails löscht, sondern entweder zurücksendet, durchlässt oder in den IMAP-Ordner 'Spam' verschiebt.
Das Auto-Lernsystem von SpamAssassin muss eingerichtet werden: Wenn ich eine E-Mail in den Ordner „Spam“ verschiebe, sollte es daraus lernen; wenn ich eine E-Mail aus dem Ordner „Spam“ verschiebe, sollte es auch daraus lernen. Die Ergebnisse des Trainings von SpamAssassin sollten die Wahrscheinlichkeit beeinflussen, dass eine E-Mail im Spam-Ordner landet.
PHP-Skripte müssen in der Lage sein, E-Mails im Namen jeder Domain auf diesem Server zu senden.
Es muss einen OpenVPN-Dienst geben, der die Nutzung von IPv6 auf einem Client ermöglicht, der über kein IPv6 verfügt.

Zuerst müssen die Interfaces und die Routingkonfiguration, einschließlich IPv6, eingerichtet werden.
Anschließend muss OpenVPN konfiguriert werden, das sich über IPv4 verbindet und dem Client eine statische, echte IPv6-Adresse zuweist. Dieser Client hat Zugriff auf alle IPv6-Dienste auf dem Server und auf alle IPv6-Ressourcen im Internet.
Danach muss Postfix zum Versand von E-Mails sowie SPF, DKIM, rDNS und andere ähnliche Einstellungen konfiguriert werden.
Danach muss Dovecot konfiguriert werden, einschließlich Multidomain-Einrichtung.
Danach muss SpamAssassin konfiguriert und das Lernen eingerichtet werden.
Zum Abschluss muss Bind installiert werden.

============= Multi-Interfaces =============

Für die Konfiguration der Interfaces muss Folgendes in „/etc/network/interfaces“ eingegeben werden.

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eno1
iface eno1 inet static
        address XX.XX.XX.X0/24
        gateway XX.XX.XX.1
        dns-nameservers 127.0.0.1 213.248.1.6
        post-up ip route add XX.XX.XX.0/24 dev eno1 src XX.XX.XX.X0 table eno1t
        post-up ip route add default via XX.XX.XX.1 table eno1t
        post-up ip rule add table eno1t from XX.XX.XX.X0
        post-up ip rule add table eno1t to XX.XX.XX.X0

auto eno1:1
iface eno1:1 inet static
address XX.XX.XX.X1
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X1
        post-up ip rule add table eno1t to XX.XX.XX.X1
        post-up   ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t
        post-down ip route del 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t

auto eno1:2
iface eno1:2 inet static
address XX.XX.XX.X2
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X2
        post-up ip rule add table eno1t to XX.XX.XX.X2

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
        gateway XXXX:XXXX:XXXX:XXXX::1
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:2/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:1:1:2/64 dev $IFACE

# The secondary network interface
allow-hotplug eno2
iface eno2 inet static
        address XX.XX.XX.X5
        netmask 255.255.255.0
        post-up   ip route add XX.XX.XX.0/24 dev eno2 src XX.XX.XX.X5 table eno2t
        post-up   ip route add default via XX.XX.XX.1 table eno2t
        post-up   ip rule add table eno2t from XX.XX.XX.X5
        post-up   ip rule add table eno2t to XX.XX.XX.X5
        post-up   ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X5 table eno2t
        post-down ip route del 10.8.0.0/24 dev tun0 src XX.XX.XX.X5 table eno2t

iface eno2 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:2::/96
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:2:1:1/64 dev $IFACE
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:2:1:2/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:2:1:1/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:2:1:2/64 dev $IFACE

# OpenVPN network
iface tun0 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:3::/80

Diese Einstellungen können auf jedem Server bei tech.ru angewendet werden (nach kurzer Absprache mit dem Support) und sie funktionieren sofort wie gewünscht.

Wenn Sie Erfahrung mit ähnlichen Konfigurationen bei Hetzner oder OVH haben, wissen Sie, dass es dort anders und komplizierter ist.

eno1 ist der Name der Netzwerkkarte #1 (langsam, aber unbegrenzt).
eno2 ist der Name der Netzwerkkarte #2 (schnell, aber mit Tarif).
tun0 ist der Name der virtuellen Netzwerkkarte von OpenVPN.
XX.XX.XX.X0 ist die IPv4 #1 auf eno1.
XX.XX.XX.X1 ist die IPv4 #2 auf eno1.
XX.XX.XX.X2 ist die IPv4 #3 auf eno1.
XX.XX.XX.X5 ist die IPv4 #1 auf eno2.
XX.XX.XX.1 ist das IPv4-Gateway.
XXXX:XXXX:XXXX:XXXX::/64 ist die IPv6 für den gesamten Server.
XXXX:XXXX:XXXX:XXXX:1:2::/96 ist die IPv6 für eno2, alles andere kommt über eno1.
XXXX:XXXX:XXXX:XXXX::1 ist das IPv6-Gateway (es sei angemerkt, dass dies anders konfiguriert werden sollte. IPv6 des Switches angeben).
dns-nameservers sind auf 127.0.0.1 (da bind lokal installiert ist) und 213.248.1.6 (dies ist von tech.ru) angegeben.

Die "table eno1t" und "table eno2t" bedeuten, dass der Verkehr, der über eno1 hereinkommt, auch über diesen ausgehen soll, während der Verkehr, der über eno2 hereinkommt, ebenfalls über diesen ausgehen soll. Zudem sollen Server-initiierten Verbindungen über eno1 gehen.

ip route add default via XX.XX.XX.1 table eno1t

Mit diesem Befehl legen wir fest, dass jeglicher unbekannter Datenverkehr, der unter eine Regel fällt, die mit „table eno1t“ markiert ist, an das Interface eno1 weitergeleitet wird.

ip route add XX.XX.XX.0/24 dev eno1 src XX.XX.XX.X0 table eno1t

Mit diesem Befehl legen wir fest, dass jeglicher Datenverkehr, der vom Server initiiert wird, an das Interface eno1 weitergeleitet wird.

ip rule add table eno1t from XX.XX.XX.X0
ip rule add table eno1t to XX.XX.XX.X0

Mit diesem Befehl legen wir die Regeln zur Markierung des Datenverkehrs fest.

auto eno1:2
iface eno1:2 inet static
address XX.XX.XX.X2
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X2
        post-up ip rule add table eno1t to XX.XX.XX.X2

Dieser Block legt eine zweite IPv4-Adresse für das Interface eno1 fest.

ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t

Mit diesem Befehl legen wir die Route für OpenVPN-Clients zu lokalen IPv4-Adressen, außer XX.XX.XX.X0, fest.
Warum dieser Befehl für alle IPv4-Adressen ausreicht, verstehe ich immer noch nicht.

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
        gateway XXXX:XXXX:XXXX:XXXX::1

Hier legen wir die Adresse für das Interface selbst fest. Der Server wird sie als „ausgehende“ Adresse verwenden. Ansonsten wird sie nicht genutzt.

Warum ist „:1:1::“ so kompliziert angegeben? Damit OpenVPN korrekt funktioniert, und nur dafür. Mehr dazu später.

Zum Thema Gateway: So funktioniert es, das ist in Ordnung. Richtigerweise sollte jedoch die IPv6-Adresse des Switches angegeben werden, an den der Server angeschlossen ist.

Warum funktioniert IPv6 jedoch nicht, wenn ich das so mache? Wahrscheinlich sind das irgendwelche Probleme von tech.ru.

ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE

Dies fügt eine IPv6-Adresse zum Interface hinzu. Wenn Sie einhundert Adressen benötigen, sind das also einhundert Zeilen in dieser Datei.

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
...
iface eno2 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:2::/96
...
iface tun0 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:3::/80

Ich habe die Adressen und Subnetze aller Interfaces markiert, um es anschaulicher zu machen.
eno1 muss unbedingt „/64“ sein, denn das ist unser gesamter Adresspool.
tun0 muss unbedingt eine größere Subnetzmaske als eno1 haben. Andernfalls kann das IPv6-Gateway für OpenVPN-Kunden nicht eingerichtet werden.
eno2 muss unbedingt eine größere Subnetzmaske als tun0 haben. Andernfalls können OpenVPN-Kunden nicht auf lokale IPv6-Adressen zugreifen.
Zur Verdeutlichung habe ich einen Subnetzschritt von 16 gewählt, aber man kann sogar einen Schritt von „1“ machen, wenn man möchte.
Das heißt 64+16 = 80 und 80+16 = 96.

Zur weiteren Verdeutlichung:
XXXX:XXXX:XXXX:XXXX:1:1:YYYY:YYYY – das sind die Adressen, die bestimmten Websites oder Diensten auf dem Interface eno1 zugeordnet werden sollten.
XXXX:XXXX:XXXX:XXXX:1:2:YYYY:YYYY — dies sind Adressen, die bestimmten Webseiten oder Diensten auf der Schnittstelle eno2 zugewiesen werden müssen.
XXXX:XXXX:XXXX:XXXX:1:3:YYYY:YYYY — dies sind Adressen, die OpenVPN-Kunden zugewiesen werden sollen oder als Dienstadressen von OpenVPN verwendet werden.

Für die Netzwerkkonfiguration muss die Möglichkeit bestehen, den Server neu zu starten.
IPv4-Änderungen werden bei Ausführung erfasst (unbedingt in einem Screen ausführen — andernfalls wird dieser Befehl die Netzwerkverbindung auf dem Server unterbrechen):

/etc/init.d/networking restart

Am Ende der Datei "/etc/iproute2/rt_tables" hinzufügen:

100 eno1t
101 eno2t

Ohne dies können benutzerdefinierte Tabellen in der Datei "/etc/network/interfaces" nicht verwendet werden.
Die Zahlen müssen einzigartig und kleiner als 65535 sein.

IPv6-Änderungen können ohne Neustart leicht vorgenommen werden, aber dafür müssen mindestens drei Befehle beherrscht werden:

ip -6 addr ...
ip -6 route ...
ip -6 neigh ...

Konfiguration von "/etc/sysctl.conf"

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward = 1

# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0

# For receiving ARP replies
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.default.arp_filter = 0

# For sending ARP
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.default.arp_announce = 0

# Enable IPv6
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

# IPv6 configuration
net.ipv6.conf.all.autoconf = 1
net.ipv6.conf.all.accept_ra = 0

# For OpenVPN
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.proxy_ndp = 1

# For nginx on boot
net.ipv6.ip_nonlocal_bind = 1

Dies sind die «sysctl»-Einstellungen meines Servers. Ich werde die wichtigen Punkte hervorheben.

net.ipv4.ip_forward = 1

Ohne dies wird OpenVPN überhaupt nicht funktionieren.

net.ipv6.ip_nonlocal_bind = 1

Jeder, der versucht, eine IPv6-Bindung (zum Beispiel nginx) sofort nach der Aktivierung der Schnittstelle vorzunehmen, erhält einen Fehler, wonach diese Adresse nicht verfügbar ist.

Um diese Situation zu vermeiden, wird diese Einstellung vorgenommen.

net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.proxy_ndp = 1

Ohne diese Einstellungen gelangt der IPv6-Verkehr des OpenVPN-Clients nicht ins Internet.

Andere Einstellungen sind entweder irrelevant oder ich erinnere mich nicht, wozu sie dienen.
Aber zur Sicherheit lasse ich es «wie es ist».

Um die Änderungen dieser Datei ohne Neustart des Servers zu übernehmen, muss der Befehl ausgeführt werden:

sysctl -p

Detaillierte Informationen zu „table“-Regeln: habr.com/post/108690

============= OpenVPN =============

OpenVPN IPv4 funktioniert nicht ohne iptables.

Mein iptables ist wie folgt für das VPN konfiguriert:

iptables -A INPUT -p udp -s YY.YY.YY.YY --dport 1194 -j ACCEPT
iptables -A FORWARD -i tun0 -o eno1 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j SNAT --to-source XX.XX.XX.X0
##iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j MASQUERADE
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -j DROP
iptables -A FORWARD -p udp --dport 1194 -j DROP

YY.YY.YY.YY — das ist meine statische IPv4-Adresse des lokalen Rechners.
10.8.0.0/24 — das IPv4-Netzwerk von OpenVPN, die IPv4-Adressen für OpenVPN-Clients.
Die Reihenfolge der Regeln ist wichtig.

iptables -A INPUT -p udp -s YY.YY.YY.YY --dport 1194 -j ACCEPT
iptables -A FORWARD -i tun0 -o eno1 -j ACCEPT
...
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -j DROP
iptables -A FORWARD -p udp --dport 1194 -j DROP

Diese Einschränkung sorgt dafür, dass nur ich von meiner statischen IP-Adresse OpenVPN nutzen kann.

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j SNAT --to-source XX.XX.XX.X0
  -- oder --
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j MASQUERADE

Um IPv4-Pakete zwischen OpenVPN-Clienten und dem Internet weiterzuleiten, muss eines dieser Kommandos eingegeben werden.

Für unterschiedliche Szenarien eignet sich nicht jede Option.
In meinem Fall sind beide Befehle geeignet.
Nach Durchsicht der Dokumentation habe ich die erste Option gewählt, da sie weniger CPU-Ressourcen verbraucht.

Damit alle iptables-Einstellungen nach einem Neustart übernommen werden, müssen sie irgendwo gespeichert werden.

iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

Diese Namen sind nicht zufällig gewählt. Sie werden vom Paket „iptables-persistent“ verwendet.

apt-get install iptables-persistent

Installation des Hauptpakets OpenVPN:

apt-get install openvpn easy-rsa

Legen wir eine Vorlage für die Zertifikate fest (ersetzen Sie die Werte durch Ihre):

make-cadir ~/openvpn-ca
cd ~/openvpn-ca
ln -s openssl-1.0.0.cnf openssl.cnf

Lassen Sie uns die Einstellungen der Zertifikatvorlage bearbeiten:

mcedit vars

...
# Dies sind die Standardwerte für Felder
# die im Zertifikat erscheinen.
# Lassen Sie keines dieser Felder leer.
export KEY_COUNTRY="DE"
export KEY_PROVINCE="Baden-Württemberg"
export KEY_CITY="Stuttgart"
export KEY_ORG="Eigene"
export KEY_EMAIL="admin@domain1.com"
export KEY_OU="VPN"

# X509 Subject Field
export KEY_NAME="server"
...

Erstellen wir ein Serverzertifikat:

cd ~/openvpn-ca
source vars
./clean-all
./build-ca
./build-key-server server
./build-dh
openvpn --genkey --secret keys/ta.key

Wir bereiten die Erstellung der endgültigen „client-name.opvn“-Dateien vor:

mkdir -p ~/client-configs/files
chmod 700 ~/client-configs/files
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
mcedit ~/client-configs/base.conf

# Client mode
client

# Interface tunnel type
dev tun

# TCP protocol
proto tcp-client

# Address/Port of VPN server
remote XX.XX.XX.X0 1194

# Don't bind to local port/address
nobind

# Don't need to re-read keys and re-create tun at restart
persist-key
persist-tun

# Remote peer must have a signed certificate
remote-cert-tls server
ns-cert-type server

# Enable compression
comp-lzo

# Custom
ns-cert-type server
tls-auth ta.key 1
cipher DES-EDE3-CBC

Wir bereiten ein Skript vor, das alle Dateien zu einer einzigen opvn-Datei zusammenfügt.

mcedit ~/client-configs/make_config.sh
chmod 700 ~/client-configs/make_config.sh

#!/bin/bash

# First argument: Client identifier

KEY_DIR=~/openvpn-ca/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf

cat ${BASE_CONFIG} 
    <(echo -e '<ca>') 
    ${KEY_DIR}/ca.crt 
    <(echo -e '</ca>n<cert>') 
    ${KEY_DIR}/${1}.crt 
    <(echo -e '</cert>n<key>') 
    ${KEY_DIR}/${1}.key 
    <(echo -e '</key>n<tls-auth>') 
    ${KEY_DIR}/ta.key 
    <(echo -e '</tls-auth>') 
    > ${OUTPUT_DIR}/${1}.ovpn

Wir erstellen den ersten OpenVPN-Client:

cd ~/openvpn-ca
source vars
./build-key client-name
cd ~/client-configs
./make_config.sh client-name

Die Datei „~/client-configs/files/client-name.ovpn“ senden wir an das Gerät des Clients.

Für iOS-Clients müssen wir einen Trick machen:
Der Inhalt des Tags „tls-auth“ sollte ohne Kommentare sein.
Außerdem muss „key-direction 1“ direkt vor dem Tag „tls-auth“ gesetzt werden.

Wir konfigurieren die OpenVPN-Servereinstellungen:

cd ~/openvpn-ca/keys
cp ca.crt ca.key server.crt server.key ta.key dh2048.pem /etc/openvpn
gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | tee /etc/openvpn/server.conf
mcedit /etc/openvpn/server.conf

# Listen port
port 1194

# Protocol
proto tcp-server

# IP tunnel
dev tun0
tun-ipv6
push tun-ipv6

# Master certificate
ca ca.crt

# Server certificate
cert server.crt

# Server private key
key server.key

# Diffie-Hellman parameters
dh dh2048.pem

# Allow clients to communicate with each other
client-to-client

# Client config dir
client-config-dir /etc/openvpn/ccd

# Run client-specific script on connection and disconnection
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/server-clientconnect.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/server-clientdisconnect.sh"

# Server mode and client subnets
server 10.8.0.0 255.255.255.0
server-ipv6 XXXX:XXXX:XXXX:XXXX:1:3::/80
topology subnet

# IPv6 routes
push "route-ipv6 XXXX:XXXX:XXXX:XXXX::/64"
push "route-ipv6 2000::/3"

# DNS (for Windows)
# These are OpenDNS
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

# Configure all clients to redirect their default network gateway through the VPN
push "redirect-gateway def1 bypass-dhcp"
push "redirect-gateway ipv6" #For iOS

# Don't need to re-read keys and re-create tun at restart
persist-key
persist-tun

# Ping every 10s. Timeout of 120s.
keepalive 10 120

# Enable compression
comp-lzo

# User and group
user vpn
group vpn

# Log a short status
status openvpn-status.log

# Logging verbosity
##verb 4

# Custom config
tls-auth ta.key 0
cipher DES-EDE3-CBC

Dies ist notwendig, um jedem Client eine statische Adresse zuzuweisen (nicht unbedingt erforderlich, aber ich benutze es):

# Client config dir
client-config-dir /etc/openvpn/ccd

Das ist das schwierigste und entscheidende Detail.

Leider kann OpenVPN noch nicht automatisch das IPv6-Gateway für Clients konfigurieren.
Es ist notwendig, dies „manuell“ für jeden Client weiterzuleiten.

# Run client-specific script on connection and disconnection
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/server-clientconnect.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/server-clientdisconnect.sh"

Die Datei „/etc/openvpn/server-clientconnect.sh“:

#!/bin/sh

# Check client variables
if [ -z "$ifconfig_pool_remote_ip" ] || [ -z "$common_name" ]; then
        echo "Missing environment variable."
        exit 1
fi

# Load server variables
. /etc/openvpn/variables

ipv6=""

# Find out if there is a specific config with fixed IPv6 for this client
if [ -f "/etc/openvpn/ccd/$common_name" ]; then
        # Get fixed IPv6 from client config file
        ipv6=$(sed -nr 's/^.*ifconfig-ipv6-push[ t]+([0-9a-fA-F:]+).*$/1/p' "/etc/openvpn/ccd/$common_name")
        echo $ipv6
fi

# Get IPv6 from IPv4
if [ -z "$ipv6" ]; then
        ipp=$(echo "$ifconfig_pool_remote_ip" | cut -d. -f4)
        if ! [ "$ipp" -ge 2 -a "$ipp" -le 254 ] 2>/dev/null; then
                echo "Invalid IPv4 part."
                exit 1
        fi
        hexipp=$(printf '%x' $ipp)
        ipv6="$prefix$hexipp"
fi

# Create proxy rule
/sbin/ip -6 neigh add proxy $ipv6 dev eno1

Die Datei „/etc/openvpn/server-clientdisconnect.sh“:

#!/bin/sh

# Check client variables
if [ -z "$ifconfig_pool_remote_ip" ] || [ -z "$common_name" ]; then
        echo "Missing environment variable."
        exit 1
fi

# Load server variables
. /etc/openvpn/variables

ipv6=""

# Find out if there is a specific config with fixed IPv6 for this client
if [ -f "/etc/openvpn/ccd/$common_name" ]; then
        # Get fixed IPv6 from client config file
        ipv6=$(sed -nr 's/^.*ifconfig-ipv6-push[ t]+([0-9a-fA-F:]+).*$/1/p' "/etc/openvpn/ccd/$common_name")
fi

# Get IPv6 from IPv4
if [ -z "$ipv6" ]; then
        ipp=$(echo "$ifconfig_pool_remote_ip" | cut -d. -f4)
        if ! [ "$ipp" -ge 2 -a "$ipp" -le 254 ] 2>/dev/null; then
                echo "Invalid IPv4 part."
                exit 1
        fi
        hexipp=$(printf '%x' $ipp)
        ipv6="$prefix$hexipp"
fi

# Delete proxy rule
/sbin/ip -6 neigh del proxy $ipv6 dev eno1

Beide Skripte verwenden die Datei «/etc/openvpn/variables»:

# Subnet
prefix=XXXX:XXXX:XXXX:XXXX:2:
# netmask
prefixlen=112

Warum das hier so geschrieben steht, kann ich mich nicht erinnern.

Aktuell sieht es seltsam aus, netmask = 112 (hier sollte 96 sein).
Und das Prefix ist seltsam, entspricht nicht dem Netzwerk tun0.
Aber gut, ich lasse es «wie es ist».

cipher DES-EDE3-CBC

Das ist Geschmackssache – ich habe diese Verschlüsselungsmethode für die Verbindung ausgewählt.

Mehr Details zur Konfiguration von OpenVPN IPv4.

Mehr Details zur Konfiguration von OpenVPN IPv6.

============= Postfix =============

Installation des Hauptpakets:

apt-get install postfix

Bei der Installation «internet-site» auswählen.

Meine «/etc/postfix/main.cf» sieht so aus:

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = nein

# Das Anhängen von .domain liegt in der Verantwortung des MUA.
append_dot_mydomain = nein

readme_directory = nein

# Weitere Informationen unter http://www.postfix.org/COMPATIBILITY_README.html -- standardmäßig 2 bei
# frischen Installationen.
compatibility_level = 2

# TLS-Parameter
smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key
smtpd_use_tls=ja
smtpd_tls_auth_only = ja
smtp_bind_address = XX.XX.XX.X0
smtp_bind_address6 = XXXX:XXXX:XXXX:XXXX:1:1:1:1

smtp_tls_security_level = kann
smtp_tls_ciphers = export
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_loglevel = 1

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = domain1.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = domain1.com
mydestination = localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4

internal_mail_filter_classes = bounce

# Speichertyp
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf

# SMTP-Auth-Einstellungen
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = ja
smtpd_recipient_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        #reject_invalid_hostname,
        #reject_unknown_recipient_domain,
        reject_unauth_destination,
        reject_rbl_client sbl.spamhaus.org,
        check_policy_service unix:private/policyd-spf

smtpd_helo_restrictions =
        #reject_invalid_helo_hostname,
        #reject_non_fqdn_helo_hostname,
        reject_unknown_helo_hostname

smtpd_client_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_non_fqdn_helo_hostname,
        permit

# SPF
policyd-spf_time_limit = 3600

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:var/run/opendkim/opendkim.sock

# IP-Adresse pro Domain
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Lassen Sie uns die Details dieser Konfiguration ansehen.

smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key

Laut den Nutzern von Habr enthält dieser Block `Fehlinformationen und falsche Thesen`.Erst acht Jahre nach Beginn meiner Karriere verstand ich, wie SSL funktioniert.

Deshalb werde ich es mir erlauben, zu beschreiben, wie man SSL nutzt (ohne Fragen wie „Wie funktioniert das?“ und „Warum funktioniert das?“ zu beantworten).

Die Grundlage der modernen Verschlüsselung ist die Erstellung eines Schlüsselpaares (zwei sehr lange Zeichenfolgen).

Ein „Schlüssel“ ist privat, der andere Schlüssel ist „öffentlich“. Den privaten Schlüssel bewahren wir sorgfältig geheim. Den öffentlichen Schlüssel verteilen wir an alle Interessierten.

Mit dem öffentlichen Schlüssel kann eine Textzeile so verschlüsselt werden, dass nur der Besitzer des privaten Schlüssels sie entschlüsseln kann.
Das ist die gesamte Grundlage der Technologie.

Schritt Nr. 1 – HTTPS-Websites.
Beim Zugriff auf die Website erfährt der Browser vom Webserver, dass die Website HTTPS ist, und fordert daher den öffentlichen Schlüssel an.
Der Webserver liefert den öffentlichen Schlüssel. Der Browser verschlüsselt die HTTP-Anfrage mit dem öffentlichen Schlüssel und sendet sie ab.
Der HTTP-Request kann nur von jemandem gelesen werden, der den privaten Schlüssel hat, also nur vom Server, an den die Anfrage gesendet wird.
Ein HTTP-Request enthält mindestens eine URI. Wenn in einem Land der Zugriff nicht auf die gesamte Website, sondern auf eine bestimmte Seite eingeschränkt wird, ist dies bei HTTPS-Seiten nicht möglich.

Schritt Nr. 2 – die verschlüsselte Antwort.
Der Webserver gibt eine Antwort, die leicht auf dem Weg gelesen werden kann.
Die Lösung ist äußerst einfach – der Browser erzeugt lokal ein entsprechendes Paar aus privatem und öffentlichem Schlüssel für jede HTTPS-Website.
Zusammen mit der Anfrage nach dem öffentlichen Schlüssel der Website sendet er seinen lokalen öffentlichen Schlüssel.
Der Webserver speichert ihn und verschlüsselt bei der Übertragung der HTTP-Antwort mit diesem öffentlichen Schlüssel des spezifischen Clients.
Jetzt kann die HTTP-Antwort nur vom Inhaber des privaten Schlüssels des Client-Browsers entschlüsselt werden (also vom Client selbst).

Schritt Nr. 3 – die Einrichtung einer sicheren Verbindung über einen öffentlichen Kanal.
Im Beispiel Nr. 2 gibt es eine Schwachstelle – nichts hindert Dritte daran, den HTTP-Request abzufangen und die Informationen über den öffentlichen Schlüssel zu bearbeiten.
Auf diese Weise kann der Vermittler alle Inhalte der gesendeten und empfangenen Nachrichten einsehen, bis sich der Kommunikationskanal ändert.
Dagegen vorzugehen ist ganz einfach – es genügt, den öffentlichen Schlüssel des Browsers als Nachricht, die mit dem öffentlichen Schlüssel des Webservers verschlüsselt ist, zu senden.
Der Webserver sendet dann zunächst eine Antwort, die lautet: „Dein öffentlicher Schlüssel ist folgender“ und verschlüsselt diese Nachricht mit demselben öffentlichen Schlüssel.
Der Browser überprüft die Antwort – wenn die Nachricht „Dein öffentlicher Schlüssel ist folgender“ eingetroffen ist, dann ist dies eine 100%ige Garantie, dass dieser Kommunikationskanal sicher ist.
Wie sicher ist er?
Die Einrichtung eines solchen sicheren Kommunikationskanals erfolgt mit einer Geschwindigkeit von ping*2. Beispielsweise 20 ms.
Ein Angreifer muss entweder im Voraus den privaten Schlüssel einer der Parteien besitzen oder den privaten Schlüssel innerhalb weniger Millisekunden knacken.
Das Knacken eines modernen privaten Schlüssels würde Jahrzehnte auf einem Supercomputer in Anspruch nehmen.

Schritt Nr. 4 – öffentliche Datenbank der öffentlichen Schlüssel.
Offensichtlich gibt es in dieser Geschichte die Möglichkeit für einen Angreifer, der sich im Kommunikationskanal zwischen dem Client und dem Server befindet.
Die Möglichkeit für den Kunden, sich als Server darzustellen, und für den Server, sich als Kunde auszugeben. So kann ein Schlüsselpaar in beide Richtungen emuliert werden.
Dann wird der Angreifer den gesamten Traffic sehen und hat die Möglichkeit, den Traffic zu 'modifizieren'.
Beispielsweise kann er die Adresse ändern, an die Geld gesendet wird, ein Passwort für das Online-Banking kopieren oder 'unerwünschte' Inhalte blockieren.
Um solchen Angreifern entgegenzuwirken, wurde eine öffentliche Datenbank mit öffentlichen Schlüsseln für jede HTTPS-Website erfunden.
Jeder Browser 'weiß' über das Vorhandensein von etwa 200 solchen Datenbanken Bescheid. Das ist in jeden Browser integriert.
Dieses 'Wissen' wird durch den öffentlichen Schlüssel jedes Zertifikats untermauert. Das bedeutet, dass eine Verbindung zu jedem bestimmten Zertifizierungszentrum nicht gefälscht werden kann.

Jetzt gibt es ein einfaches Verständnis dafür, wie man SSL für HTTPS verwendet.
Wenn man ein wenig nachdenkt, wird klar, wie Geheimdienste in diesem System etwas hacken könnten. Aber das würde enormen Aufwand kosten.
Für Organisationen wie das NSA oder das CIA ist es praktisch unmöglich, das bestehende Schutzniveau selbst für VIPs zu hacken.

Ich möchte noch etwas zu SSH-Verbindungen hinzufügen. Es gibt keine öffentlichen Schlüssel; was sollen wir tun? Es gibt zwei Lösungsmöglichkeiten.
Option SSH mit Passwort:
Bei der ersten Verbindung sollte der SSH-Client warnen, dass wir hier einen neuen öffentlichen Schlüssel vom SSH-Server haben.
Wenn bei weiteren Verbindungen die Warnung „neuer öffentlicher Schlüssel vom SSH-Server“ erscheint, bedeutet das, dass man versucht, Ihre Kommunikation abzuhören.
Oder bei der ersten Verbindung wurde Ihre Kommunikation abgehört, und jetzt kommunizieren Sie ohne Zwischenhändler mit dem Server.
Eigens, weil das Abhören schnell und einfach entdeckt werden kann, wird dieser Angriff nur in besonderen Fällen gegen bestimmte Kunden eingesetzt.

Option SSH mit Schlüssel:
Nehmen Sie einen USB-Stick, speichern Sie den privaten Schlüssel für den SSH-Server darauf (es gibt dafür Begriffe und viele wesentliche Nuancen, aber ich schreibe hier eine Einführung, keine Anleitung zur Anwendung).
Der öffentliche Schlüssel bleibt auf dem Gerät, wo der SSH-Client betrieben wird, und sollte ebenfalls geheim gehalten werden.
Bringen Sie den USB-Stick zum Server, stecken Sie ihn ein, kopieren Sie den privaten Schlüssel, und verbrennen Sie den USB-Stick oder formatieren Sie ihn mit Nullen.
Das ist alles – nach einem solchen Vorgang wird es unmöglich sein, eine derartige SSH-Verbindung zu knacken. Natürlich kann in 10 Jahren auf einem Supercomputer der Traffic eingesehen werden – aber das ist eine andere Geschichte.

Entschuldigen Sie bitte den Off-Topic-Beitrag.

Nun, da die Theorie bekannt ist, möchte ich den Ablauf der Erstellung eines SSL-Zertifikats erläutern.

Mit «openssl genrsa» erstellen wir einen privaten Schlüssel und «Vorlagen» für den öffentlichen Schlüssel.
Die «Vorlagen» senden wir an ein externes Unternehmen, dem wir etwa 9 € für das einfachste Zertifikat zahlen.

Nach ein paar Stunden erhalten wir von diesem externen Unternehmen unseren «öffentlichen» Schlüssel sowie einen Satz weiterer öffentlicher Schlüssel.

Warum wir einem externen Unternehmen für die Erstellung meines öffentlichen Schlüssels bezahlen, ist eine separate Frage, die wir hier nicht betrachten werden.

Jetzt ist der Sinn der Aufschrift klar:

smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key

Im Ordner «/etc/ssl» befinden sich alle Dateien für SSL-Angelegenheiten.
domain1.com – der Name der Domain.
2018 – das Jahr der Schlüsselcreation.
«key» – zeigt an, dass es sich um eine private Schlüsseldatei handelt.

Und der Sinn dieser Datei ist:

smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
domain1.com – der Name der Domain.
2018 – das Jahr der Schlüsselcreation.
chained — bezeichnet eine Kette von öffentlichen Schlüsseln (der erste — unser öffentlicher Schlüssel und die weiteren — die von der Firma, die den öffentlichen Schlüssel ausgestellt hat).
crt — bezeichnet, dass es sich hierbei um ein fertiges Zertifikat handelt (öffentlicher Schlüssel mit technischen Erläuterungen).

smtp_bind_address = XX.XX.XX.X0
smtp_bind_address6 = XXXX:XXXX:XXXX:XXXX:1:1:1:1

Diese Einstellung wird in diesem Fall nicht verwendet, ist aber als Beispiel genannt.

Ein Fehler in diesem Parameter kann dazu führen, dass Ihr Server Spam versendet (ohne Ihr Wissen).

Danach müssen Sie allen beweisen, dass Sie nicht schuld sind.

recipient_delimiter = +

Vielleicht wissen das viele nicht; dies ist ein Standardzeichen zur Kategorisierung von E-Mails, das von den meisten modernen Mailservern unterstützt wird.

Wenn Sie beispielsweise ein Postfach „username@gmail.com“ haben, versuchen Sie es mit „username+spam@gmail.com“ – sehen Sie, was dabei herauskommt.

inet_protocols = ipv4

Das könnte verwirrend sein.

Das ist jedoch nicht ohne Grund. Jede neue Domain unterstützt standardmäßig nur IPv4, dann aktiviere ich IPv6 für jede einzeln.

virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf

Hier legen wir fest, dass alle eingehenden E-Mails an Dovecot weitergeleitet werden.
Die Regeln für Domain, Mailbox und Alias – diese finden Sie in der Datenbank.

/etc/postfix/mysql-virtual-mailbox-domains.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_domains WHERE name='%s'

/etc/postfix/mysql-virtual-mailbox-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_users WHERE email='%s'

/etc/postfix/mysql-virtual-alias-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

# SMTP-Auth settings
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

Nun weiß Postfix, dass E-Mails für die weitere Zustellung nur mit einer Authentifizierung über Dovecot akzeptiert werden können.

Ich verstehe wirklich nicht, warum das hier doppelt angegeben wird. Wir haben doch bereits in „virtual_transport“ alles Wichtige festgelegt.

Aber das Postfix-System ist sehr alt – vermutlich sind das Überbleibsel aus der Vergangenheit.

smtpd_recipient_restrictions =
        ...

smtpd_helo_restrictions =
        ...

smtpd_client_restrictions =
        ...

Das muss für jeden Mailserver individuell konfiguriert werden.

Ich habe drei Mailserver zur Verfügung, und diese Einstellungen sind aufgrund unterschiedlicher Nutzungsvoraussetzungen sehr unterschiedlich.

Die Konfiguration muss sorgfältig erfolgen – andernfalls kann Spam bei Ihnen eintreffen oder, noch schlimmer, Spam könnte von Ihnen ausgehen.

# SPF
policyd-spf_time_limit = 3600

Konfiguration für ein Plugin zur Überprüfung von SPF für eingehende E-Mails.

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:var/run/opendkim/opendkim.sock

Einstellung, dass alle ausgehenden E-Mails mit einer DKIM-Signatur versehen werden müssen.

# IP address per domain
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Dies ist ein zentrales Element bei der Routing von E-Mails, wenn E-Mails von PHP-Skripten gesendet werden.

Die Datei "/etc/postfix/sdd_transport.pcre":

/^www-domain1@domain1.com$/ domain1:
/^www-domain2@domain1.com$/ domain2:
/^www-domain3@domain1.com$/ domain3:
/@domain1.com$/             domain1:
/@domain2.com$/             domain2:
/@domain3.com$/             domain3:

Links stehen die regulären Ausdrücke. Rechts ist das Label, mit dem die E-Mail gekennzeichnet wird.
Postfix berücksichtigt in Übereinstimmung mit dem Label noch einige Konfigurationszeilen für die spezifische E-Mail.

Wie Postfix für eine bestimmte E-Mail neu konfiguriert wird, wird in «master.cf» angegeben.

Die Zeilen 4, 5, 6 – sie sind entscheidend. In welchem Namen wir die E-Mail senden, setzen wir als dieses Label.
Aber nicht immer wird im PHP-Skript im alten Code das Feld «from» angegeben. Dann kommt der Benutzername ins Spiel.

Der Artikel ist bereits umfangreich genug – ich möchte nicht von der Konfiguration von nginx+fpm ablenken.

Kurz gesagt – wir setzen für jede Website einen eigenen Linux-Benutzer als Eigentümer fest. Und entsprechend auch einen eigenen fpm-Pool.

Der fpm-Pool kann jede PHP-Version verwenden (das ist großartig, da man auf einem Server ohne Probleme unterschiedliche PHP-Versionen und sogar unterschiedliche php.ini für benachbarte Websites verwenden kann).

Also hat der spezifische Linux-Benutzer «www-domain2» die Website domain2.com. Auf dieser Website gibt es Code zum Versenden von E-Mails ohne Angabe des Feldes «from».

Selbst in diesem Fall werden die E-Mails korrekt gesendet und landen niemals im Spam.

Meine "/etc/postfix/master.cf" sieht so aus:

...
smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin
...
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
...
policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

spamassassin unix -     n       n       -       -       pipe
    user=spamd argv=/usr/bin/spamc -f -e
    /usr/sbin/sendmail -oi -f ${sender} ${recipient}
...
domain1  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X1
   -o smtp_helo_name=domain1.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:1:1
   -o syslog_name=postfix-domain1

domain2  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X5
   -o smtp_helo_name=domain2.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:2:1:1
   -o syslog_name=postfix-domain2

domain3  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X2
   -o smtp_helo_name=domain3
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:5:1
   -o syslog_name=postfix-domain3

Die Datei ist nicht vollständig – sie ist ohnehin schon sehr groß.
Habe nur die Änderungen markiert.

smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin
...
spamassassin unix -     n       n       -       -       pipe
    user=spamd argv=/usr/bin/spamc -f -e
    /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Dies sind Einstellungen, die mit spamassassin zusammenhängen, dazu später mehr.

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

Wir erlauben den Zugriff auf den Mailserver über Port 587.
Dafür ist eine Authentifizierung erforderlich.

policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Wir aktivieren die SPF-Prüfung.

apt-get install postfix-policyd-spf-python

Wir installieren das Paket für die SPF-Prüfungen oben.

domain1  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X1
   -o smtp_helo_name=domain1.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:1:1
   -o syslog_name=postfix-domain1

Und das ist das Interessanteste. Diese Möglichkeit, E-Mails für eine bestimmte Domain von einer bestimmten IPv4/IPv6-Adresse zu senden.

Das geschieht wegen rDNS. rDNS ist die Zuordnung eines Strings zu einer IP-Adresse.
Und für E-Mails wird diese Möglichkeit verwendet, um zu bestätigen, dass der helo genau dem rDNS der Adresse entspricht, von der die E-Mail gesendet wurde.

Wenn der helo nicht mit der E-Mail-Domain übereinstimmt, in deren Namen die E-Mail gesendet wurde, werden Spam-Punkte vergeben.

Helo stimmt nicht mit dem rDNS überein – es gibt viele Spam-Punkte.
Daher benötigt jede Domain ihre eigene IP-Adresse.
Für OVH gibt es in der Konsole die Möglichkeit, rDNS anzugeben.
Für tech.ru wird das Problem über den Support gelöst.
Für AWS wird das Problem über den Support gelöst.
„inet_protocols“ und „smtp_bind_address6“ aktivieren die Unterstützung von IPv6.
Für IPv6 muss ebenfalls rDNS konfiguriert werden.
„syslog_name“ dient der besseren Lesbarkeit der Logs.

Zertifikate kaufen empfehle ich hier.

Konfiguration von postfix+dovecot hier.

Einrichtung von SPF.

============= Dovecot =============

apt-get install dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql dovecot-antispam

Konfiguration von MySQL, wir installieren die Pakete selbst.

Datei „/etc/dovecot/conf.d/10-auth.conf“

disable_plaintext_auth = yes
auth_mechanisms = plain login

Authentifizierung nur in verschlüsselter Form.

Datei „/etc/dovecot/conf.d/10-mail.conf“

mail_location = maildir:/var/mail/vhosts/%d/%n

Hier geben wir den Speicherort für die E-Mails an.

Ich möchte, dass sie in Dateien gespeichert werden und nach Domains gruppiert sind.

Datei „/etc/dovecot/conf.d/10-master.conf“

service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    address = XX.XX.XX.X1, XX.XX.XX.X2, XX.XX.XX.X5, [XXXX:XXXX:XXXX:XXXX:1:1:1:1], [XXXX:XXXX:XXXX:XXXX:1:2:1:1], [XXXX:XXXX:XXXX:XXXX:1:1:5:1]
    port = 993
    ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 0
  }
  inet_listener pop3s {
    address = XX.XX.XX.X1, XX.XX.XX.X2, XX.XX.XX.X5, [XXXX:XXXX:XXXX:XXXX:1:1:1:1], [XXXX:XXXX:XXXX:XXXX:1:2:1:1], [XXXX:XXXX:XXXX:XXXX:1:1:5:1]
    port = 995
    ssl = yes
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}
service imap {
}
service pop3 {
}
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
  }

  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
  user = dovecot
}
service auth-worker {
  user = vmail
}
service dict {
  unix_listener dict {
  }
}

Dies ist die Hauptkonfigurationsdatei von Dovecot.
Hier deaktivieren wir ungesicherte Verbindungen.
Und aktivieren gesicherte Verbindungen.

Datei „/etc/dovecot/conf.d/10-ssl.conf“

ssl = required
ssl_cert = </etc/nginx/ssl/domain1.com.2018.chained.crt
ssl_key = </etc/nginx/ssl/domain1.com.2018.key
local XX.XX.XX.X5 {
  ssl_cert = </etc/nginx/ssl/domain2.com.2018.chained.crt
  ssl_key =  </etc/nginx/ssl/domain2.com.2018.key
}

SSL wird konfiguriert. Wir legen fest, dass SSL erforderlich ist.
Und das Zertifikat selbst. Ein wichtiger Punkt ist die Direktive „local“. Sie gibt an, welches SSL-Zertifikat bei der Verbindung zu welcher lokalen IPv4 verwendet werden soll.

Übrigens ist IPv6 hier nicht konfiguriert. Ich werde dieses Versäumnis irgendwann später beheben.
XX.XX.XX.X5 (domain2) — kein Zertifikat vorhanden. Für die Verbindung der Clients muss domain1.com angegeben werden.
XX.XX.XX.X2 (domain3) — Zertifikat vorhanden, für die Verbindung der Clients können domain1.com oder domain3.com verwendet werden.

Datei «/etc/dovecot/conf.d/15-lda.conf»

protocol lda {
  mail_plugins = $mail_plugins sieve
}

Das wird später für SpamAssassin benötigt.

Datei «/etc/dovecot/conf.d/20-imap.conf»

protocol imap {
  mail_plugins = $mail_plugins antispam
}

Das ist das Antispam-Plugin. Es wird benötigt, um SpamAssassin beim Verschieben in / aus dem Ordner «Spam» zu trainieren.

Datei «/etc/dovecot/conf.d/20-pop3.conf»

protocol pop3 {
}

Einfach, eine solche Datei existiert.

Datei «/etc/dovecot/conf.d/20-lmtp.conf»

protocol lmtp {
  mail_plugins = $mail_plugins sieve
  postmaster_address = admin@domain1.com
}

LMTP-Konfiguration.

Datei «/etc/dovecot/conf.d/90-antispam.conf»

plugin {
  antispam_backend = pipe
  antispam_trash = Trash;trash
  antispam_spam = Junk;Spam;SPAM
  antispam_pipe_program_spam_arg = --spam
  antispam_pipe_program_notspam_arg = --ham
  antispam_pipe_program = /usr/bin/sa-learn
  antispam_pipe_program_args = --username=%Lu
}

Einstellungen für das Training von SpamAssassin beim Verschieben in / aus dem Ordner «Spam».

Datei «/etc/dovecot/conf.d/90-sieve.conf»

plugin {
  sieve = ~/dovecot.sieve
  sieve_dir = ~/sieve
  sieve_after = /var/lib/dovecot/sieve/default.sieve
}

Datei, die angibt, was mit eingehenden Nachrichten geschehen soll.

Datei «/var/lib/dovecot/sieve/default.sieve»

require ["fileinto", "mailbox"];

if header :contains "X-Spam-Flag" "YES" {
        fileinto :create "Spam";
}

Die Datei muss kompiliert werden: «sievec default.sieve».

Die Datei «/etc/dovecot/conf.d/auth-sql.conf.ext»

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

Angabe der SQL-Dateien zur Authentifizierung.
Die Datei selbst dient als Authentifizierungsmethode.

Die Datei «/etc/dovecot/dovecot-sql.conf.ext»

driver = mysql
connect = host=127.0.0.1 dbname=servermail user=usermail password=password
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

Dies entspricht ähnlichen Einstellungen für Postfix.

Die Datei «/etc/dovecot/dovecot.conf»

protocols = imap lmtp pop3
listen = *, ::
dict {
}
!include conf.d/*.conf
!include_try local.conf

Die Hauptkonfigurationsdatei.
Es ist wichtig, die Protokolle hier anzugeben bzw. hinzuzufügen.

============= SpamAssassin =============

apt-get install spamassassin spamc

Wir installieren die Pakete.

adduser spamd --disabled-login

Wir fügen den Benutzer hinzu, unter dessen Namen.

systemctl enable spamassassin.service

Wir aktivieren den automatischen Start des SpamAssassin-Dienstes beim Booten.

Die Datei «/etc/default/spamassassin»:

CRON=1

Aktivierung der automatischen Regelaktualisierung „standardmäßig“.

Die Datei «/etc/spamassassin/local.cf»:

report_safe 0

use_bayes          1
bayes_auto_learn   1
bayes_auto_expire  1
bayes_store_module Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn      DBI:mysql:sa:localhost:3306
bayes_sql_username sa
bayes_sql_password password

Es muss eine MySQL-Datenbank „sa“ mit dem Benutzer „sa“ und dem Passwort „password“ erstellt werden (ersetzen Sie es durch etwas Angemessenes).

report_safe – anstelle einer E-Mail wird ein Bericht über die Spam-E-Mail gesendet.
use_bayes – dies sind die Einstellungen für das maschinelle Lernen von SpamAssassin.

Die anderen Einstellungen von SpamAssassin wurden zuvor gemäß dem Artikel angewendet.

Allgemeine Einstellungen von «SpamAssassin».
Zur Verschiebung neuer Spam-E-Mails in den IMAP-Ordner «Spam».
Zur einfachen Kombination von Dovecot + SpamAssassin.
Ich empfehle das Lesen der Theorie des Lernens von SpamAssassin beim Verschieben von E-Mails in IMAP-Ordnern (und empfehle die Anwendung nicht)..

============= Aufruf an die Gemeinschaft =============

Ich möchte auch eine Idee in die Gemeinschaft einbringen, wie man die Sicherheit von weitergeleiteten E-Mails erhöhen kann. Da ich mich so tief mit dem Thema E-Mail beschäftigt habe.

Damit der Benutzer in seinem Client (Outlook, Thunderbird, Browser-Plugin, …) ein Paar Schlüssel erstellen kann. Öffentlich und privat. Öffentlich – in DNS senden. Privat – im Client speichern. Die Mail-Server sollten in der Lage sein, den öffentlichen Schlüssel für den Versand an einen bestimmten Empfänger zu verwenden.

Und um sich gegen Spam bei solchen E-Mails zu schützen (ja, der Mail-Server kann den Inhalt nicht überprüfen) – müssen drei Regeln eingeführt werden:

  1. Verpflichtende echte DKIM-Signatur, verpflichtendes SPF, verpflichtendes rDNS.
  2. Ein neuronales Netzwerk zum Thema Anti-Spam-Training + eine dazugehörige Datenbank auf der Client-Seite.
  3. Der Verschlüsselungsalgorithmus sollte so gestaltet sein, dass die sendende Partei 100 Mal mehr CPU-Leistung für die Verschlüsselung aufwenden muss als die empfangende Partei.

Neben öffentlichen E-Mails sollte ein Standard für ein Angebotsanschreiben zur "Beginn eines sicheren Austauschs" entwickelt werden. Ein Benutzer (E-Mail-Postfach) sendet einer anderen E-Mail-Adresse eine Nachricht mit einem Anhang. In der Nachricht steht der Textvorschlag, einen sicheren Kommunikationskanal für den Austausch zu beginnen, sowie der öffentliche Schlüssel des E-Mail-Postfachbesitzers (wobei der private Schlüssel auf der Client-Seite bleibt).

Man kann sogar ein paar Schlüssel speziell für jede Kommunikation erstellen. Der empfangende Benutzer kann dieses Angebot annehmen und seinen öffentlichen Schlüssel (ebenfalls speziell für diese Kommunikation erstellt) senden. Danach sendet der erste Benutzer eine Kontrollnachricht (verschlüsselt mit dem öffentlichen Schlüssel des zweiten Benutzers) — deren Empfang dem zweiten Benutzer ermöglicht, den etablierten Kommunikationskanal als zuverlässig zu betrachten. Anschließend sendet der zweite Benutzer eine Kontrollnachricht — und dann kann auch der erste Benutzer den entstandenen Kanal als geschützt betrachten.

Um der Abfangen von Schlüsseln auf dem Weg entgegenzuwirken — sollte das Protokoll die Möglichkeit vorsehen, zumindest einen öffentlichen Schlüssel über einen USB-Stick zu übertragen.

Und das Wichtigste — damit das alles funktioniert (die Frage „wer bezahlt dafür?“):
Einführung von E-Mail-Zertifikaten zu Preisen ab 10 € für 3 Jahre. Diese werden es dem Absender ermöglichen, im DNS anzugeben, dass „meine öffentlichen Schlüssel dort sind“. Und sie werden die Möglichkeit bieten, eine geschützte Verbindung zu starten. Dabei werden solche Verbindungen kostenlos akzeptiert.
Gmail wird endlich monetarisiert. Für 10 $ in 3 Jahren – das Recht, sichere Kommunikationskanäle zu erstellen.

============= Fazit =============

Um den gesamten Artikel zu testen, hatte ich vor, einen dedizierten Server für einen Monat zu mieten und eine Domain mit einem SSL-Zertifikat zu kaufen.

Doch aufgrund von Lebensumständen hat sich diese Frage auf zwei Monate verzögert.
Und als ich wieder etwas freie Zeit hatte, beschloss ich, den Artikel so zu veröffentlichen, wie er ist, anstatt das Risiko einzugehen, dass sich die Veröffentlichung um ein weiteres Jahr verzögert.

Wenn es genügend Fragen wie "Hier ist nicht ausreichend detailliert beschrieben" gibt, dann werde ich wohl die Kraft finden, doch einen dedizierten Server mit einer neuen Domain und einem neuen SSL-Zertifikat zu mieten und alles noch detaillierter zu beschreiben, insbesondere die wichtigen Details zu klären, die bisher übersehen wurden.

Ich wäre auch an Rückmeldungen zu der Idee von E-Mail-Zertifikaten interessiert. Wenn die Idee gefällt, werde ich versuchen, die Energie für einen Entwurf für die RFC zu finden.

Beim Kopieren größerer Teile des Artikels ist auf diesen Artikel zu verweisen.
Bei der Übersetzung in eine andere Sprache ist ebenfalls auf diesen Artikel zu verweisen.
Ich werde versuchen, selbst ins Englische zu übersetzen und die Querverweise zu hinterlassen.


Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster