Migración de servidores mail a Postfix con Dovecot y autenticación LDAP
Introducción
La migración de un servidor de correo electrónico es, sin duda, una de las tareas más críticas y delicadas en la administración de sistemas. Un error puede significar la pérdida de correos, downtime para toda la organización o, peor aún, la inclusión del dominio en listas negras (RBL). Este artículo detalla el proceso de migración hacia una stack moderna y altamente escalable: Postfix como MTA (Mail Transfer Agent), Dovecot como MDA (Mail Delivery Agent) y servidor IMAP/POP3, y OpenLDAP como backend de autenticación y almacenamiento de cuentas de usuario.
El objetivo es proporcionar una guía paso a paso, explicando no solo el cómo sino el por qué de cada decisión técnica, para que el ingeniero pueda adaptar la solución a su infraestructura específica. Asumiremos una migración desde un servidor legacy (por ejemplo, Exim con cuentas locales Unix o un servidor propietario) hacia un entorno virtualizado o bare-metal moderno.
Alerta de producción: Este proceso debe realizarse en un entorno de pruebas (staging) idéntico al de producción antes de la migración real. Asegúrate de tener backups completos y verificados de los buzones, configuración y base de datos LDAP.
Justificación de la Arquitectura
Antes de comenzar, es crucial entender por qué esta combinación es el estándar de facto en el alojamiento compartido y empresarial.
| Componente | Rol | Ventaja clave |
|---|---|---|
| Postfix | MTA (Recepción/Envío) | Seguro, modular, rápido, fácil de integrar con políticas externas (milter). |
| Dovecot | MDA/IMAP/POP3 | Rendimiento excepcional, cuotas de buzón, indexación nativa, soporte para clustering (director). |
| OpenLDAP | Backend de autenticación | Centralización de cuentas, escalabilidad horizontal, integración con otros servicios (web, VPN). |
¿Por qué LDAP y no una base de datos SQL? Aunque MySQL/MariaDB es viable, LDAP está diseñado específicamente para operaciones de lectura intensivas (autenticación, búsqueda de cuentas) y soporta jerarquías (dominios, usuarios, alias) de forma nativa. Para un ISP o empresa con miles de buzones, LDAP ofrece un rendimiento de consulta superior y una estructura de árbol que refleja la organización de los dominios.
Fase 0: Preparación del Entorno y Backup
1. Inventario del Sistema Legacy
Identifica todos los componentes del servidor actual:
- MTA actual: Exim, Sendmail, Qmail.
- MDA/IMAP: Courier, UW-IMAP, Dovecot antiguo.
- Formato de buzón:
mbox(un solo archivo por usuario) oMaildir(archivos por mensaje). La migración a Maildir es fuertemente recomendada. - Autenticación:
/etc/passwd,MySQL,LDAPo archivos de texto. - Alias y listas de correo: Archivos
/etc/aliases,virtual_alias_maps. - Reglas de filtrado: Procmail, Sieve, scripts de servidor.
- Certificados SSL/TLS: Rutas y fechas de expiración.
- Registros DNS: MX, SPF, DKIM, DMARC. Fundamental para no perder reputación.
2. Backup Completo
Ejecuta los siguientes comandos en el servidor legacy (ajusta rutas según tu sistema):
# Backup de buzones (ejemplo para Maildir)
tar -czf /backup/maildirs_$(date +%Y%m%d).tar.gz /var/mail/
# Backup de configuraciones del MTA actual
tar -czf /backup/exim_config_$(date +%Y%m%d).tar.gz /etc/exim/
# Backup de bases de datos de usuarios (si usa MySQL)
mysqldump --all-databases --single-transaction --quick --routines > /backup/mysql_$(date +%Y%m%d).sql
# Backup de LDAP (si ya existe)
slapcat -l /backup/ldap_$(date +%Y%m%d).ldif
Nota crítica: Verifica la integridad de los backups con
tar -tzf backup.tar.gz | head -20ymysqlcheck --all-databasesdespués de la restauración en un entorno de pruebas.
Fase 1: Instalación y Configuración Base de Postfix
Instalamos Postfix con soporte para LDAP, SASL y TLS.
# Debian/Ubuntu
apt-get update
apt-get install postfix postfix-ldap postfix-pcre sasl2-bin libsasl2-modules-ldap
# CentOS/RHEL/Rocky
dnf install postfix postfix-ldap cyrus-sasl cyrus-sasl-ldap cyrus-sasl-plain
Configuración Principal (main.cf)
El archivo /etc/postfix/main.cf debe ser configurado para usar LDAP como origen de datos de buzones virtuales.
# main.cf - Postfix Configuration File
# =====================================
# Identificación del servidor
myhostname = mail.sysprovider.com
mydomain = sysprovider.com
myorigin = $mydomain
# Interfaces de escucha
inet_interfaces = all
inet_protocols = ipv4
# Modo de entrega: virtual (buzones en LDAP)
virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf
virtual_mailbox_maps = ldap:/etc/postfix/ldap-mailboxes.cf
virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf
# Usuario y grupo virtual para los buzones (debe existir en el sistema)
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
# Directorio base de los buzones
virtual_mailbox_base = /var/mail/vhosts
# Configuración del transporte (opcional, para forzar entrega a Dovecot)
virtual_transport = lmtp:unix:private/dovecot-lmtp
# Restricciones de seguridad
smtpd_helo_required = yes
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
# Autenticación SASL (Dovecot actuará como servidor SASL)
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
# TLS
smtpd_tls_cert_file = /etc/ssl/certs/mail.sysprovider.com.pem
smtpd_tls_key_file = /etc/ssl/private/mail.sysprovider.com.key
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
Archivos de Mapeo LDAP
Cada archivo .cf en /etc/postfix/ define cómo Postfix consulta LDAP.
/etc/postfix/ldap-domains.cf (dominios aceptados):
server_host = ldap://localhost:389
search_base = dc=sysprovider,dc=com
query_filter = (&(objectClass=mailDomain)(mailDomain=%s))
result_attribute = mailDomain
bind = yes
bind_dn = cn=admin,dc=sysprovider,dc=com
bind_pw = contraseña_segura
/etc/postfix/ldap-mailboxes.cf (buzones de usuario):
server_host = ldap://localhost:389
search_base = ou=users,dc=sysprovider,dc=com
query_filter = (&(objectClass=mailUser)(mail=%s))
result_attribute = mailRoutingAddress
# O si usas Dovecot con LMTP, devuelve el usuario local
# result_attribute = mailLocalAddress
bind = yes
bind_dn = cn=admin,dc=sysprovider,dc=com
bind_pw = contraseña_segura
Explicación:
mailRoutingAddresscontiene la dirección de entrega real (ej:usuario@sysprovider.com), que Postfix usará para buscar envirtual_mailbox_maps. Si usamos LMTP, Dovecot maneja la entrega y Postfix solo necesita saber que el dominio es válido.
Fase 2: Instalación y Configuración de Dovecot
Dovecot manejará la entrega (via LMTP), el almacenamiento IMAP/POP3 y la autenticación SASL para Postfix.
apt-get install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-ldap
Configuración Principal (dovecot.conf)
Mantén la configuración modular en /etc/dovecot/dovecot.conf:
# Protocolos habilitados
protocols = imap pop3 lmtp
# Autenticación
auth_mechanisms = plain login
!include auth-ldap.conf.ext
# Localización de buzones
mail_location = maildir:/var/mail/vhosts/%d/%n
# Cuotas
mail_plugins = quota
plugin {
quota = maildir:User quota
quota_rule = *:storage=1G
quota_rule2 = Trash:storage=10%%
}
# LMTP para recepción desde Postfix
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
# Autenticación SASL para Postfix
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
group = vmail
}
}
Archivo de Autenticación LDAP (auth-ldap.conf.ext)
Crea el archivo /etc/dovecot/conf.d/auth-ldap.conf.ext:
passdb {
driver = ldap
args = /etc/dovecot/dovecot-ldap.conf.ext
}
userdb {
driver = ldap
args = /etc/dovecot/dovecot-ldap.conf.ext
# Si usas static, omite el userdb LDAP para uid/gid
# driver = static
# args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
Configuración de Conexión LDAP (dovecot-ldap.conf.ext)
hosts = localhost:389
dn = cn=admin,dc=sysprovider,dc=com
dnpass = contraseña_segura
auth_bind = yes
base = ou=users,dc=sysprovider,dc=com
scope = subtree
# Mapeo de atributos
user_attrs = =home=/var/mail/vhosts/%d/%n,=uid=vmail,=gid=vmail
user_filter = (&(objectClass=mailUser)(mail=%u))
pass_filter = (&(objectClass=mailUser)(mail=%u))
# Iteración de usuarios (para listas)
iterate_attrs = mail=user
iterate_filter = (objectClass=mailUser)
Nota importante sobre
auth_bind: Al habilitarauth_bind = yes, Dovecot no necesita la contraseña del usuario en texto claro. En su lugar, intenta autenticarse directamente contra LDAP con las credenciales del usuario. Esto es más seguro, pero requiere que el usuario exista en LDAP y que el servidor LDAP permita binds anónimos o con la DN del usuario.
Fase 3: Diseño e Implementación del Esquema LDAP
La estructura LDAP debe reflejar dominios y usuarios. Un esquema mínimo pero funcional:
# Dominio
dn: dc=sysprovider,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: Sysprovider Inc.
dc: sysprovider
# Unidad de Usuarios
dn: ou=users,dc=sysprovider,dc=com
objectClass: organizationalUnit
ou: users
# Unidad de Grupos (para alias)
dn: ou=groups,dc=sysprovider,dc=com
objectClass: organizationalUnit
ou: groups
# Ejemplo de Usuario
dn: uid=jdoe,ou=users,dc=sysprovider,dc=com
objectClass: inetOrgPerson
objectClass: mailUser
uid: jdoe
cn: John Doe
sn: Doe
mail: jdoe@sysprovider.com
mailRoutingAddress: jdoe@sysprovider.com
userPassword: {SSHA}hash_de_contraseña
mailQuota: 1073741824
Atributos personalizados vs estándar: Puedes usar mailUser como clase auxiliar y definir atributos como mailRoutingAddress y mailQuota. Alternativamente, usa inetLocalMailRecipient del esquema mail.schema. La clave es la consistencia.
Poblar LDAP desde el Sistema Legacy
Si los usuarios estaban en /etc/passwd o MySQL, escribe un script para migrarlos. Ejemplo en Python usando ldap3:
import ldap3
import crypt
# Conexión LDAP
server = ldap3.Server('localhost', port=389, get_info=ldap3.ALL)
conn = ldap3.Connection(server, 'cn=admin,dc=sysprovider,dc=com', 'password', auto_bind=True)
# Leer usuarios desde un archivo CSV
with open('users.csv', 'r') as f:
for line in f:
username, domain, password_hash = line.strip().split(',')
dn = f'uid={username},ou=users,dc=sysprovider,dc=com'
attrs = {
'objectClass': ['inetOrgPerson', 'mailUser'],
'uid': username,
'cn': username,
'sn': username,
'mail': f'{username}@{domain}',
'mailRoutingAddress': f'{username}@{domain}',
'userPassword': password_hash, # Asegúrate de que sea {SSHA} o {CRYPT}
'mailQuota': '1073741824'
}
conn.add(dn, attributes=attrs)
Advertencia de seguridad: Nunca almacenes contraseñas en texto plano. Usa
slappasswd -h {SSHA}para generar hashes o migra desde sistemas que ya usen{CRYPT}.
Fase 4: Migración de Buzones (mbox a Maildir)
Este es el paso más intensivo en recursos. La herramienta mb2md o imapsync son las opciones estándar.
Opción A: Migración Offline con mb2md (Recomendada para pequeños volúmenes)
# Instalar mb2md
apt-get install mb2md
# Convertir buzón de usuario 'jdoe' de mbox a Maildir
mb2md -s /var/mail/jdoe -d /var/mail/vhosts/sysprovider.com/jdoe -R
# Ajustar permisos
chown -R vmail:vmail /var/mail/vhosts/sysprovider.com/jdoe
chmod -R 700 /var/mail/vhosts/sysprovider.com/jdoe
Opción B: Migración Online con imapsync (Sin Downtime)
imapsync sincroniza buzones IMAP de un servidor a otro. Es ideal si ambos servidores pueden estar activos simultáneamente.
# Instalar imapsync
apt-get install imapsync
# Sincronizar usuario 'jdoe' desde servidor antiguo (imap.old.com) al nuevo
imapsync \
--host1 imap.old.com --user1 jdoe --password1 'pass_antigua' --ssl1 \
--host2 localhost --user2 jdoe@siprovider.com --password2 'pass_nueva' --ssl2 \
--noauthmd5 --nofoldersizes --skipsize --delete2 --expunge2
Explicación de flags:
--delete2 --expunge2elimina en el destino los mensajes que ya no están en el origen, asegurando una réplica exacta.--skipsizeacelera la sincronización inicial al no comparar tamaños.
Fase 5: Configuración de Autenticación SASL y TLS
Dovecot como Proveedor SASL
Ya configuramos el socket de autenticación en dovecot.conf. Asegúrate de que Postfix tenga el socket en su chroot:
# Crear directorio si no existe
mkdir -p /var/spool/postfix/private
