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

Este artigo é sobre como configurar um servidor de email moderno.
Postfix + Dovecot. SPF + DKIM + rDNS. Com IPv6.
Com criptografia TSL. Com suporte a vários domínios — parte com um verdadeiro certificado SSL.
Com proteção contra spam e alta classificação antispam em outros servidores de email.
Com suporte a várias interfaces físicas.
Com OpenVPN, que se conecta via IPv4 e fornece IPv6.

Se você não quer estudar todas essas tecnologias, mas deseja configurar esse servidor — então este artigo é para você.

O artigo não tenta explicar cada detalhe. A explicação está relacionada ao que está configurado de forma não padrão ou que é importante do ponto de vista do consumidor.

A motivação para configurar um servidor de email é meu antigo sonho. Pode parecer uma loucura, mas na minha opinião, é muito melhor do que sonhar com um novo carro da marca favorita.

A motivação para configurar o IPv6 é dupla. Um profissional de TI precisa estar sempre aprendendo novas tecnologias para sobreviver. Quero fazer minha humilde contribuição na luta contra a censura.

A motivação para configurar o OpenVPN é apenas para que o IPv6 funcione na máquina local.
A motivação para configurar várias interfaces físicas é que no meu servidor uma interface é 'lenta, mas ilimitada', enquanto a outra é 'rápida, mas com limite'.

A motivação para configurar o Bind é que meu provedor oferece um servidor DNS instável, e o Google também pode falhar. Quero um servidor DNS estável para uso pessoal.

A motivação para escrever este artigo — o rascunho foi feito há 10 meses, e eu já olhei para ele duas vezes. Se até o autor precisa disso regularmente, há uma grande chance de que outros também precisem.

Não há uma solução universal para um servidor de email. Mas vou tentar escrever algo como 'faça assim e depois, quando tudo funcionar como deveria — exclua o que não serve'.

Tenho um servidor de Colocation na empresa tech.ru. Há a possibilidade de comparação com OVH, Hetzner, AWS. Para resolver essa tarefa, será muito mais eficaz colaborar com a tech.ru.

O servidor está rodando Debian 9.

O servidor tem 2 interfaces `eno1` e `eno2`. A primeira é ilimitada, enquanto a segunda é rápida.

Há 3 endereços IP estáticos, XX.XX.XX.X0, XX.XX.XX.X1 e XX.XX.XX.X2 na interface `eno1` e XX.XX.XX.X5 na interface `eno2`.

Há um pool de endereços IPv6 XXXX:XXXX:XXXX:XXXX::/64, que estão atribuídos à interface `eno1` e, a pedido meu, XXXX:XXXX:XXXX:XXXX:1:2::/96 foi atribuído a `eno2`.

Existem 3 domínios `domain1.com`, `domain2.com`, `domain3.com`. Para `domain1.com` e `domain3.com` há certificado SSL.

Há uma conta do Google que gostaria de vincular à caixa de correio `vasya.pupkin@domain1.com` (receber e enviar e-mails diretamente da interface do Gmail).
Deve haver uma caixa de correio `support@domain2.com`, da qual quero receber uma cópia dos e-mails no meu Gmail. E ter a possibilidade de enviar algo em nome de `support@domain2.com` através da interface web.

Deve haver uma caixa de correio `ivanov@domain3.com`, que será utilizada por Ivanov em seu iPhone.

Os e-mails enviados devem atender a todos os requisitos modernos de anti-spam.
Deve haver o mais alto nível de criptografia previsto em redes públicas.
Deve haver suporte para IPv6 tanto para envio quanto para recebimento de e-mails.
Deve haver SpamAssassin que nunca irá excluir e-mails. Ele deve ou fazer bounce ou passar ou enviar para a pasta IMAP 'Spam'.
Deve ser configurado o auto-aprendizagem do SpamAssassin: se eu mover um e-mail para a pasta 'Spam' — ele deve aprender com isso; se eu mover um e-mail da pasta 'Spam' — ele deve aprender com isso. Os resultados do aprendizado do SpamAssassin devem influenciar a classificação do e-mail na pasta 'Spam'.
Os scripts PHP devem ser capazes de enviar e-mails em nome de qualquer domínio neste servidor.
Deve haver um serviço openvpn, com a possibilidade de usar IPv6 no cliente que não possui IPv6.

