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

Este artículo trata sobre cómo configurar un servidor de correo moderno.
Postfix + Dovecot. SPF + DKIM + rDNS. Con IPv6.
Con cifrado TSL. Con soporte para múltiples dominios — parte con un certificado SSL real.
Con protección contra spam y alta calificación anti-spam en otros servidores de correo.
Con soporte para múltiples interfaces físicas.
Con OpenVPN, al que se conecta a través de IPv4, y que proporciona IPv6.

Si no desea aprender todas estas tecnologías, pero quiere configurar un servidor así, este artículo es para usted.

En el artículo no se intentan explicar todos los detalles. La explicación va dirigida a lo que está configurado de manera no estándar o es importante desde el punto de vista del consumidor.

La motivación para configurar un servidor de correo es un sueño antiguo mío. Puede sonar tonto, pero en mi opinión, es mucho mejor que soñar con un nuevo coche de la marca favorita.

La motivación para configurar IPv6 es doble. Un profesional de TI necesita estudiar nuevas tecnologías constantemente para sobrevivir. Quiero contribuir modestamente a la lucha contra la censura.

La motivación para configurar OpenVPN es solo para que IPv6 funcione en la máquina local.
La motivación para configurar múltiples interfaces físicas es que en mi servidor tengo una interfaz 'lenta, pero ilimitada', y otra 'rápida, pero con tarifa'.

La motivación para configurar Bind es que mi proveedor ofrece un servidor DNS inestable, y Google también tiene fallos. Quiero un servidor DNS estable para uso personal.

La motivación para escribir el artículo es que el borrador fue escrito hace 10 meses, y ya lo he consultado dos veces. Si el autor necesita revisarlo regularmente, es muy probable que otros también lo necesiten.

No hay una solución universal para un servidor de correo. Pero intentaré escribir algo como 'hagan esto y luego, cuando todo funcione como debe, eliminen lo innecesario'.

Tengo un servidor de colocation en la empresa tech.ru. Hay posibilidad de comparar con OVH, Hetzner, AWS. Para esta tarea será mucho más eficiente colaborar precisamente con tech.ru.

En el servidor está instalado Debian 9.

En el servidor hay 2 interfaces `eno1` y `eno2`. La primera es ilimitada, y la segunda es rápida, respectivamente.

Dispongo de 3 direcciones IP estáticas, XX.XX.XX.X0, XX.XX.XX.X1 y XX.XX.XX.X2 en la interfaz `eno1`, y XX.XX.XX.X5 en la interfaz `eno2`.

Dispongo de un bloque de direcciones IPv6 XXXX:XXXX:XXXX:XXXX::/64, que están asignadas a la interfaz `eno1`, y de XXXX:XXXX:XXXX:XXXX:1:2::/96 a petición mía fueron asignadas a `eno2`.

Hay 3 dominios `domain1.com`, `domain2.com`, `domain3.com`. Para `domain1.com` y `domain3.com` hay un certificado SSL.

Dispongo de una cuenta de Google, a la que quiero vincular el buzón de correo `vasya.pupkin@domain1.com` (recibir correos y enviar correos directamente desde la interfaz de Gmail).
Debería haber un buzón de correo `support@domain2.com`, del cual quiero ver una copia de los correos en mi Gmail. Y ocasionalmente tener la posibilidad de enviar algo en nombre de `support@domain2.com` a través de la interfaz web.

Debería haber un buzón de correo `ivanov@domain3.com`, que será utilizado por Ivanov desde su iPhone.

Los correos enviados deben cumplir con todos los requisitos modernos contra el spam.
Debería haber el más alto nivel de cifrado previsto en redes públicas.
Debería haber soporte para IPv6 tanto para el envío como para la recepción de correos.
Debería haber un SpamAssassin que nunca elimine correos. Debe hacer un bounce o pasar o enviar a la carpeta IMAP 'Spam'.
Debería estar configurado el autoaprendizaje de SpamAssassin: si muevo un correo a la carpeta 'Spam', debe aprender de esto; si muevo un correo de la carpeta 'Spam', debe aprender de esto. Los resultados del aprendizaje de SpamAssassin deben influir en la probabilidad de que un correo termine en la carpeta 'Spam'.
Los scripts PHP deberían poder enviar correos en nombre de cualquier dominio en este servidor.
Debería haber un servicio OpenVPN, con la posibilidad de usar IPv6 en un cliente que no tiene IPv6.

