Postfix es el agente de transferencia de correo (MTA) que usan por defecto Debian y Ubuntu: acepta correo de otros servidores en el puerto 25, lo entrega en los buzones locales y envía el correo saliente al resto de internet. En este tutorial configurarás Postfix en Ubuntu 24.04 para que reciba el correo de your_domain en buzones Maildir, envíe correo que supere las comprobaciones SPF, DKIM y DMARC de Gmail y Outlook, y use un certificado de Let's Encrypt para TLS. Los clientes de correo (IMAP y envío autenticado por el puerto 587) se añaden con Dovecot en la guía siguiente.

Requisitos previos

Para seguir este tutorial necesitas:

  • Un servidor con Ubuntu 24.04 LTS y una dirección IPv4 pública, por ejemplo un VPS de CubePath. Lo mejor es un servidor limpio; no instales Postfix junto a otro MTA.
  • Un usuario no root con privilegios sudo. Esta guía usa your_user como el buzón que recibe el correo.
  • Un dominio que controles (your_domain) y acceso a su zona DNS.
  • La posibilidad de configurar el registro DNS inverso (PTR) de la IP del servidor.
  • El puerto TCP 25 de salida abierto. En CubePath, como en la mayoría de proveedores cloud, el puerto 25 de salida está cerrado por defecto para evitar el spam; abre un ticket de soporte describiendo el uso que harás del correo para solicitarlo. El paso 1 explica cómo comprobarlo.

A lo largo de la guía, sustituye your_domain por tu dominio, mail.your_domain por el nombre del servidor de correo y your_server_ip por su IPv4 pública.

Paso 1: Configurar el nombre del servidor y comprobar el puerto 25

Los servidores de correo se identifican por su nombre en cada conversación SMTP, y los servidores que reciben comprueban que el nombre, la IP y el DNS inverso coinciden. Asigna al servidor su nombre completo:

sudo hostnamectl set-hostname mail.your_domain

Añádelo a /etc/hosts para que el servidor resuelva su propio nombre sin depender del DNS:

sudo nano /etc/hosts
127.0.1.1 mail.your_domain mail

Comprueba el resultado:

hostname -f
mail.your_domain

Ahora comprueba que el puerto 25 de salida está abierto conectando con el servidor de correo entrante de Gmail:

nc -vz -w 5 gmail-smtp-in.l.google.com 25
Connection to gmail-smtp-in.l.google.com (142.250.x.x) 25 port [tcp/smtp] succeeded!

Si el comando agota el tiempo de espera, el SMTP saliente está bloqueado. Puedes terminar la instalación y recibir correo, pero no podrás entregarlo a otros servidores hasta que se abra.

Paso 2: Crear los registros DNS

Crea estos registros en la zona DNS de tu dominio. El registro DKIM se añade más adelante, en el paso 7, cuando exista la clave.

TipoNombreValorPara qué sirve
Amail.your_domainyour_server_ipResuelve el servidor de correo
MXyour_domain10 mail.your_domainIndica a otros servidores dónde entregar el correo del dominio
TXTyour_domainv=spf1 mx ~allSPF: solo los servidores MX pueden enviar en nombre del dominio
TXT_dmarc.your_domainv=DMARC1; p=none; rua=mailto:postmaster@your_domainPolítica e informes DMARC

Configura el registro PTR (DNS inverso) de your_server_ip para que apunte a mail.your_domain. El DNS inverso pertenece a quien gestiona la dirección IP, así que se configura a través de tu proveedor de hosting y no en la zona de tu dominio. Sin un PTR que coincida, Gmail y Outlook rechazan tu correo o lo mandan a spam.

~all (fallo suave) y p=none son valores seguros para empezar mientras haces pruebas. Cuando los informes DMARC muestren que todo el correo legítimo pasa las comprobaciones, endurécelos a -all y a p=quarantine o p=reject.

Comprueba los registros desde el servidor. Los cambios de DNS pueden tardar unos minutos en propagarse:

dig +short MX your_domain
dig +short A mail.your_domain
dig +short -x your_server_ip
dig +short TXT your_domain
10 mail.your_domain.
your_server_ip
mail.your_domain.
"v=spf1 mx ~all"

Paso 3: Instalar Postfix

Actualiza el índice de paquetes e instala Postfix:

sudo apt update
sudo apt install postfix

El instalador hace dos preguntas:

  • General mail configuration type: elige Internet Site.
  • System mail name: escribe your_domain (no mail.your_domain). Este valor se guarda en /etc/mailname y se convierte en el dominio del correo que envían los usuarios locales, de modo que your_user envía como your_user@your_domain.

Postfix arranca automáticamente. Comprueba que escucha en el puerto 25:

sudo ss -ltnp | grep ':25 '
LISTEN 0      100          0.0.0.0:25        0.0.0.0:*    users:(("master",pid=2215,fd=13))
LISTEN 0      100             [::]:25           [::]:*    users:(("master",pid=2215,fd=14))

Si te has equivocado en alguna opción, ejecuta sudo dpkg-reconfigure postfix para responder de nuevo.

Paso 4: Obtener un certificado TLS

Los demás servidores de correo cifran la conexión con STARTTLS cuando el tuyo lo ofrece, y Gmail marca el correo de los servidores que no usan TLS. Obtén un certificado gratuito para mail.your_domain con Let's Encrypt. El modo standalone de Certbot levanta su propio servidor web temporal en el puerto 80, así que antes permite SSH y HTTP en el cortafuegos:

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

Instala Certbot y solicita el certificado. El hook de despliegue recarga Postfix tras cada renovación automática para que use los archivos nuevos:

sudo apt install certbot
sudo certbot certonly --standalone -d mail.your_domain --deploy-hook "systemctl reload postfix"

Certbot guarda el certificado en /etc/letsencrypt/live/mail.your_domain/ e instala un temporizador de systemd que lo renueva. Prueba la renovación:

sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/mail.your_domain/fullchain.pem (success)

Paso 5: Configurar Postfix

Los ajustes principales de Postfix están en /etc/postfix/main.cf. En lugar de editar el archivo a mano, usa postconf -e, que cambia un único parámetro y evita líneas duplicadas. Primero haz una copia del original:

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

Define el nombre del servidor y los dominios para los que acepta correo:

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

Entrega el correo en una carpeta Maildir dentro del directorio personal de cada usuario. Maildir guarda un archivo por mensaje y es el formato que usará Dovecot en la guía siguiente. Vaciar mailbox_command garantiza que ningún programa de entrega externo lo sustituya:

sudo postconf -e "home_mailbox = Maildir/"
sudo postconf -e "mailbox_command ="

Indica a Postfix el certificado de Let's Encrypt y activa TLS oportunista en ambos sentidos:

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"

may es lo correcto para el correo entre servidores en el puerto 25: se usa TLS siempre que el otro extremo lo admita, y el correo de los pocos servidores que no lo admiten se sigue aceptando.

Añade restricciones básicas que rechazan remitentes claramente mal configurados o falsificados antes de aceptar el mensaje:

sudo postconf -e "smtpd_helo_required = yes"
sudo postconf -e "disable_vrfy_command = yes"
sudo postconf -e "smtpd_helo_restrictions = permit_mynetworks, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname"
sudo postconf -e "smtpd_sender_restrictions = permit_mynetworks, 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 que el servidor sea un relay abierto: solo los procesos locales pueden enviar a dominios externos. Déjalo como está.

Si el servidor tiene más de una IPv4 pública, fija el correo saliente a la que tiene el PTR mail.your_domain:

sudo postconf -e "smtp_bind_address = your_server_ip"

Comprueba que la configuración no tiene errores y recarga:

sudo postfix check
sudo systemctl reload postfix

postfix check no muestra nada cuando todo está bien. Revisa todos los ajustes que difieren de los valores por defecto con:

postconf -n

Paso 6: Configurar alias y recibir correo

El correo para postmaster@your_domain y root@your_domain tiene que llegar a una persona: ahí van los informes DMARC y los avisos de rebote. Abre el archivo de alias:

sudo nano /etc/aliases
postmaster: root
root: your_user

Regenera la base de datos de alias:

sudo newaliases

Ahora envía un mensaje desde una cuenta externa, como Gmail, a your_user@your_domain y sigue el log mientras llega:

sudo tail -f /var/log/mail.log

Una entrega correcta termina con una línea como esta:

postfix/local[3120]: 4XbQ2K1d7Wz9sWb: to=<your_user@your_domain>, relay=local, delay=0.12, delays=0.08/0.01/0/0.03, dsn=2.0.0, status=sent (delivered to maildir)

Pulsa Ctrl+C para dejar de seguir el log. El mensaje queda guardado como archivo en el Maildir del usuario:

ls ~/Maildir/new/

Postfix crea el directorio Maildir en la primera entrega, así que no existe antes de que llegue el primer mensaje.

Paso 7: Firmar el correo saliente con DKIM

DKIM añade una firma criptográfica a cada mensaje saliente, y los servidores que lo reciben la verifican con una clave pública publicada en DNS. Junto con SPF, es lo que permite que DMARC dé un resultado positivo. OpenDKIM firma el correo y Postfix le pasa los mensajes a través de la interfaz milter.

Instala OpenDKIM:

sudo apt install opendkim opendkim-tools

Genera un par de claves de 2048 bits con el selector default:

sudo mkdir -p /etc/opendkim/keys/your_domain
sudo opendkim-genkey -b 2048 -d your_domain -D /etc/opendkim/keys/your_domain -s default -v
sudo chown -R opendkim:opendkim /etc/opendkim/keys