Primeiro, é necessário configurar as interfaces e a roteamento, incluindo IPv6.
Depois, será necessário configurar o OpenVPN, que se conectará via IPv4 e fornecerá ao cliente um endereço IPv6 estático e real. Este cliente terá acesso a todos os serviços IPv6 no servidor e a quaisquer recursos IPv6 na internet.
Depois, será necessário configurar o Postfix para enviar e-mails + SPF + DKIM + rDNS e outras pequenas coisas semelhantes.
Depois, será necessário configurar o Dovecot e configurar Multidomain.
Depois, será necessário configurar o SpamAssassin e configurar o aprendizado.
Por fim, instalar o Bind.

============= Multi-interfaces =============

Para configurar as interfaces, deve-se escrever o seguinte em '/etc/network/interfaces'.

# 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

Essas configurações podem ser aplicadas em qualquer servidor em tech.ru (com uma pequena aprovação do suporte) e funcionarão imediatamente como necessário.

Se tiver experiência em configurar coisas semelhantes para Hetzner, OVH — é diferente. Mais complicado.

eno1 é o nome da placa de rede #1 (lenta, mas ilimitada).
eno2 é o nome da placa de rede #2 (rápida, mas com tarifa).
tun0 — é o nome de uma interface de rede virtual do OpenVPN.
XX.XX.XX.X0 — IPv4 #1 no eno1.
XX.XX.XX.X1 — IPv4 #2 no eno1.
XX.XX.XX.X2 — IPv4 #3 no eno1.
XX.XX.XX.X5 — IPv4 #1 no eno2.
XX.XX.XX.1 — gateway IPv4.
XXXX:XXXX:XXXX:XXXX::/64 — IPv6 para todo o servidor.
XXXX:XXXX:XXXX:XXXX:1:2::/96 — IPv6 para eno2, todo o restante entra pelo eno1.
XXXX:XXXX:XXXX:XXXX::1 — gateway IPv6 (vale a pena mencionar que isso pode/precisa ser feito de forma diferente. Indicar o IPv6 do switch).
dns-nameservers — configurados como 127.0.0.1 (porque o bind está instalado localmente) e 213.248.1.6 (este é do tech.ru).

«table eno1t» e «table eno2t» — o sentido destas route-rule é que o tráfego que entra pelo eno1 -> saia por ele mesmo, enquanto o tráfego que entra pelo eno2 -> saia por ele mesmo. Além disso, as conexões iniciadas pelo servidor também devem sair pelo eno1.

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

Este comando define que qualquer tráfego confuso, que se encaixe em qualquer regra marcada como «table eno1t» -> deve ser direcionado para a interface eno1.

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

Este comando define que qualquer tráfego iniciado pelo servidor deve ser direcionado para a interface eno1.

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

Este comando define as próprias regras de marcação do tráfego.

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 bloco define um segundo IPv4 para a interface eno1.

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

Este comando define a rota dos clientes OpenVPN para os IPv4 locais, exceto XX.XX.XX.X0.
Por que este comando é suficiente para todos os IPv4 — eu ainda não entendo.

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

Aqui estamos definindo o endereço para a própria interface. O servidor usará isso como o endereço «de saída». Não será usado de outra forma.

Por que foi indicado «:1:1::» de forma tão complexa? Para que o OpenVPN funcione corretamente e somente para isso. Falarei mais sobre isso mais tarde.

Sobre o gateway — assim funciona, e tudo bem. Mas, tecnicamente, aqui deveria ser indicado o IPv6 do switch ao qual o servidor está conectado.

No entanto, por alguma razão, o IPv6 deixa de funcionar se eu fizer isso. Provavelmente são complexidades do tech.ru.

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

Isso adiciona um endereço IPv6 à interface. Se precisar de uma centena de endereços — serão necessárias uma centena de linhas neste arquivo.

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

