Postfix y Dovecot juntos forman un servidor de correo completo: Postfix intercambia correo con otros servidores por SMTP, y Dovecot lo almacena, lo sirve a los clientes de correo por IMAP y comprueba las contraseñas de ambos. En este tutorial montarás ese conjunto en Ubuntu 24.04 con buzones virtuales, es decir, cuentas de correo como admin@your_domain que no son usuarios de Linux. Postfix entrega el correo entrante a Dovecot por LMTP, Dovecot autentica a los clientes para IMAP y para el envío por el puerto 587, y añadir un usuario o un dominio completo se reduce a editar dos archivos de texto.

Requisitos previos

Para seguir este tutorial necesitas:

  • Un servidor recién instalado con Ubuntu 24.04 LTS y una IPv4 pública, por ejemplo un VPS de CubePath, y un usuario no root con privilegios sudo.
  • Un dominio (your_domain) con estos registros DNS: un registro A para mail.your_domain que apunte a your_server_ip, un registro MX de your_domain que apunte a mail.your_domain, un registro SPF (v=spf1 mx ~all) y un registro DMARC en _dmarc.your_domain.
  • El DNS inverso (PTR) de your_server_ip configurado como mail.your_domain, a través de tu proveedor de hosting.
  • El puerto TCP 25 de salida abierto. En CubePath, como en la mayoría de proveedores cloud, está cerrado por defecto; solicítalo con un ticket de soporte que describa el uso que harás del correo.

La guía "Cómo montar un servidor de correo Postfix en Ubuntu 24.04" explica en detalle los registros DNS, la comprobación del puerto 25 y la firma DKIM. Este tutorial se centra en las partes en las que Postfix y Dovecot se conectan.

Así encajan las piezas:

TráficoPuertoQuién lo gestiona
Correo de otros servidores25smtpd de Postfix, y después LMTP hacia Dovecot
Correo que envían tus usuarios587 (STARTTLS)smtpd de Postfix, con la contraseña comprobada por el SASL de Dovecot
Clientes que leen el correo993 (IMAPS)IMAP de Dovecot
Entrega de Postfix a DovecotSocket Unix private/dovecot-lmtpLMTP de Dovecot
Autenticación de Postfix contra DovecotSocket Unix private/authServicio auth de Dovecot

Paso 1: Configurar el nombre del servidor y obtener un certificado

Asigna al servidor el nombre que aparece en tu registro MX:

sudo hostnamectl set-hostname mail.your_domain

Añade el nombre a /etc/hosts para que se resuelva localmente:

sudo nano /etc/hosts
127.0.1.1 mail.your_domain mail

Activa el cortafuegos con SSH y los puertos que necesita este servidor. Certbot usa el puerto 80 para demostrar que controlas el dominio:

sudo ufw allow OpenSSH
sudo ufw allow 25/tcp
sudo ufw allow 80/tcp
sudo ufw allow 587/tcp
sudo ufw allow 993/tcp
sudo ufw enable

Instala Certbot y obtén un certificado para mail.your_domain en modo standalone:

sudo apt update
sudo apt install certbot
sudo certbot certonly --standalone -d mail.your_domain

Postfix y Dovecot solo leen el certificado al arrancar, así que hay que recargarlos tras cada renovación. Certbot ejecuta todos los ejecutables de su directorio de hooks deploy después de una renovación correcta:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
#!/bin/sh
systemctl reload postfix dovecot
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh

Comprueba que la renovación funciona:

sudo certbot renew --dry-run

Paso 2: Instalar Postfix y Dovecot

Instala Postfix, el núcleo de Dovecot, el servidor IMAP y el servidor LMTP:

sudo apt install postfix dovecot-core dovecot-imapd dovecot-lmtpd

Cuando el instalador de Postfix pregunte, elige Internet Site y escribe mail.your_domain como System mail name. En una configuración de buzones virtuales, your_domain lo sirve Dovecot, así que no debe tratarse como el dominio local del sistema.

Comprueba que ambos servicios están en marcha:

systemctl is-active postfix dovecot
active
active

Paso 3: Crear el usuario de almacenamiento del correo

Todos los buzones virtuales se guardan bajo un mismo directorio y pertenecen a un único usuario del sistema sin privilegios, vmail. Crea el grupo y el usuario con el ID fijo 5000:

sudo groupadd --system --gid 5000 vmail
sudo useradd --system --uid 5000 --gid vmail --home-dir /var/mail/vhosts --no-create-home --shell /usr/sbin/nologin vmail

Crea el directorio de almacenamiento y asígnalo a vmail:

sudo mkdir -p /var/mail/vhosts
sudo chown vmail:vmail /var/mail/vhosts
sudo chmod 770 /var/mail/vhosts

El correo de usuario@dominio se guardará en /var/mail/vhosts/dominio/usuario/ en formato Maildir. Dovecot crea las carpetas de cada dominio y usuario en la primera entrega.

Paso 4: Configurar Postfix para dominios virtuales

Haz una copia del archivo de configuración principal:

sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.orig

Define el nombre del servidor y limita mydestination a los nombres propios de la máquina. Si incluyeras your_domain aquí, Postfix lo entregaría a usuarios de Linux en lugar de a Dovecot:

sudo postconf -e "myhostname = mail.your_domain"
sudo postconf -e "mydestination = \$myhostname, localhost.localdomain, localhost"

Indica a Postfix qué dominios y direcciones son virtuales y que los entregue a Dovecot por LMTP. La ruta del socket es relativa al directorio de spool de Postfix, /var/spool/postfix:

sudo postconf -e "virtual_mailbox_domains = hash:/etc/postfix/vdomains"
sudo postconf -e "virtual_mailbox_maps = hash:/etc/postfix/vmailbox"
sudo postconf -e "virtual_alias_maps = hash:/etc/postfix/virtual"
sudo postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"

Usa Dovecot para la autenticación SASL:

sudo postconf -e "smtpd_sasl_type = dovecot"
sudo postconf -e "smtpd_sasl_path = private/auth"

Configura TLS con el certificado de Let's Encrypt. may ofrece STARTTLS en el puerto 25 sin rechazar a los pocos servidores que no pueden usarlo:

sudo postconf -e "smtpd_tls_cert_file = /etc/letsencrypt/live/mail.your_domain/fullchain.pem"
sudo postconf -e "smtpd_tls_key_file = /etc/letsencrypt/live/mail.your_domain/privkey.pem"
sudo postconf -e "smtpd_tls_security_level = may"
sudo postconf -e "smtp_tls_security_level = may"

Añade comprobaciones básicas a las conexiones entrantes:

sudo postconf -e "smtpd_helo_required = yes"
sudo postconf -e "disable_vrfy_command = yes"
sudo postconf -e "smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname"
sudo postconf -e "smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain"

El valor por defecto de smtpd_relay_restrictions en Ubuntu (permit_mynetworks permit_sasl_authenticated defer_unauth_destination) ya impide el relay abierto, así que déjalo como está.

Crear las tablas de búsqueda

Crea la lista de dominios virtuales. El valor que sigue al dominio se ignora, pero es obligatorio poner uno:

sudo nano /etc/postfix/vdomains
your_domain    OK

Crea la lista de buzones. Cada dirección apunta a sí misma: virtual_mailbox_maps solo necesita que exista la clave, y el valor se reutiliza en el paso 5 para decidir qué usuario puede enviar como qué dirección:

sudo nano /etc/postfix/vmailbox
admin@your_domain    admin@your_domain

Crea los alias. Todo dominio necesita postmaster y abuse, y aquí ambos van a admin:

sudo nano /etc/postfix/virtual
postmaster@your_domain    admin@your_domain
abuse@your_domain         admin@your_domain

Postfix lee versiones compiladas de estos archivos. Genéralas con postmap:

sudo postmap /etc/postfix/vdomains
sudo postmap /etc/postfix/vmailbox
sudo postmap /etc/postfix/virtual

Redirige el correo de las cuentas locales del sistema, como root (tareas cron, actualizaciones de seguridad), al buzón de administración:

sudo nano /etc/aliases
postmaster: root
root: admin@your_domain
sudo newaliases

Paso 5: Activar el puerto de envío

Los usuarios envían correo por el puerto 587, donde la autenticación es obligatoria. Abre la tabla de servicios de Postfix:

sudo nano /etc/postfix/master.cf

El archivo de Ubuntu incluye un bloque submission comentado. Sustitúyelo por este. Las líneas que empiezan por -o deben ir sangradas:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_sender_login_maps=hash:/etc/postfix/vmailbox
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_sender_restrictions=reject_sender_login_mismatch
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

Qué hacen estas opciones:

  • smtpd_tls_security_level=encrypt exige STARTTLS antes de cualquier otro comando.
  • smtpd_sasl_auth_enable=yes activa la autenticación solo en este puerto. El puerto 25 nunca acepta contraseñas.
  • smtpd_sender_login_maps junto con reject_sender_login_mismatch impide que un usuario autenticado envíe en nombre de otro. Como vmailbox asocia cada dirección consigo misma, admin@your_domain solo puede enviar como admin@your_domain.

Comprueba la configuración de Postfix:

sudo postfix check

Si no muestra nada, no hay errores. Postfix se reinicia en el paso 7, cuando Dovecot ya ofrezca los sockets que necesita.

Paso 6: Configurar Dovecot

La configuración de Dovecot está en /etc/dovecot/conf.d/. Vas a modificar cinco archivos.

Ubicación del correo

Abre los ajustes de correo:

sudo nano /etc/dovecot/conf.d/10-mail.conf

Establece como ubicación el árbol de buzones virtuales. %d es el dominio y %n la parte de usuario del login:

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

Autenticación

Abre los ajustes de autenticación:

sudo nano /etc/dovecot/conf.d/10-auth.conf

Establece las opciones siguientes. Al final del archivo, comenta el backend de usuarios del sistema y activa el de archivo de contraseñas:

disable_plaintext_auth = yes
auth_mechanisms = plain login

#!include auth-system.conf.ext
!include auth-passwdfile.conf.ext

Ahora define ese backend. Abre su archivo y sustituye todo su contenido:

sudo nano /etc/dovecot/conf.d/auth-passwdfile.conf.ext
passdb {
  driver = passwd-file
  args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/users
}

userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

El passdb comprueba las contraseñas contra /etc/dovecot/users, usando como clave la dirección completa (%u). El userdb asigna a todas las cuentas el mismo propietario del sistema, vmail, y un directorio personal derivado de la dirección, así no tienes que repetirlo para cada usuario. Dovecot sigue usando el archivo de contraseñas para comprobar que un usuario existe antes de aceptar correo para él.

TLS

Abre los ajustes de SSL:

sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.your_domain/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.your_domain/privkey.pem
ssl_min_protocol = TLSv1.2

El < delante de cada ruta indica a Dovecot que lea el contenido del archivo.

Sockets para Postfix

Abre las definiciones de servicios:

sudo nano /etc/dovecot/conf.d/10-master.conf

Sustituye el bloque service lmtp para que el socket LMTP se cree dentro del spool de Postfix, donde pueden alcanzarlo los procesos de Postfix que se ejecutan en chroot:

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

En el bloque service auth, descomenta y completa el socket de autenticación para Postfix:

service auth {
  unix_listener auth-userdb {
    #mode = 0666
    #user =
    #group =
  }

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

Carpetas por defecto

Abre las definiciones de buzones:

sudo nano /etc/dovecot/conf.d/15-mailboxes.conf

Añade auto = subscribe a los bloques Drafts, Junk, Trash y Sent para que todas las cuentas nuevas los tengan. Por ejemplo:

  mailbox Sent {
    auto = subscribe
    special_use = \Sent
  }

Paso 7: Crear el primer buzón y arrancar los servicios

Genera el hash de la contraseña de admin@your_domain. El comando pide la contraseña dos veces y muestra el hash:

sudo doveadm pw -s SHA512-CRYPT
Enter new password:
Retype new password:
{SHA512-CRYPT}$6$Xk2Qb0yY3m6n5R9s$Qm8...

Crea el archivo de contraseñas:

sudo nano /etc/dovecot/users

Añade una línea por buzón: la dirección completa, dos puntos y el hash que acabas de generar:

admin@your_domain:{SHA512-CRYPT}$6$Xk2Qb0yY3m6n5R9s$Qm8...

Solo Dovecot debe poder leerlo:

sudo chown root:dovecot /etc/dovecot/users
sudo chmod 640 /etc/dovecot/users

Comprueba la configuración de Dovecot. doveconf -n termina con un mensaje de error si algún archivo tiene un fallo:

sudo doveconf -n > /dev/null && echo "Dovecot config OK"

Reinicia primero Dovecot, para que existan los sockets, y después Postfix:

sudo systemctl restart dovecot
sudo systemctl restart postfix

Confirma que se han creado los dos sockets con el propietario correcto:

sudo ls -l /var/spool/postfix/private/auth /var/spool/postfix/private/dovecot-lmtp
srw-rw---- 1 postfix postfix 0 Sep 25 12:10 /var/spool/postfix/private/auth
srw------- 1 postfix postfix 0 Sep 25 12:10 /var/spool/postfix/private/dovecot-lmtp

Paso 8: Probar el flujo completo

Prueba cada eslabón de la cadena por separado, para que un fallo apunte a un único componente.

Autenticación y búsqueda de usuario

Comprueba la contraseña y los datos de usuario que usará Dovecot:

sudo doveadm auth test admin@your_domain
sudo doveadm user admin@your_domain
passdb: admin@your_domain auth succeeded
extra fields:
  user=admin@your_domain

field	value
uid	5000
gid	5000
home	/var/mail/vhosts/your_domain/admin

Entrega local por LMTP

Envía un mensaje al alias postmaster. Postfix debería expandirlo a admin@your_domain y pasárselo a Dovecot:

printf 'Subject: Prueba LMTP\n\nLa entrega funciona.\n' | sendmail postmaster@your_domain

Revisa el log:

sudo grep -E 'lmtp|saved mail' /var/log/mail.log | tail -n 3
postfix/lmtp[7021]: 4XbS0q2Hc1z9sWg: to=<admin@your_domain>, orig_to=<postmaster@your_domain>, relay=mail.your_domain[private/dovecot-lmtp], delay=0.08, dsn=2.0.0, status=sent (250 2.0.0 <admin@your_domain> 8cB2FIr7c2ZtGwAAqL9Tyg Saved)
dovecot: lmtp(admin@your_domain)<7023><8cB2FIr7c2ZtGwAAqL9Tyg>: msgid=<[email protected]_domain>: saved mail to INBOX

Confirma el número de mensajes del buzón:

sudo doveadm mailbox status -u admin@your_domain messages INBOX
INBOX messages=1

Leer el correo por IMAP

Abre una sesión IMAP sobre TLS e inicia sesión con la dirección completa. Sustituye your_password por la contraseña real:

openssl s_client -connect mail.your_domain:993 -quiet
a LOGIN admin@your_domain your_password
b SELECT INBOX
c LOGOUT
a OK [CAPABILITY ...] Logged in
* 1 EXISTS
...
b OK [READ-WRITE] Select completed.

Enviar por el puerto de envío

Instala swaks, una herramienta de pruebas SMTP de línea de comandos, y envía un mensaje a un buzón externo por el puerto 587. Te pedirá la contraseña:

sudo apt install swaks
swaks --to [email protected] --from admin@your_domain --server mail.your_domain --port 587 --tls --auth LOGIN --auth-user admin@your_domain
<-  250 2.0.0 Ok: queued as 4XbS3d5Kq1z9sWh
 -> QUIT
<-  221 2.0.0 Bye

Prueba a enviar como una dirección que no te pertenece para confirmar que la comprobación del remitente funciona:

swaks --to [email protected] --from ceo@your_domain --server mail.your_domain --port 587 --tls --auth LOGIN --auth-user admin@your_domain
<** 553 5.7.1 <ceo@your_domain>: Sender address rejected: not owned by user admin@your_domain

Por último, envía un mensaje desde Gmail u Outlook a admin@your_domain y comprueba que llega con doveadm mailbox status como antes. Así confirmas que el registro MX, el puerto 25 y la entrega por LMTP funcionan de extremo a extremo.

Paso 9: Añadir usuarios y dominios

Para añadir un buzón, genera un hash con sudo doveadm pw -s SHA512-CRYPT y después:

  1. Añade una línea usuario@your_domain:{SHA512-CRYPT}... a /etc/dovecot/users. Dovecot detecta el cambio por sí solo.
  2. Añade usuario@your_domain usuario@your_domain a /etc/postfix/vmailbox y ejecuta sudo postmap /etc/postfix/vmailbox.

Para añadir otro dominio, por ejemplo example.net:

  1. Crea sus registros A, MX, SPF y DMARC.
  2. Añade example.net OK a /etc/postfix/vdomains y ejecuta sudo postmap /etc/postfix/vdomains.
  3. Añade sus alias postmaster y abuse a /etc/postfix/virtual y ejecuta sudo postmap /etc/postfix/virtual.
  4. Añade sus buzones como se describe arriba.

Postfix detecta automáticamente las tablas hash: regeneradas, así que no hace falta recargarlo. Para eliminar un buzón, borra sus líneas de ambos archivos, vuelve a ejecutar postmap y elimina /var/mail/vhosts/dominio/usuario cuando ya no necesites su correo.

Paso 10: Bloquear intentos de adivinar contraseñas con Fail2ban

Tanto el puerto 587 como el 993 recibirán intentos de adivinar contraseñas. Instala Fail2ban:

sudo apt install fail2ban

Activa sus jails incluidas para Dovecot y el SASL de Postfix:

sudo nano /etc/fail2ban/jail.d/mail.local
[dovecot]
enabled = true

[postfix-sasl]
enabled = true

Reinicia el servicio y comprueba que las jails están activas:

sudo systemctl restart fail2ban
sudo fail2ban-client status
Status
|- Number of jail:      3
`- Jail list:   dovecot, postfix-sasl, sshd

Solución de problemas

  • connect to transport private/dovecot-lmtp: No such file or directory: falta el socket LMTP. Revisa el bloque service lmtp de 10-master.conf, reinicia Dovecot y lista /var/spool/postfix/private/.
  • status=bounced (... User doesn't exist: user@your_domain): Postfix aceptó la dirección, pero Dovecot no la conoce. La dirección está en vmailbox pero falta en /etc/dovecot/users, o está escrita de forma distinta en cada archivo.
  • Recipient address rejected: User unknown in virtual mailbox table: la dirección no está en /etc/postfix/vmailbox, o no ejecutaste postmap después de editarlo.
  • Error: open(/var/mail/vhosts/...) failed: Permission denied: /var/mail/vhosts debe pertenecer a vmail:vmail. Corrígelo con sudo chown -R vmail:vmail /var/mail/vhosts.
  • SASL LOGIN authentication failed en el log de Postfix con una contraseña correcta: comprueba la parte de Dovecot con sudo doveadm auth test user@your_domain y lee sudo grep 'auth' /var/log/mail.log | tail.
  • El correo saliente se queda en la cola con Connection timed out: el puerto 25 de salida está bloqueado. Compruébalo con nc -vz -w 5 gmail-smtp-in.l.google.com 25.

Conclusión

Tienes un servidor de correo en el que Postfix acepta y reenvía el correo, Dovecot lo guarda en carpetas Maildir por dominio y autentica a los usuarios de IMAP y SMTP, y los buzones o dominios nuevos se añaden editando dos archivos. Antes de usarlo con correo real, añade la firma DKIM con OpenDKIM como se explica en la guía de Postfix, porque Gmail y Outlook la esperan. Después, plantéate filtrar el spam con Rspamd, añadir cuotas y filtros Sieve con dovecot-sieve, y hacer copias de seguridad periódicas de /var/mail/vhosts, /etc/postfix, /etc/dovecot y /etc/opendkim.