Esto crea default.private (la clave privada) y default.txt (el registro DNS). Abre la configuración de OpenDKIM:

sudo nano /etc/opendkim.conf

Busca la línea existente Socket local:/run/opendkim/opendkim.sock y coméntala con #. Después añade estas líneas al final del archivo:

Domain      your_domain
Selector    default
KeyFile     /etc/opendkim/keys/your_domain/default.private
Socket      inet:8891@localhost

Un socket TCP en localhost evita problemas de permisos con Postfix, que en Ubuntu ejecuta su servidor SMTP dentro de un chroot. Reinicia OpenDKIM y comprueba que escucha:

sudo systemctl restart opendkim
sudo ss -ltnp | grep 8891
LISTEN 0      4096       127.0.0.1:8891      0.0.0.0:*    users:(("opendkim",pid=4012,fd=3))

Conecta Postfix con OpenDKIM. non_smtpd_milters hace que también se firme el correo enviado localmente con sendmail, y milter_default_action = accept mantiene el flujo de correo si OpenDKIM está caído:

sudo postconf -e "milter_default_action = accept"
sudo postconf -e "smtpd_milters = inet:localhost:8891"
sudo postconf -e "non_smtpd_milters = \$smtpd_milters"
sudo systemctl reload postfix

Publica la clave pública. Muestra el registro generado:

sudo cat /etc/opendkim/keys/your_domain/default.txt

El archivo divide la clave en varias cadenas entre comillas. En tu panel DNS, crea un registro TXT llamado default._domainkey.your_domain cuyo valor sea todas esas cadenas unidas, sin comillas ni espacios entre ellas, empezando por v=DKIM1; h=sha256; k=rsa; p= seguido de la clave.

Cuando el registro se haya propagado, compruébalo:

sudo opendkim-testkey -d your_domain -s default -vvv
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'default._domainkey.your_domain'
opendkim-testkey: key not secure
opendkim-testkey: key OK

key not secure solo significa que la zona no está firmada con DNSSEC. La línea que importa es key OK.

Paso 8: Probar el correo saliente

Envía un mensaje de prueba a un buzón externo que puedas leer, como una dirección de Gmail. El comando sendmail lo proporciona Postfix:

printf 'Subject: Prueba de Postfix\n\nHola desde mail.your_domain.\n' | sendmail -f your_user@your_domain [email protected]

Busca el resultado en el log:

sudo grep 'status=' /var/log/mail.log | tail -n 3
postfix/smtp[4410]: 4XbQ7m2Hc1z9sWd: to=<[email protected]>, relay=gmail-smtp-in.l.google.com[142.250.x.x]:25, delay=1.2, delays=0.05/0.01/0.4/0.7, dsn=2.0.0, status=sent (250 2.0.0 OK ...)

status=sent con dsn=2.0.0 significa que el servidor de destino aceptó el mensaje. En Gmail, abre el mensaje, elige Mostrar original y comprueba que SPF, DKIM y DMARC aparecen como PASS.

Solución de problemas

  • connect to ...:25: Connection timed out en el log: el puerto 25 de salida está bloqueado. Compruébalo como en el paso 1 y solicita su apertura a tu proveedor. Los mensajes se quedan en la cola y se reintentan automáticamente; consúltalos con mailq y fuerza un reintento con sudo postqueue -f.
  • El correo se rechaza o llega a spam: comprueba que el registro PTR coincide con myhostname (dig +short -x your_server_ip) y lee en Mostrar original qué comprobación falla. Si el servidor también tiene IPv6, el PTR y el SPF deben cubrir también la dirección IPv6, o limita Postfix a IPv4 con sudo postconf -e "inet_protocols = ipv4" seguido de sudo systemctl restart postfix.
  • Relay access denied al recibir: el dominio de la dirección de destino no está en mydestination.
  • status=bounced (unknown user: ...): no existe ningún usuario de Linux ni alias con ese nombre. Crea el usuario o añade un alias en /etc/aliases y ejecuta sudo newaliases.
  • DKIM no firma: busca líneas de opendkim en /var/log/mail.log. Si los mensajes salientes no generan una línea DKIM-Signature field added, lo habitual es que el dominio del From no coincida con el valor de Domain en /etc/opendkim.conf.

Conclusión

Tu servidor acepta ahora correo para your_domain en el puerto 25, lo guarda en Maildir y envía correo por TLS con un registro PTR válido, SPF, DKIM y DMARC. El siguiente paso es instalar Dovecot para que los usuarios lean el correo por IMAP y envíen a través del servidor desde un cliente de correo en el puerto 587 con autenticación. Después, plantéate añadir filtrado de spam con Rspamd y pasar la política DMARC a p=quarantine cuando los informes estén limpios.