Primero hay que configurar las interfaces y la ruta, incluyendo IPv6.
Luego, habrá que configurar OpenVPN, que se conectará por IPv4 y proporcionará al cliente una dirección IPv6 real estática. Este cliente tendrá acceso a todos los servicios IPv6 en el servidor y acceso a cualquier recurso IPv6 en Internet.
Después, se deberá configurar Postfix para enviar correos + SPF + DKIM + rDNS y otras cosas similares.
Luego, habrá que configurar Dovecot y ajustar Multidomain.
Finalmente, se instalará Bind.
============= Multi-interfaces =============

Para la configuración de interfaces, hay que agregar lo siguiente en 'etc/network/interfaces'.

Estos ajustes se pueden aplicar en cualquier servidor en tech.ru (con una pequeña coordinación con el soporte) y funcionará de inmediato como se espera.

# 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

Si tienes experiencia configurando cosas similares para Hetzner, OVH, allí es diferente. Más complicado.

eno1 es el nombre de la tarjeta de red #1 (lenta, pero ilimitada).

eno2 es el nombre de la tarjeta de red #2 (rápida, pero con tarifa).
eno2 es el nombre de la tarjeta de red #2 (rápida, pero con tarifa).
tun0 — este es el nombre de la interfaz de red virtual de OpenVPN.
XX.XX.XX.X0 — IPv4 #1 en eno1.
XX.XX.XX.X1 — IPv4 #2 en eno1.
XX.XX.XX.X2 — IPv4 #3 en eno1.
XX.XX.XX.X5 — IPv4 #1 en eno2.
XX.XX.XX.1 — puerta de enlace IPv4.
XXXX:XXXX:XXXX:XXXX::/64 — IPv6 para todo el servidor.
XXXX:XXXX:XXXX:XXXX:1:2::/96 — IPv6 para eno2, todo lo demás entra por eno1.
XXXX:XXXX:XXXX:XXXX::1 — puerta de enlace IPv6 (es importante mencionar que aquí se puede/necesita hacer diferente. Indicar el IPv6 del switch).
dns-nameservers — se han especificado 127.0.0.1 (porque bind está instalado localmente) y 213.248.1.6 (esto es de tech.ru).

«table eno1t» y «table eno2t» — el propósito de estas reglas de ruta es que el tráfico que ingresa por eno1 salga por ese mismo, y el tráfico que ingresa por eno2 salga por ese mismo. Así como las conexiones iniciadas por el servidor saldrían por eno1.

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

Con este comando establecemos que cualquier tráfico no definido que caiga bajo cualquier regla marcada «table eno1t» -> se redirija a la interfaz eno1.

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

Con este comando establecemos que todo el tráfico iniciado por el servidor se dirija a la interfaz eno1.

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

Con este comando establecemos las propias reglas de etiquetado del tráfico.

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

Este bloque define un segundo IPv4 para la interfaz eno1.

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

Con este comando definimos la ruta de los clientes OpenVPN a las IPv4 locales excepto XX.XX.XX.X0.
Por qué este comando es suficiente para todas las IPv4 — todavía no lo entiendo.

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

Estamos estableciendo la dirección para la propia interfaz. El servidor la usará como dirección «saliente». No se utilizará de ninguna otra manera.

¿Por qué se especifica «:1:1::» de forma tan complicada? Para que OpenVPN funcione correctamente y solo por eso. Hablaremos de esto más adelante.

En cuanto a la puerta de enlace — así funciona y está bien. Pero correctamente — aquí debería indicarse el IPv6 del switch al que está conectado el servidor.

Sin embargo, por alguna razón, el IPv6 deja de funcionar si lo hago así. Probablemente son manías de tech.ru.

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

Esto añade una dirección IPv6 a la interfaz. Si necesitas cien direcciones — significa cien líneas en este archivo.

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

He marcado las direcciones y subredes de todas las interfaces para que sea más visual.
eno1 — debe tener necesariamente «/64» — porque ese es todo nuestro pool de direcciones.
tun0 — la subred debe ser obligatoriamente mayor que eno1. De lo contrario, no se podrá configurar el gateway IPv6 para los clientes de OpenVPN.
eno2 — la subred debe ser obligatoriamente mayor que tun0. De lo contrario, los clientes de OpenVPN no podrán acceder a las direcciones IPv6 locales.
Para mayor claridad elegí un paso de subred de 16, pero si se desea se puede hacer incluso con un paso de «1».
Por lo tanto, 64+16 = 80, y 80+16 = 96.

Para aún más claridad:
XXXX:XXXX:XXXX:XXXX:1:1:YYYY:YYYY — estas son las direcciones que deben asignarse a sitios o servicios específicos en la interfaz eno1.
XXXX:XXXX:XXXX:XXXX:1:2:YYYY:YYYY — estas son las direcciones que deben asignarse a sitios o servicios específicos en la interfaz eno2.
XXXX:XXXX:XXXX:XXXX:1:3:YYYY:YYYY — estas son las direcciones que deben asignarse a los clientes de OpenVPN o utilizarse como direcciones de servicio de OpenVPN.

Para configurar la red — debe haber la posibilidad de reiniciar el servidor.
Los cambios de IPv4 se detectan al ejecutar (debe realizarse en screen — de lo contrario, este comando simplemente caerá la red del servidor):

/etc/init.d/networking restart

Añadir al final del archivo «/etc/iproute2/rt_tables»:

100 eno1t
101 eno2t

Sin esto no se pueden usar tablas personalizadas en el archivo «/etc/network/interfaces».
Los números deben ser únicos y menores de 65535.

Los cambios de IPv6 se modifican fácilmente sin reiniciar, pero para esto se deben aprender al menos tres comandos:

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

Configuración de «/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

Estos son los ajustes de «sysctl» de mi servidor. Notaré algo importante.

net.ipv4.ip_forward = 1

Sin esto, OpenVPN no funcionará en absoluto.

net.ipv6.ip_nonlocal_bind = 1

Cualquiera que intente hacer bind IPv6 (por ejemplo, nginx) justo después de que la interfaz se habilite — obtendrá un error. Diciendo que tal dirección no está disponible.

Para evitar esa situación se realiza esta configuración.

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

Sin estos ajustes, el tráfico IPv6 de los clientes de OpenVPN no saldrá al mundo.

Otros ajustes o no son relevantes o no recuerdo para qué sirven.
Pero por si acaso, lo dejo «tal cual».

Para que los cambios de este archivo se apliquen sin reiniciar el servidor — hay que ejecutar el comando:

sysctl -p

Más sobre las reglas de «table»: habr.com/post/108690

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

OpenVPN IPv4 no funciona sin iptables.

Mis iptables son los siguientes para VPN:

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 es mi dirección IPv4 estática de la máquina local.
10.8.0.0/24 es la red IPv4 de openvpn. Direcciones IPv4 para los clientes de openvpn.
El orden de las reglas es importante.

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

Esta restricción es para que solo yo pueda utilizar OpenVPN desde mi IP estática.

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

Para el enrutamiento de paquetes IPv4 entre los clientes de OpenVPN y la Internet, es necesario usar uno de estos comandos.

Un caso no es adecuado para diferentes situaciones.
Para mi caso, ambos comandos son adecuados.
Después de leer la documentación, elegí la primera opción porque consume menos CPU.

Para que todos los ajustes de iptables se conserven después de reiniciar, deben guardarse en algún lugar.

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

Estos nombres no fueron elegidos al azar. Son utilizados por el paquete 'iptables-persistent'.

apt-get install iptables-persistent

Instalación del paquete principal de OpenVPN:

apt-get install openvpn easy-rsa

Configuraremos la plantilla para los certificados (inserte sus valores):

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

Editaremos los ajustes de la plantilla de certificados:

mcedit vars

... 
# Estos son los valores predeterminados para los campos
# que serán colocados en el certificado.
# No deje ninguno de estos campos en blanco.
export KEY_COUNTRY="RU"
export KEY_PROVINCE="Krasnodar"
export KEY_CITY="Dinskaya"
export KEY_ORG="Own"
export KEY_EMAIL="admin@domain1.com"
export KEY_OU="VPN"

# Campo de sujeto X509
export KEY_NAME="server"
...

Creando un certificado de servidor:

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

Prepararemos la posibilidad de crear los archivos finales 'client-name.opvn':

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

Prepararemos un script que combinará todos los archivos en un único archivo opvn.

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

Creando el primer cliente de OpenVPN:

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

El archivo '~/client-configs/files/client-name.ovpn' se envía al dispositivo del cliente.

Para los clientes de iOS será necesario hacer un truco:
El contenido de la etiqueta «tls-auth» debe estar sin comentarios.
Y también poner «key-direction 1» justo antes de la etiqueta «tls-auth».

Configurar el archivo de configuración del servidor OpenVPN:

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

Esto es necesario para asignar una dirección estática a cada cliente (no es obligatorio, pero yo lo uso):

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

El detalle más complicado y clave.

Desafortunadamente, OpenVPN aún no puede configurar automáticamente el gateway IPv6 para los clientes.
Es necesario hacer esto «manualmente» para cada cliente.

# 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"

Archivo «/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

Archivo «/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

Ambos scripts utilizan el archivo «/etc/openvpn/variables»:

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

Por qué está escrito así, no recuerdo.

Ahora parece extraño netmask = 112 (aquí debería ser 96).
Y el prefijo es extraño, no coincide con la red tun0.
Pero bueno, lo dejo «como está».

cipher DES-EDE3-CBC

Esto es cuestión de gustos: elegí este método de cifrado de la conexión.

Más detalles sobre la configuración de OpenVPN IPv4.

Más detalles sobre la configuración de OpenVPN IPv6.

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

Instalación del paquete principal:

apt-get install postfix

Al instalar, seleccionar «internet-site».

Mi «/etc/postfix/main.cf» se ve así:

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

# El trabajo de agregar .domain es del MUA.
append_dot_mydomain = no

readme_directory = no

# Consulta http://www.postfix.org/COMPATIBILITY_README.html -- predeterminado a 2 en
# instalaciones nuevas.
compatibility_level = 2

# Parámetros de TLS
smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtp_bind_address = XX.XX.XX.X0
smtp_bind_address6 = XXXX:XXXX:XXXX:XXXX:1:1:1:1

smtp_tls_security_level = may
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

# Tipo de almacenamiento
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

# Configuración de SMTP-Auth
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
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

# Dirección IP por dominio
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Analicemos los detalles de esta configuración.

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

Según la opinión de los usuarios de Habr, este bloque contiene `desinformación y afirmaciones incorrectas`.Sólo ocho años después de comenzar mi carrera comencé a entender cómo funciona SSL.

Por lo tanto, me atreveré a describir cómo usar SSL (sin responder a preguntas como "¿Cómo funciona?" y "¿Por qué funciona?").

La base de la criptografía moderna es la creación de un par de claves (dos cadenas de caracteres muy largas).

Una clave es privada, la otra clave es pública. La clave privada la guardamos celosamente en secreto. La clave pública la compartimos con todos los interesados.

Con la clave pública se puede cifrar una cadena de texto de tal forma que sólo el propietario de la clave privada pueda descifrarla.
Y esa es la base de la tecnología.

Paso n.º 1: sitios https.
El navegador al acceder al sitio informa al servidor web que el sitio es https y, por lo tanto, solicita la clave pública.
El servidor web proporciona la clave pública. El navegador, utilizando la clave pública, cifra la solicitud HTTP y la envía.
El contenido de la solicitud HTTP solo puede ser leído por quien tiene la clave privada, es decir, solo el servidor al que se está dirigiendo.
La solicitud HTTP contiene al menos un URI. Por lo tanto, si en un país intentan limitar el acceso no a todo el sitio, sino a una página específica, esto es imposible para los sitios HTTPS.

Paso #2 — respuesta cifrada.
El servidor web da una respuesta que puede ser fácilmente leída en el camino.
La solución es sumamente simple: el navegador forma localmente un par de clave pública-clave privada para cada sitio HTTPS.
Y junto con la solicitud de la clave pública del sitio, envía su propia clave pública local.
El servidor web la recuerda y al enviar la respuesta HTTP cifra con esta clave pública específica del cliente.
Ahora la respuesta HTTP solo puede ser descifrada por el propietario de la clave privada del navegador del cliente (es decir, el propio cliente).

Paso #3 — establecimiento de una conexión segura a través de un canal público.
En el ejemplo #2 hay una vulnerabilidad: nada impide que un intruso intercepte la solicitud HTTP y edite la información sobre la clave pública.
Así, el intermediario podrá ver todo el contenido de los mensajes enviados y recibidos hasta que se cambie el canal de comunicación.
Luchar contra esto es sumamente simple: basta con enviar la clave pública del navegador como un mensaje cifrado con la clave pública del servidor web.
El servidor web entonces envía como respuesta algo del tipo «tu clave pública es esta» y cifra este mensaje con la misma clave pública.
El navegador revisa la respuesta: si recibe el mensaje «tu clave pública es esta», es una garantía del 100% de que este canal de comunicación es seguro.
¿Qué tan seguro es?
La creación de un canal seguro ocurre a la velocidad de ping*2. Por ejemplo, 20 ms.
Un atacante debe o tener de antemano la clave privada de una de las partes o descifrarla en un par de milisegundos.
Romper una clave privada moderna puede llevar décadas en una supercomputadora.

Paso #4 — base de datos pública de claves públicas.
Es evidente que en toda esta historia existe la posibilidad de un atacante que esté en el canal de comunicación entre el cliente y el servidor.
La posibilidad de que el cliente se presente como un servidor y el servidor como un cliente. Y emular un par de claves en ambas direcciones.
Entonces el atacante verá todo el tráfico y tendrá la oportunidad de "editar" el tráfico.
Por ejemplo, cambiar la dirección a la que enviar dinero, copiar la contraseña de un banco en línea o bloquear contenido "indeseado".
Para combatir a tales atacantes, se creó una base de datos pública con claves públicas para cada sitio https.
Cada navegador "sabe" de la existencia de alrededor de 200 de tales bases de datos. Esto está preestablecido en cada navegador.
"El conocimiento" está respaldado por la clave pública de cada certificado. Es decir, es imposible falsificar la conexión con cada centro de certificación específico.

Ahora hay una comprensión sencilla de cómo usar SSL para https.
Si se piensa un poco, se entenderá cómo los servicios secretos pueden romper algo en esta construcción. Pero les costará un esfuerzo monstruoso.
A organizaciones que no son la NSA o la CIA, prácticamente les resulta imposible romper el nivel de protección existente, incluso para clientes VIP.

También agregaré algo sobre las conexiones ssh. Allí no hay claves públicas, ¿qué hacer entonces? La cuestión se resuelve de dos maneras.
Opción ssh por contraseña:
En la primera conexión, el cliente ssh debe advertir que aquí tenemos una nueva clave pública del servidor ssh.
Y en conexiones posteriores, si aparece la advertencia "nueva clave pública del servidor ssh", significará que están intentando interceptar la conexión.
O que en la primera conexión lo estaban interceptando y ahora te comunicas con el servidor sin intermediarios.
En realidad, debido a que el hecho de la interceptación se revela fácil, rápida y sin esfuerzo, este ataque solo se utiliza en casos especiales para un cliente específico.

Opción ssh por clave:
Tomamos una memoria USB, grabamos en ella la clave privada para el servidor ssh (para esto hay términos y muchos matices significativos, pero yo estoy escribiendo un manual básico, no instrucciones de uso).
La clave pública la dejamos en la máquina donde estará el cliente ssh y también la mantenemos en secreto.
Llevamos la memoria USB al servidor, la insertamos, copiamos la clave privada, y luego quemamos la memoria USB y esparcimos las cenizas al viento (o al menos la formateamos con ceros).
Y eso es todo: después de esta operación, será imposible hackear una conexión ssh así. Por supuesto, en unos 10 años, alguien con una supercomputadora podría revisitar el tráfico, pero esa es otra historia.

Mis disculpas por el off-topic.

Así que, ahora que conocemos la teoría, hablaré sobre el flujo de creación del certificado ssl.

Con «openssl genrsa», creamos una clave privada y una 'plantilla' para la clave pública.
La 'plantilla' se envía a una empresa externa, a la que pagamos aproximadamente $9 por el certificado más básico.

Después de un par de horas, recibimos de esta empresa externa nuestra 'clave pública' y un conjunto adicional de varias claves públicas.

Por qué pagar a una empresa externa por certificar mi clave pública es una pregunta aparte, no la consideraremos aquí.

Ahora queda claro el sentido de la inscripción:

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

En la carpeta '\/etc\/ssl' se almacenan todos los archivos relacionados con ssl.
domain1.com — el nombre de dominio.
2018 — el año en que se crearon las claves.
«key» — indica que el archivo es una clave privada.

Y el sentido de este archivo es:

smtpd_tls_cert_file=\/etc\/ssl\/domain1.com.2018.chained.crt
domain1.com — el nombre de dominio.
2018 — el año en que se crearon las claves.
chained — indica que aquí hay una cadena de claves públicas (primera — nuestra pública y las restantes — las que recibimos de la empresa que emitió la clave pública).
crt — indica que aquí hay un certificado listo (una clave pública con explicaciones técnicas).

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

Esta configuración no se utiliza en este caso, pero se incluye como ejemplo.

Porque un error en este parámetro podría llevar a que tu servidor envíe spam (sin que tú lo quieras).

Luego tendrás que demostrar que no eres culpable.

recipient_delimiter = +

Puede que muchos no lo sepan, pero este es el símbolo estándar para segmentar correos, y lo apoyan la mayoría de los servidores de correo modernos.

Por ejemplo, si tienes un buzón de 'username@gmail.com', intenta enviar a 'username+spam@gmail.com' — veamos qué sucede.

inet_protocols = ipv4

Esto podría resultar confuso.

Pero no es aleatorio. Cada nuevo dominio, por defecto, solo usa IPv4, luego habilito IPv6 individualmente.

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

Aquí establecemos que todo el correo entrante se envía a dovecot.
Y las reglas para dominio, buzón, alias — se consultan en la base de datos.

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

usuario = usermail
contraseña = mailpassword
hosts = 127.0.0.1
dbname = servermail
consulta = SELECT 1 FROM virtual_domains WHERE name='%s'

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

usuario = usermail
contraseña = mailpassword
hosts = 127.0.0.1
dbname = servermail
consulta = SELECT 1 FROM virtual_users WHERE email='%s'

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

usuario = usermail
contraseña = mailpassword
hosts = 127.0.0.1
dbname = servermail
consulta = 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

Ahora postfix sabe que puede recibir correos para su posterior envío solo con autorización de dovecot.

Realmente no entiendo por qué duplicar esto aquí. Ya hemos indicado en «virtual_transport» todo lo necesario.

Pero el sistema postfix es muy antiguo, probablemente sean remiendos de tiempos pasados.

smtpd_recipient_restrictions =
        ...

smtpd_helo_restrictions =
        ...

smtpd_client_restrictions =
        ...

Esto se configura de manera diferente para cada servidor de correo.

Dispongo de 3 servidores de correo y estas configuraciones son muy diferentes debido a los diversos requisitos de uso.

La configuración debe hacerse con cuidado, de lo contrario el spam fluirá hacia usted o, aún peor, el spam fluirá desde usted.

# SPF
policyd-spf_time_limit = 3600

Configuración para algún plugin relacionado con la verificación de SPF en correos entrantes.

# 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

Configuración para que todos los correos salientes deben estar firmados con DKIM.

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

Este es un detalle clave en la ruta de los correos al enviar correos desde scripts php.

Archivo «/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:

A la izquierda están las expresiones regulares. A la derecha, la etiqueta que marca el correo.
Postfix, de acuerdo con la etiqueta, tendrá en cuenta otras líneas de configuración específicas para ese correo.

Cómo se reconfigurará postfix para un correo específico se indicará en «master.cf».

Las líneas 4, 5, 6 son las principales. Desde qué dominio se envía el correo, esa será la etiqueta que se coloque.
Pero no siempre en los scripts php del código antiguo se indica el campo «from». Entonces, entra en juego el nombre de usuario.

El artículo ya es extenso, no quisiera distraerme con la configuración de nginx+fpm.

En resumen, asignamos un propietario linux-user a cada sitio. Y, en consecuencia, su propio fpm-pool.

El fpm-pool utiliza cualquier versión de php (esto es genial cuando en un solo servidor sin problemas se puede usar diferentes versiones de php y hasta diferentes php.ini).

Así que, en el caso del linux-user específico «www-domain2», tiene el sitio domain2.com. En este sitio hay código para enviar correos sin indicar el campo from.

Así que incluso en tal caso, los correos se enviarán correctamente y nunca caerán en spam.

Mi «/etc/postfix/master.cf» se ve así:

... 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

El archivo no está completo, ya es muy grande.
Solo marqué lo que se ha cambiado.

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}

Estas son configuraciones relacionadas con spamassassin, de esto hablaremos después.

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

Permitimos conectarse al servidor de correo a través del puerto 587.
Para ello, es imprescindible autenticarse.

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

Activamos la verificación de SPF.

apt-get install postfix-policyd-spf-python

Instalaremos el paquete para las verificaciones de SPF.

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

Y esto es lo más interesante. Es la posibilidad de enviar correos para un dominio específico desde una dirección IPv4/IPv6 específica.

Esto se hace por el rDNS. El rDNS es la obtención de una cadena a partir de una dirección IP.
Y para el correo, esta posibilidad se utiliza para confirmar que el helo coincide con el rDNS de la dirección desde la cual se ha enviado el email.

Si el helo no coincide con el dominio del correo desde el cual se ha enviado, se acumulan puntos de spam.

El helo no coincide con el rDNS: se acumulan muchos puntos de spam.
Por lo tanto, cada dominio debe tener su propia dirección IP.
Para OVH, en el panel hay una opción para especificar el rDNS.
Para tech.ru, se resuelve a través del soporte.
Para AWS, se resuelve a través del soporte.
«inet_protocols» y «smtp_bind_address6» — esto habilita el soporte para IPv6.
También se debe configurar rDNS para IPv6.
«syslog_name» — esto es para facilitar la lectura de los registros.

Comprar certificados recomiendo aquí.

Configuración de la combinación postfix+dovecot aquí.

Configuración de SPF.

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

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

Configuración de mysql, instalamos los paquetes nosotros mismos.

El archivo «/etc/dovecot/conf.d/10-auth.conf»

disable_plaintext_auth = yes
auth_mechanisms = plain login

Autenticación solo en forma encriptada.

El archivo «/etc/dovecot/conf.d/10-mail.conf»

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

Aquí especificaremos el lugar de almacenamiento de los correos.

Quiero que se almacenen en archivos y estén agrupados por dominios.

El archivo «/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 {
  }
}

Este es el archivo principal de configuración de dovecot.
Aquí desactivamos las conexiones no seguras.
Y habilitamos las conexiones seguras.

El archivo «/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
}

Configuramos ssl. Indicamos que ssl es obligatorio.
Y el certificado en sí. Y un detalle importante — la directiva «local». Indica qué certificado ssl utilizar al conectarse a un IPv4 local.

Por cierto, IPv6 no está configurado aquí, corregiré esa omisión en algún momento.
XX.XX.XX.X5 (domain2) — no hay certificado. Para la conexión de clientes se debe indicar domain1.com.
XX.XX.XX.X2 (domain3) — hay certificado, para la conexión de clientes se puede indicar domain1.com o domain3.com.

El archivo «/etc/dovecot/conf.d/15-lda.conf»

protocol lda {
  mail_plugins = $mail_plugins sieve
}

Esto será necesario más adelante para spamassassin.

El archivo «/etc/dovecot/conf.d/20-imap.conf»

protocol imap {
  mail_plugins = $mail_plugins antispam
}

Este es el plugin antispam. Necesario para entrenar spamassassin en el momento de mover hacia/desde la carpeta «Spam».

El archivo «/etc/dovecot/conf.d/20-pop3.conf»

protocol pop3 {
}

Simplemente, existe tal archivo.

El archivo «/etc/dovecot/conf.d/20-lmtp.conf»

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

Configuración de lmtp.

Archivo «/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
}

Configuraciones de entrenamiento de spamassassin al mover a/desde la carpeta «Spam».

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

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

Archivo en el que se indica qué hacer con los correos entrantes.

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

require ["fileinto", "mailbox"];

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

Es necesario compilar el archivo: «sievec default.sieve».

Archivo «/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
}

Especificación de archivos sql para la autorización.
Y el archivo en sí — como método de autorización.

Archivo «/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';

Esto corresponde a configuraciones similares para postfix.

Archivo «/etc/dovecot/dovecot.conf»

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

Archivo de configuración principal.
Es importante que aquí indiquemos-agreguemos protocolos.

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

apt-get install spamassassin spamc

Instalaremos los paquetes.

adduser spamd --disabled-login

Agregaremos un usuario bajo el cual.

systemctl enable spamassassin.service

Activamos el autoload del servicio de spamassassin al iniciar.

Archivo «/etc/default/spamassassin»:

CRON=1

Activamos la actualización automática de reglas «por defecto».

Archivo «/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 necesario crear en la base de datos MySQL «sa» con el usuario «sa» y la contraseña «password» (reemplazar por algo adecuado).

report_safe — en lugar de un correo se enviará un informe sobre el correo de spam.
use_bayes — estas son configuraciones de aprendizaje automático de spamassassin.

Las demás configuraciones de spamassassin se aplicaron anteriormente según el artículo.

Configuración general de «spamassassin».
Sobre el movimiento de nuevos correos spam a la carpeta IMAP «Spam».
Sobre la simple integración de Dovecot + SpamAssassin.
Recomiendo leer sobre la teoría del aprendizaje de spamassassin al mover correos en carpetas IMAP (y no recomiendo su aplicación).

============= Llamado a la comunidad =============

También me gustaría plantear una idea en la comunidad sobre cómo mejorar la seguridad de los correos electrónicos enviados. Dado que me he sumergido tanto en el tema del correo.

Para que el usuario pueda crear un par de claves en su cliente (Outlook, Thunderbird, complemento del navegador, ...). La clave pública se enviaría al DNS. La clave privada se almacenaría en el cliente. Los servidores de correo deberían ser capaces de usar la clave pública para enviar al destinatario específico.

Y para protegerse contra el spam en esos correos electrónicos (sí, el servidor de correo no podrá ver el contenido) - se deberán introducir 3 reglas:

  1. Firma DKIM válida obligatoria, SPF obligatorio, rDNS obligatorio.
  2. Una red neuronal para el aprendizaje del anti-spam + su base de datos del lado del cliente.
  3. El algoritmo de cifrado debe ser tal que la parte emisora deba gastar un 100 veces más de capacidades de CPU en el cifrado que la parte receptora.

Además de los correos públicos, desarrollar un estándar para correos de oferta "iniciar una conversación segura". Un usuario (buzón de correo) envía a otro buzón un correo con un archivo adjunto. En el correo, un texto propone iniciar un canal seguro de comunicación y la clave pública del propietario del buzón de correo (mientras que la clave privada está del lado del cliente).

Incluso se pueden crear un par de claves específicamente para cada conversación. El usuario receptor puede aceptar esta oferta y enviar su clave pública (también creada específicamente para esta conversación). Luego, el primer usuario envía un correo de control de servicio (cifrado con la clave pública del segundo usuario) - al recibirlo, el segundo usuario puede considerar el canal de comunicación formado como confiable. Luego, el segundo usuario envía un correo de control - y entonces el primer usuario también puede considerar el canal formado como protegido.

Para combatir la interceptación de claves en tránsito, se debe prever en el protocolo la posibilidad de transmitir al menos una clave pública mediante una memoria USB.

Y lo más importante: que todo esto funcione (la pregunta es "¿quién pagará por esto?"):
Introducir certificados de correo electrónico a partir de 10$ por 3 años. Que permitirán al remitente indicar en DNS que «mis claves públicas están allí». Y permitirán iniciar una conexión segura. Además, recibir tales conexiones será gratis.
Gmail finalmente monetiza a sus usuarios. Por 10$ en 3 años – el derecho a crear canales de comunicación seguros.

============= Conclusión =============

Para probar todo el artículo, planeaba alquilar un servidor dedicado por un mes y comprar un dominio con un certificado SSL.

Pero las circunstancias de la vida hicieron que este asunto se prolongara por 2 meses.
Y cuando nuevamente tuve tiempo libre, decidí publicar el artículo tal como está, en lugar de arriesgarme a que la publicación se retrase otro año.

Si hay suficientes preguntas del tipo «aquí no está lo suficientemente detallado» — entonces, probablemente, encontraré las fuerzas para tomar un servidor dedicado con un nuevo dominio y un nuevo certificado SSL y describir todo con más detalle y, lo más importante, identificar todos los detalles importantes que se pasaron por alto.

También me gustaría recibir comentarios sobre la idea de los certificados de correo electrónico. Si la idea es bien recibida, intentaré encontrar las fuerzas para redactar un borrador para el RFC.

Al copiar grandes secciones del artículo, se debe indicar el enlace a este artículo.
Al traducir a cualquier otro idioma, se debe indicar el enlace a este artículo.
Yo mismo intentaré traducir al inglés y dejaré enlaces cruzados.


Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster