Servidor de correo en VPS
En la actualidad, existen muchas soluciones en el mercado que te permiten enviar correos desde tu aplicación (Mailgun
, Postmark
, etc.), sin embargo, todos son productos “freemium” y tienen una cantidad limitada de correos mensuales, que en la mayoría de los casos es suficiente para un proyecto pequeño. Pero, debido a algunos problemas técnicos con las plataformas 😅, tuve que optar por instalar mi propio servicio de correo electrónico.
Objetivo
Instalar un servicio de correo electrónico en un VPS
con Ubuntu 22.04
que me permita enviar correos desde una aplicación alojada en el mismo servidor, en un subdominio diferente.
Proceso
El proceso es relativamente sencillo:
- Tener un dominio vigente.
- Configurar un registro tipo
MX
en elDNS
de tu proveedor de dominios. - Instalar y habilitar el servicio de postfix en el servidor.
Sin embargo, la teoría no siempre es perfecta. Me encontré con diversos factores que hicieron larga la instalación y configuración del servicio.
Reto 1: Seguridad del servicio Postfix
Por fortuna de todos, los frameworks de desarrollo tienen restricciones que te impiden usar servicios con seguridad baja o nula. Tal es el caso de mi aplicación, la cual no me permite usar el servicio de SMTP
si no tiene una encriptación TLS
y, por ende, requería de un certificado SSL
.
Para ello, me apoyé del tutorial de upcloud (que por cierto, es extremadamente bueno 🌟), pero un par de inconvenientes causaron un retraso de un par de horas.
Tan solo agregaría dos puntos importantes:
Punto de refuerzo 1 - Habilitar submission
Submission
es uno procesos que vienen en el paquete de instalación de postfix
, pero, viene deshabilitado por defecto. Su función es escuchar peticiones de aplicaciones de terceros para
enviar un correo electrónico cuándo estas lo soliciten.
Para habilitarlo:
- Debemos editar el archivo
/etc/postfix/master.cf
- Quitar el comentario de la entrada del proceso
submission
(o agregar la línea completa en caso de que no exista), quedando de la siguiente manera:
submission inet n - y - - smtpd
Punto de refuerzo 2 - Habilitar los puertos de postfix en el firewall
En caso de tener algún firewall activo, es importante que permitas el acceso a los puertos de email. En mi caso, usando ufw
, logré esto con los siguientes comandos:
$ ufw allow Postfix
$ ufw allow "Postfix SMTP"
$ ufw allow "Postfix Submission"
Reto 2: [Configuración de Laravel] - host
Para poder enviar notificaciones por correo electrónico que traía mi aplicación por defecto, se requiere especificar los siguientes datos:
Driver=smtp
Host=
Port=
User=
Password=
Encryption=
El servidor, en teoría, podría ser suplido por los valores 127.0.0.1
o localhost
. Sin embargo, esto causó bastantes problemas porque el servicio de portfix
está configurado para rechazar peticiones cuyo host difiera del dominio principal. Para solucionarlo:
- Debemos modificar el archivo
/etc/postfix/main.cf
- En la entrada
mydestination
, debemos agregar el dominio esperado, ejemplo:
mydestination = example.com, mail.example.com, $mydomain, $myhostname, localhost.$myhostname, localhost.com, , localhost
Agregamos el texto:
mail.example.com, $mydomain, $myhostname, localhost.$myhostname
Reto 3: [Configuración de Laravel] - Usuario y contraseña
En el post compartido por upcloud
, se asume que conocemos el funcionamiento del servicio postfix
, ya que su intención es la instalación y configuración. Sin embargo, para poder utilizarlo en mi aplicación, es necesario proporcionar un usuario y contraseña.
Como dato curioso: cada usuario creado en linux genera su propio usuario de correo electrónico, compuesto por
{USER_NAME}@{POSTFIX_DOMAIN}
, por ejemplo, si creamos un usuarioanne_droid
y asumiendo que el dominio configurado en postfix esexample.com
, su correo por defecto seríaanne_droid@example.com
.
Para solucionar este punto, bastó con ejecutar las siguientes instrucciones en la terminal:
- Crear un usuario que no requirere login:
$ adduser -s /sbin/nologin {USERNAME};
- Establecer una contraseña de usuario
$ passwd {USERNAME}
Una vez creado, tanto el usuario como la contraseña, la aplicación se configuró con estos valores.
Reto 3: Los correos no llegaban 😢
Finalmente, el servicio de correo electrónico parecía configurado y no arrojaba ningún error al enviar correos, pero estos jamás llegaban.
Investigando un poco, los registros de correo electrónico suelen encontrarse en /var/log/mail.log
y gracias a ellos descubrí que el servicio estaba siendo rechazado por Google
con el error:
550-5.7.26 This mail is unauthenticated, which poses a security risk to the sender and Gmail users, and has been blocked. The sender must authenticate with at least one of SPF or DKIM.
La documentación de Google
explica cómo resolver este problema desde Google Workspace
, pero no tiene secciones para la configuración de terceros.
Después de buscar información en algunos sitios, todo se resume a lo siguiente:
Se deben implementar 3 estándares de seguridad para pasar los filtros de Google
, cada uno equivale a una entrada TXT
en el proveedor de dominios y DNS
.
SPF (Sender Policy Framework)
Ayuda a prevenir la suplantación de identidad, permitiendo especificar qué servidores están autorizados para enviar correos en nombre de tu dominio.
Basta con agregar un registro en la tabla de DNS
con los siguientes datos:
- Tipo:
TXT
- Host:
@
- Valor:
v=spf1 mx -all
- TTL:
Automatic
|60 Min
Es importante mencionar que esta entrada es genérica, pero se puede mejorar muchísimo creando un registro personalizado usando la palabra include
que permite especificar que solo cierto dominio puede enviar correos, por ejemplo:
v=spf1 include:example.com ~all
Que cumpliría con el mismo proposito.
DKIM (DomainKeys Identified Mail)
Permite asociar un dominio con un mensaje de correo electrónico, lo que permite a una organización responsabilizarse del mensaje.
Probablemente el más complejo de todos, consta de 3 pasos:
- Instalar el servicio
opendkim
yopendkim-tools
.
$ apt-get install opendkim opendkim-tools
- Crear un par de llaves usando:
$ mkdir -p /etc/opendkim/keys
$ cd /etc/opendkim/keys
$ opendkim-genkey -b 2048 -h rsa-sha256 -r -v -s default -d example.com
Esto generará 2 archivos: un default.private
, que se usará de forma interna, y un default.txt, cuyo contenido se va a usar en el siguiente paso.
- Configurar el archivo
/etc/opendkim.conf
, en específico los siguientes valores:
Mode sv
Domain example.com
Selector default # Important for the DNS record
KeyFile /etc/opendkim/keys/default.private #{KEY_PATH}
- Revisar el contenido de la llave
default.txt
que tiene un formato similar al siguiente:
default._domainkey IN TXT ( "v=DKIM1; h=rsa-sha256; k=rsa; s=email; "
"p=long_text_1"
"long_text_2" ) ; ----- DKIM key default for example.com
- Ir al proveedor de
DNS
y agregar un nuevo registro:
- Tipo:
TXT
- Host:
default._domainkey
- Valor:
v=DKIM1; h=rsa-sha256; k=rsa; s=email; p=long_text_1long_text_2
- TTL:
Automatic
|60 Min
Importante: En este paso, default._domainkey puede cambiar dependiendo del selector que se usó en la configuración del archivo
/etc/opendkim.conf
, por ejemplo, si escribímos2020
como selector, el valor deHost
deberá cambiar a2020._domainkey
.
Importante: Al igual que se modificó el contenido del archivo
default.txt
para agregarlo al registroDNS
, hay que prestar atención al valor dep
que concatenó ambas cadenas sin espacios (long_text_1
ylong_text_2
) y eliminó por completo las comillas y los saltos de línea del archivo original.
DMARC (Domain-based Message Authentication, Reporting, and Conformance)
Especifica cómo los receptores deben tratar los correos que no pasan las comprobaciones de SPF y DKIM.
Se corrige agregando un registro en la tabla de DNS
con los siguientes datos:
- Tipo:
TXT
- Host:
@
- Valor:
v=DMARC1; p=none; rua=mailto:info@example.com
- TTL:
Automatic
|60 Min
En dónde:
p
: Especifica la acción a realizar y puede tener los valores:none
,quarantine
oreject
según tus necesidades.rua
: Es un correo al cuál se puede dirigir en caso de ser necesario.
Resultados y conclusión
Una vez realizada esta serie de pasos, el servicio de correo electrónico quedó totalmente configurado y listo para su uso con mi aplicación interna.
Lo que me gustaría destacar, extrayendo la información esencial de los recursos utilizados, son los pasos a seguir para configurar un servicio smtp de forma segura:
- Contar con un
dominio
y acceso al panel de configuración deDNS
. - Agregar registros
MX
para el correo electrónico. - Instalar los servicios
postfix
ydovecot
. Puedes usar la guia de upclod para facilitar la instalación. - Instalar un
certificado SSL
. Te puedes apoyar de let’s encrypt y certbot para ello. - Configurar los certificados
SSL
enpostfix
. - Habilitar el proceso
submission
depostfix
. - Habilitar los puertos de
postfix
en tufirewall
. - Implementar el estándar
SPF
. - Implementar el estándar
DKIM
. - Implementar el estándar
DMARC
. - Probar la configuración auxiliándose del de
mail-utils
y el archivo/var/log/mail.log
. - Crear un usuario exclusivo para correo (que puede ser usado por tu aplicación).
El proceso es mucho más complejo de lo esperado, pero espero que esta guía haga un poco más ameno este proceso para todos nosotros.