Marquei os endereços e sub-redes de todas as interfaces, para ser mais claro.
eno1 — deve obrigatoriamente ter «/64» — pois este é todo o nosso pool de endereços.
tun0 — a sub-rede deve ser obrigatoriamente maior que eno1. Caso contrário, não será possível configurar o gateway IPv6 para clientes OpenVPN.
eno2 — a sub-rede deve ser obrigatoriamente maior que tun0. Caso contrário, os clientes OpenVPN não poderão acessar os endereços IPv6 locais.
Para melhor visualização, escolhi um passo de sub-rede de 16, mas se desejado, pode-se até fazer um passo de «1».
Portanto, 64+16 = 80, e 80+16 = 96.

Para ainda mais clareza:
XXXX:XXXX:XXXX:XXXX:1:1:YYYY:YYYY — são os endereços que devem ser atribuídos a sites ou serviços específicos na interface eno1.
XXXX:XXXX:XXXX:XXXX:1:2:YYYY:YYYY — são os endereços que devem ser atribuídos a sites ou serviços específicos na interface eno2.
XXXX:XXXX:XXXX:XXXX:1:3:YYYY:YYYY — são os endereços que devem ser atribuídos a clientes OpenVPN ou utilizados como endereços de serviço OpenVPN.

Para configurar a rede — deve haver a possibilidade de reiniciar o servidor.
As alterações em IPv4 são aplicadas ao executar (certifique-se de usar o screen — caso contrário, este comando simplesmente derrubará a rede no servidor):

/etc/init.d/networking restart

Adicionar ao final do arquivo «/etc/iproute2/rt_tables»:

100 eno1t
101 eno2t

Sem isso, não é possível usar tabelas personalizadas no arquivo «/etc/network/interfaces».
Os números devem ser únicos e menores que 65535.

As mudanças em IPv6 são alteradas facilmente sem reiniciar, mas para isso é necessário aprender pelo menos três comandos:

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

Configuração 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

Estas são as configurações de «sysctl» do meu servidor. Vou destacar o importante.

net.ipv4.ip_forward = 1

Sem isso, o OpenVPN não funcionará de forma alguma.

net.ipv6.ip_nonlocal_bind = 1

Qualquer um que tentar fazer bind IPv6 (por exemplo, nginx) imediatamente após o interface ser configurada — receberá um erro. Dado que tal endereço não está disponível.

Para evitar tal situação, é esta configuração que está sendo feita.

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

Sem estas configurações, o tráfego IPv6 dos clientes OpenVPN não sairá para o mundo.

Outras configurações ou não são relevantes ou eu não me lembro para que servem.
Mas, por via das dúvidas, deixo «como está».

Para que as alterações deste arquivo sejam aplicadas sem reiniciar o servidor — deve-se executar o comando:

sysctl -p

Mais detalhes sobre regras de «table»: habr.com/post/108690

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

OpenVPN IPv4 não funciona sem iptables.

Minhas regras iptables para VPN são as seguintes:

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 — este é o meu endereço IPv4 estático da máquina local.
10.8.0.0/24 — rede IPv4 do OpenVPN. Endereços IPv4 para os clientes do OpenVPN.
A sequência das regras é 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 é uma restrição para que apenas eu, com meu IP estático, possa usar o OpenVPN.

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

Para encaminhar pacotes IPv4 entre clientes OpenVPN e a Internet, é necessário executar um desses comandos.

Para diferentes situações, uma das opções pode não ser adequada.
Para minha situação, ambas as comandos são adequadas.
Após ler a documentação, escolhi a primeira opção, pois ela consome menos CPU.

Para que todas as configurações do iptables sejam aplicadas após a reinicialização, é necessário salvá-las em algum lugar.

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

Esses nomes não foram escolhidos por acaso. Eles são usados pelo pacote "iptables-persistent".

apt-get install iptables-persistent

Instalação do pacote principal do OpenVPN:

apt-get install openvpn easy-rsa

Vamos configurar o modelo para os certificados (substitua seus valores):

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

Vamos editar as configurações do modelo dos certificados:

mcedit vars

...
# Esses são os valores padrão para os campos
# que serão colocados no certificado.
# Não deixe nenhum desses campos em branco.
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 assunto X509
export KEY_NAME="server"
...

Criamos o certificado do servidor:

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

Prepararemos a possibilidade de criar os arquivos finais "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 um script que irá fundir todos os arquivos em um único arquivo 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

Criamos o primeiro cliente OpenVPN:

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

O arquivo "~/client-configs/files/client-name.ovpn" é enviado para o dispositivo do cliente.

Para clientes iOS, será necessário fazer um truque:
O conteúdo da tag "tls-auth" deve estar sem comentários.
E também colocar "key-direction 1" imediatamente antes da tag "tls-auth".

Vamos configurar o arquivo de configuração do 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

Isso é necessário para atribuir um endereço estático a cada cliente (não é obrigatório, mas eu utilizo):

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

A parte mais complexa e crucial.

Infelizmente, o OpenVPN ainda não consegue configurar automaticamente o gateway IPv6 para os clientes.
É preciso "manualmente" encaminhar isso 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"

Arquivo "/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

Arquivo "/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 os scripts utilizam o arquivo "/etc/openvpn/variables":

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

Por que está escrito assim — não consigo lembrar.

Agora parece estranho netmask = 112 (deveria ser 96).
E o prefixo é estranho, não corresponde à rede tun0.
Mas tudo bem, deixo "como está".

cipher DES-EDE3-CBC

Isso é questão de gosto — eu escolhi esse método de criptografia da conexão.

Mais detalhes sobre a configuração do OpenVPN IPv4.

Mais detalhes sobre a configuração do OpenVPN IPv6.

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

Instalação do pacote principal:

apt-get install postfix

Ao instalar, selecionar "internet-site".

Meu "/etc/postfix/main.cf" fica assim:

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

# a tarefa de adicionar .domain é do MUA.
append_dot_mydomain = no

readme_directory = no

# Veja http://www.postfix.org/COMPATIBILITY_README.html -- padrão para 2 em
# novas instalações.
compatibility_level = 2

# Parâmetros 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 armazenamento
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

# Configurações 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

# Endereço IP por domínio
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Vamos ver os detalhes desta configuração.

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

De acordo com os participantes do Habr, este bloco contém `desinformação e teses incorretas`.Somente após 8 anos de minha carreira eu comecei a entender como funciona o SSL.

Portanto, eu me atrevo a descrever como usar o SSL (sem responder às questões ‘Como isso funciona?’ e ‘Por que isso funciona?’).

A base da criptografia moderna é a criação de um par de chaves (duas cadeias de caracteres muito longas).

Uma chave é privada, a outra chave é pública. A chave privada deve ser mantida em segurança total em segredo. A chave pública é distribuída para todos que desejam.

Usando a chave pública, é possível criptografar uma string de texto de modo que somente o proprietário da chave privada consiga decifrá-la.
E essa é toda a base da tecnologia.

Passo nº 1 — sites https.
Quando o navegador acessa um site, ele descobre a partir do servidor web que o site é https e, portanto, solicita a chave pública.
O servidor web fornece a chave pública. O navegador usa a chave pública para criptografar a http-request e enviá-la.
O conteúdo da http-request só pode ser lido por quem tem a chave privada, ou seja, apenas o servidor ao qual a solicitação é feita.
A http-request contém pelo menos o URI. Portanto, se um país tenta restringir o acesso não a todo o site, mas a uma página específica — para sites https isso é impossível.

Passo nº 2 — resposta criptografada.
O servidor web dá uma resposta que pode ser facilmente lida ao longo do caminho.
A solução é extremamente simples — o navegador localmente forma um par de chaves privada-pública para cada site https.
E junto com a solicitação da chave pública do site, envia sua chave pública local.
O servidor web a memoriza e, ao enviar a http-response, criptografa com essa chave pública de um cliente específico.
Agora a http-response pode ser descryptografada apenas pelo proprietário da chave privada do navegador do cliente (ou seja, o próprio cliente).

Passo nº 3 — estabelecimento de uma conexão segura por meio de um canal público.
No exemplo nº 2 há uma vulnerabilidade — nada impede que pessoas bem-intencionadas interceptem a http-request e editem as informações sobre a chave pública.
Assim, o intermediário verá todo o conteúdo das mensagens enviadas e recebidas até que o canal de comunicação mude.
Lidar com isso é extremamente simples — basta enviar a chave pública do navegador como uma mensagem criptografada com a chave pública do servidor web.
O servidor web, então, primeiro envia uma resposta do tipo "sua chave pública é esta" e criptografa essa mensagem com a mesma chave pública.
O navegador verifica a resposta — se a mensagem "sua chave pública é esta" chegou — isso é 100% garantia de que este canal de comunicação é seguro.
Quão seguro é?
A criação de um canal de comunicação seguro ocorre a uma velocidade de ping*2. Por exemplo, 20ms.
Um invasor deve ou ter de antemão a chave privada de uma das partes. Ou descobrir a chave privada em poucos milissegundos.
Hackear uma chave privada moderna levaria décadas em um supercomputador.

Passo nº 4 — banco de dados público de chaves públicas.
É claro que toda essa história apresenta uma oportunidade para um invasor que está no canal de comunicação entre cliente e servidor.
A possibilidade de o cliente se apresentar como servidor e o servidor como cliente. E simular um par de chaves em ambas as direções.
Assim, o invasor verá todo o tráfego e terá a capacidade de "editar" o tráfego.
Por exemplo, alterar o endereço para o qual enviar dinheiro ou copiar a senha do banco online ou bloquear conteúdo "indesejado".
Para combater esses invasores, foi criada uma base de dados pública com chaves públicas para cada site https.
Cada navegador "sabe" da existência de cerca de 200 dessas bases de dados. Isso está pré-instalado em cada navegador.
"O conhecimento" é reforçado pela chave pública de cada certificado. Ou seja, não é possível falsificar a conexão com cada centro de certificação específico.

Agora há uma compreensão simples de como usar SSL para https.
Se pensar um pouco, ficará claro como os serviços secretos podem explorar essa estrutura. Mas isso exigirá um esforço monstruoso.
Para organizações menores que a NSA ou a CIA — é praticamente impossível quebrar o nível de proteção existente, mesmo para VIPs.

Vou adicionar algo sobre conexões ssh. Não há chaves públicas, como resolver isso. A questão é resolvida de duas maneiras.
Opção ssh por senha:
Na primeira conexão, o cliente ssh deve avisar que aqui temos uma nova chave pública do servidor ssh.
E em conexões futuras, se aparece a mensagem "nova chave pública do servidor ssh" — isso significará que estão tentando escutar você.
Ou na primeira conexão você foi escutado, e agora está se comunicando com o servidor sem intermediários.
Na verdade, devido ao fato de que a escuta é facilmente, rapidamente e sem esforço descoberta — este tipo de ataque é utilizado apenas em casos especiais para um cliente específico.

Opção ssh por chave:
Pegue um pen drive, grave nele a chave privada para o servidor ssh (para isso existem termos e várias nuances importantes, mas estou fazendo uma apresentação, não um guia de uso).
Deixe a chave pública na máquina onde estará o cliente ssh e mantenha-a em segredo também.
Leve o pen drive ao servidor, insira, copie a chave privada, e depois queime o pen drive e espalhe as cinzas ao vento (ou pelo menos formate com preenchimento de zeros).
E é isso — após tal operação, será impossível invadir uma conexão SSH desse tipo. Claro que em 10 anos, com supercomputadores, pode-se analisar o tráfego — mas isso é outra história.

Peço desculpas pelo off-topic.

Então, agora que a teoria está clara, vou falar sobre o fluxo de criação do certificado SSL.

Com o comando “openssl genrsa”, criamos a chave privada e “modelos” para a chave pública.
Os “modelos” são enviados a uma empresa externa, pela qual pagamos cerca de $9 pelo certificado mais simples.

Depois de algumas horas, recebemos dessa empresa externa a nossa “chave pública” e um conjunto de várias chaves públicas.

Por que pagar a uma empresa externa para formalizar minha chave pública — essa é uma questão separada, que não vamos abordar aqui.

Agora fica claro o que significa a inscrição:

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

Na pasta “\/etc\/ssl” estão armazenados todos os arquivos para questões SSL.
domain1.com — o nome do domínio.
2018 — o ano de criação das chaves.
“key” — indica que o arquivo é uma chave privada.

E o significado deste arquivo:

smtpd_tls_cert_file=\/etc\/ssl\/domain1.com.2018.chained.crt
domain1.com — o nome do domínio.
2018 — o ano de criação das chaves.
chained — indica que aqui há uma cadeia de chaves públicas (a primeira — nossa chave pública e as outras — o que veio da empresa que formalizou a chave pública).
crt — indica que aqui está um certificado pronto (chave pública com explicações técnicas).

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

Essa configuração não é utilizada neste caso, mas está escrita como exemplo.

Porque um erro nesse parâmetro levará ao envio de spam do seu servidor (sem sua vontade).

Depois, você terá que provar a todos que não é culpado.

recipient_delimiter = +

Talvez muitos não saibam, mas este é o símbolo padrão para classificar e-mails, e é suportado pela maioria dos servidores de e-mail modernos.

Por exemplo, se você tem uma caixa de correio “username@gmail.com”, tente enviar para “username+spam@gmail.com” — veja o que acontece.

inet_protocols = ipv4

Isso pode confundir.

Mas não é por acaso. Cada novo domínio — por padrão apenas IPv4, depois habilito o IPv6 para cada um separadamente.

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

Aqui definimos que todo o e-mail recebido vai para o dovecot.
E as regras para domínio, caixa de correio, alias — consultar no banco de dados.

/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

Agora o postfix sabe que pode aceitar correio para envio apenas com autenticação do dovecot.

Não consigo entender por que isso precisa ser duplicado aqui. Já indicamos no "virtual_transport" tudo o que é necessário.

Mas o sistema postfix é muito antigo — provavelmente são remendos de tempos passados.

smtpd_recipient_restrictions =
        ...

smtpd_helo_restrictions =
        ...

smtpd_client_restrictions =
        ...

Isso precisa ser configurado de maneira diferente para cada servidor de correio.

Eu tenho 3 servidores de correio e essas configurações variam bastante devido a diferentes requisitos de uso.

As configurações devem ser feitas cuidadosamente — caso contrário, o spam fluíra para você ou, pior ainda, você começará a enviar spam.

# SPF
policyd-spf_time_limit = 3600

Configuração para algum plugin relacionado à verificação de SPF de e-mails recebidos.

# 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

Configuração para que todos os e-mails enviados sejam acompanhados por uma assinatura DKIM.

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

Esse é um detalhe crucial na roteirização de e-mails ao enviar através de scripts PHP.

Arquivo "/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:

À esquerda — expressões regulares. À direita — a marca que identifica o e-mail.
O postfix, de acordo com a marca, levará em consideração mais algumas linhas de configuração para um e-mail específico.

Como o postfix será reconfigurado para um e-mail específico será indicado em "master.cf".

As linhas 4, 5, 6 — são as principais. O nome do domínio a partir do qual enviamos um e-mail determina a marca que usamos.
Mas nem sempre em scripts PHP no código antigo o campo "from" é especificado. Então, o nome de usuário ajuda.

O artigo é bastante extenso — eu não gostaria de me distrair com a configuração do nginx+fpm.

Resumindo — para cada site, definimos um proprietário linux-user. E, consequentemente, seu próprio fpm-pool.

O fpm-pool usa qualquer versão do php (isso é ótimo, pois em um único servidor, sem problemas, podemos usar diferentes versões do php e até diferentes php.ini para sites vizinhos).

Assim, o usuário linux específico "www-domain2" tem o site domain2.com. Nesse site, há código para envio de e-mails sem especificar o campo from.

Mesmo assim, os e-mails serão enviados corretamente e nunca cairão em spam.

Meu "/etc/postfix/master.cf" está assim:

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

O arquivo não está completo - já é muito grande.
Marquei apenas o que foi alterado.

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}

Essas são configurações relacionadas ao spamassassin, falaremos sobre isso mais tarde.

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

Autorizamos a conexão ao servidor de e-mail pela porta 587.
Para isso, é necessário fazer a autenticação.

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

Ativamos a verificação de SPF.

apt-get install postfix-policyd-spf-python

Vamos instalar o pacote para as verificações 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

E isso é o mais interessante. Isso permite enviar e-mails para um domínio específico de um endereço IPv4/IPv6 específico.

Isso é feito para o rDNS. rDNS é a obtenção de uma string pelo endereço IP.
E para o e-mail, essa capacidade é usada para confirmar que o helo corresponde ao rDNS do endereço de onde o e-mail foi enviado.

Se o helo não corresponder ao domínio do e-mail de quem enviou a mensagem, pontos de spam são atribuídos.

Helo não corresponde ao rDNS - muitos pontos de spam são atribuídos.
Assim, cada domínio deve ter seu próprio endereço IP.
Para OVH - na console há possibilidade de visualizar o rDNS.
Para tech.ru - o suporte resolve essa questão.
Para AWS - o suporte também resolve essa questão.
«inet_protocols» e «smtp_bind_address6» — aqui ativamos o suporte a IPv6.
Para IPv6 também é necessário configurar o rDNS.
«syslog_name» — isso é para facilitar a leitura dos logs.

Comprar certificados recomendo aqui.

Configuração da combinação postfix+dovecot aqui.

Configuração do SPF.

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

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

Configuração do mysql, instalamos os pacotes por conta própria.

Arquivo «/etc/dovecot/conf.d/10-auth.conf»

disable_plaintext_auth = yes
auth_mechanisms = plain login

Autorização apenas em formato criptografado.

Arquivo «/etc/dovecot/conf.d/10-mail.conf»

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

Aqui iremos especificar o local de armazenamento das mensagens.

Quero que elas sejam armazenadas em arquivos e agrupadas por domínios.

Arquivo «/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 é o arquivo principal de configurações do dovecot.
Aqui desativamos as conexões não seguras.
E ativamos conexões seguras.

Arquivo «/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 o ssl. Especificamos que o ssl — é obrigatório.
E o próprio certificado. E um detalhe importante — a diretiva «local». Indica, ao se conectar a qual IPv4 local — qual certificado ssl utilizar.

Aliás, o IPv6 não está configurado aqui, vou corrigir essa omissão algum dia.
XX.XX.XX.X5 (domain2) — não há certificado. Para a conexão de clientes, deve-se indicar domain1.com.
XX.XX.XX.X2 (domain3) — há certificado, para a conexão de clientes pode-se indicar domain1.com ou domain3.com.

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

protocol lda {
  mail_plugins = $mail_plugins sieve
}

Isso será necessário para o spamassassin mais tarde.

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

protocol imap {
  mail_plugins = $mail_plugins antispam
}

Este é o plugin antispam. É necessário para treinar o spamassassin no momento da movimentação para/de a pasta «Spam».

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

protocol pop3 {
}

Apenas existe esse arquivo.

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

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

Configuração lmtp.

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

Configurações de aprendizado do spamassassin durante a movimentação para/de a pasta «Spam».

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

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

Arquivo que especifica o que fazer com os e-mails recebidos.

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

require ["fileinto", "mailbox"];

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

É necessário compilar o arquivo: «sievec default.sieve».

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

Especificação de arquivos sql para autenticação.
E o próprio arquivo - como forma de autenticação.

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

Isso corresponde a configurações análogas para postfix.

Arquivo «/etc/dovecot/dovecot.conf»

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

Arquivo de configuração principal.
Importante notar que especificamos/adicionamos protocolos aqui.

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

apt-get install spamassassin spamc

Vamos instalar os pacotes.

adduser spamd --disabled-login

Adicionaremos um usuário sob o qual operará.

systemctl enable spamassassin.service

Ativamos o carregamento automático do serviço spamassassin na inicialização.

Arquivo «/etc/default/spamassassin»:

CRON=1

Ativamos a atualização automática de regras «por padrão».

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

É necessário criar no MySQL o banco de dados «sa» com o usuário «sa» e a senha «password» (substituir por algo adequado).

report_safe - em vez do e-mail, será enviado um relatório sobre o e-mail de spam.
use_bayes - esta configuração é para o aprendizado de máquina do spamassassin.

As demais configurações do spamassassin foram aplicadas anteriormente no artigo.

Configuração geral do «spamassassin».
Sobre a movimentação de novos e-mails de spam para a pasta IMAP «Spam».
Sobre a integração simples do Dovecot + SpamAssassin.
Recomendo para leitura a teoria do aprendizado do spamassassin ao mover e-mails entre pastas IMAP (e não recomendo a aplicação).

============= Apelo à comunidade =============

Gostaria também de lançar uma ideia na comunidade sobre como aumentar o nível de segurança das mensagens enviadas. Já que me aprofundei tanto no tema de e-mail.

Para que o usuário possa criar um par de chaves em seu cliente (outlook, thunderbird, plugin de navegador, …). Uma chave pública a ser enviada ao DNS. A chave privada será mantida no cliente. Os servidores de e-mail deverão ser capazes de aplicar a chave pública para enviar a um destinatário específico.

E para proteger contra spam em tais mensagens (sim, o servidor de e-mail não poderá verificar o conteúdo) — será necessário introduzir 3 regras:

  1. Assinatura DKIM verdadeira obrigatória, SPF obrigatório, rDNS obrigatório.
  2. Uma rede neural para o aprendizado de antispam + um banco de dados relacionado no lado do cliente.
  3. O algoritmo de criptografia deve ser tal que a parte que envia gaste 100 vezes mais capacidade de CPU para criptografar do que a parte que recebe.

Além de mensagens públicas — desenvolver um padrão para a mensagem de proposta de "iniciar uma comunicação segura". Um dos usuários (caixa de correio) envia a outro caixa de correio uma mensagem com um anexo. Na mensagem, o texto propõe iniciar um canal seguro de comunicação e incluir a chave pública do proprietário da caixa de correio (com a chave privada permanecendo do lado do cliente).

É possível até criar um par de chaves especificamente para cada comunicação. O usuário receptor pode aceitar essa proposta e enviar sua chave pública (também criada especificamente para esta comunicação). Em seguida, o primeiro usuário envia uma mensagem de controle (criptografada com a chave pública do segundo usuário) — ao recebê-la, o segundo usuário pode considerar o canal de comunicação formado como confiável. Depois, o segundo usuário envia uma mensagem de controle — e assim o primeiro usuário também pode considerar o canal formado como seguro.

Para combater a interceptação de chaves pelo caminho — o protocolo deve prever a possibilidade de transmitir pelo menos uma chave pública por meio de um pen drive.

E o mais importante — para que tudo isso funcione (a questão "quem vai pagar por isso?"):
Introduzir certificados de e-mail a partir de 10$ por 3 anos. Que permitirão ao remetente indicar no DNS que "minhas chaves públicas estão ali". Isso permitirá iniciar uma conexão segura, aceitando tais conexões gratuitamente.
O Gmail finalmente monetiza seus usuários. Por 10$ em 3 anos — o direito de criar canais de conversa protegidos.

============= Conclusão =============

Para testar todo o artigo, eu planejava alugar um servidor dedicado por um mês e comprar um domínio com um certificado SSL.

Mas as circunstâncias da vida fizeram com que essa questão se estendesse por 2 meses.
E agora que finalmente tenho tempo livre, decidi publicar o artigo como está, e não correr o risco de que a publicação demore mais um ano.

Se houver muitas perguntas como "aqui não está suficientemente detalhado" — talvez eu consiga alugar um servidor dedicado com um novo domínio e um novo certificado SSL e descrever tudo com mais detalhes, além de destacar todos os detalhes importantes que faltaram.

Gostaria também de receber opiniões sobre a ideia dos certificados de e-mail. Se a ideia for bem recebida, farei o possível para escrever um rascunho para o RFC.

Ao copiar grandes trechos do artigo — indicar o link para este artigo.
Ao traduzir para qualquer outro idioma — indicar o link para este artigo.
Eu mesmo tentarei traduzir para o inglês e deixarei links cruzados.


Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster