SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-07

Instalar Listmonk en un VPS con Ubuntu 24.04

Guía para instalar Listmonk v6.2.0 con PostgreSQL 16, config.toml, systemd y TLS en Ubuntu 24.04, conectar SMTP y calcular el coste real de entrega.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Qué necesita un boletín autogestionado con Listmonk

Listmonk es un gestor autogestionado de boletines y listas de correo: un binario de Go, una base de datos PostgreSQL, un archivo de configuración y una unidad de systemd. Un VPS pequeño puede ejecutarlo sin problemas, porque Listmonk almacena los suscriptores y pone en cola las campañas, pero nunca entrega el correo por sí mismo. Envía cada mensaje a un servidor SMTP (protocolo simple de transferencia de correo), por lo que la tasa de entrega depende de la reputación de ese servidor y no de este software.

Esta guía instala Listmonk v6.2.0, la versión actual en julio de 2026, en Ubuntu 24.04. Necesita un VPS con una dirección IP pública, un nombre de dominio que controle y PostgreSQL 12 o posterior. La instalación tarda aproximadamente una hora. La reputación de envío tarda semanas en establecerse, y esa parte se trata cerca del final.

Instalar PostgreSQL y crear la base de datos

Ubuntu 24.04 incluye PostgreSQL 16 en su propio repositorio, una versión muy posterior a la que necesita Listmonk.

sudo apt update
sudo apt install -y postgresql curl
sudo systemctl enable --now postgresql

Cree el rol y la base de datos en una sola sesión de psql. -v ON_ERROR_STOP=1 hace que psql termine al producirse la primera instrucción fallida, por lo que un error tipográfico no deja una configuración incompleta que parezca terminada.

sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
CREATE USER listmonk WITH PASSWORD 'pick-a-long-random-password';
CREATE DATABASE listmonk OWNER listmonk;
SQL

OWNER listmonk no es un detalle decorativo. La instalación del esquema crea tablas, tipos, índices y funciones, por lo que el rol debe ser propietario de la base de datos. Si configura Listmonk para usar una base de datos cuyo propietario es otro rol, la instalación se detiene con permission denied, incluso después de ejecutar GRANT CONNECT.

Confirme que la base de datos existe antes de continuar.

sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datname='listmonk';"

Esto muestra listmonk. Una línea vacía significa que la instrucción CREATE no se ejecutó. Vuelva a revisar la salida de psql.

Instalar el binario de Listmonk

Listmonk publica un binario estático para cada arquitectura. Compruebe primero cuál usa su sistema, porque un binario amd64 en un VPS ARM es un archivo que el kernel rechaza ejecutar.

dpkg --print-architecture
cd /tmp
curl -fsSLO https://github.com/knadh/listmonk/releases/download/v6.2.0/listmonk_6.2.0_linux_amd64.tar.gz
tar -xzf listmonk_6.2.0_linux_amd64.tar.gz
sudo install -m 755 listmonk /usr/bin/listmonk
listmonk --version

En un VPS ARM, sustituya amd64 por arm64 en el nombre del archivo. listmonk --version mostrar una cadena de versión es la primera comprobación de que el binario coincide con la máquina.

Generar config.toml y restringir su acceso

--new-config escribe config.toml en el directorio de trabajo actual. Por eso cd se encuentra dentro de sh -c y no antes de sudo.

sudo install -d -m 750 /etc/listmonk
sudo sh -c 'cd /etc/listmonk && listmonk --new-config'

El archivo generado es corto. En [app], address = "localhost:9000" vincula el servidor HTTP sólo a loopback, por lo que el panel de administración no es accesible desde Internet hasta que coloque un reverse proxy delante. No modifique esa línea. En [db] aparecen host = "localhost", port = 5432, user = "listmonk", database = "listmonk" y ssl_mode = "disable". Esos valores predeterminados ya coinciden con la base de datos que creó, por lo que sólo debe cambiar la línea de la contraseña.

ssl_mode = "disable" es correcto mientras Postgres escuche en loopback en el mismo equipo, porque ese tráfico no sale de la máquina. Si mueve la base de datos a otro host, configúrelo como require; de lo contrario, la contraseña atravesará la red en texto claro.

Edite la línea de la contraseña en [db] para que coincida con el rol. Después, cree la cuenta de servicio y quite el archivo del acceso de cualquier otro usuario.

sudo useradd --system --home-dir /var/lib/listmonk --create-home --shell /usr/sbin/nologin listmonk
sudo chown -R root:listmonk /etc/listmonk
sudo chmod 640 /etc/listmonk/config.toml

Ahora la cuenta de servicio puede leer el archivo y nadie más puede hacerlo.

sudo -u listmonk cat /etc/listmonk/config.toml > /dev/null && echo readable
stat -c '%U:%G %a' /etc/listmonk/config.toml

El primer comando muestra readable. El segundo muestra root:listmonk 640. Cualquier otra cuenta sin privilegios que intente el mismo cat obtiene Permission denied. Ese es el objetivo: este archivo contiene la contraseña de la base de datos en texto claro y un servidor normalmente tiene más de una cuenta de acceso. El mismo razonamiento se aplica a todos los servicios que ejecute, así que lea una vez sobre usuarios de servicio con privilegios mínimos y aplíquelo en todos los casos.

Cree el esquema con --install

--install crea las tablas y carga la configuración predeterminada. Defina el primer acceso de administrador mediante variables de entorno para que la cuenta exista antes de que el panel sea accesible.

sudo -u listmonk env LISTMONK_ADMIN_USER=admin \
  LISTMONK_ADMIN_PASSWORD='another-long-random-password' \
  listmonk --config /etc/listmonk/config.toml --install --yes

--yes responde a la solicitud de confirmación. Lea esa solicitud una vez antes de automatizarla, porque --install es la primera ejecución del instalador y elimina un esquema de Listmonk existente. Ejecutarlo por segunda vez en una base de datos activa destruye los suscriptores. En cualquier script que pueda ejecutarse dos veces, use --install --idempotent --yes, que no hace nada cuando las tablas ya existen. Los cambios de esquema incluidos en una versión nueva se aplican con --upgrade, nunca con --install.

Compruebe el resultado desde la base de datos, no desde el navegador.

sudo -u postgres psql -d listmonk -c '\dt'
sudo -u postgres psql -d listmonk -tAc "SELECT username FROM users;"

El primero muestra las tablas de Listmonk, entre ellas subscribers, lists, campaigns, templates y bounces. El segundo muestra admin. Un resultado vacío en el segundo comando significa que las variables de entorno nunca llegaron al proceso, por lo que el panel le pedirá crear el primer usuario en el navegador.

Ejecutar Listmonk con systemd

Escriba /etc/systemd/system/listmonk.service.

[Unit]
Description=Listmonk newsletter and mailing list manager
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=listmonk
Group=listmonk
WorkingDirectory=/var/lib/listmonk
ExecStart=/usr/bin/listmonk --config /etc/listmonk/config.toml
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

WorkingDirectory es importante porque Listmonk resuelve las rutas relativas, incluida una ruta del sistema de archivos para las cargas multimedia, en relación con ella. After=postgresql.service sólo ordena el inicio; no espera a que Postgres acepte conexiones. Por eso Restart=on-failure cubre el caso en que Listmonk se inicia demasiado pronto y no puede conectarse.

sudo systemctl daemon-reload
sudo systemctl enable --now listmonk
ss -ltnp | grep 9000
curl -sI http://127.0.0.1:9000/

ss debe mostrar 127.0.0.1:9000 en estado LISTEN. Si curl devuelve cualquier línea de estado HTTP, el servidor está respondiendo. Si curl falla con Connection refused, el proceso terminó durante el inicio y journalctl -u listmonk -n 50 --no-pager indicará el motivo. Tenga en cuenta que enable --now es la parte que sobrevive a un reinicio: un proceso iniciado manualmente desaparece tras la siguiente actualización del kernel.

Coloque nginx y TLS delante

Listmonk usa HTTP sin cifrar en loopback, por lo que nginx termina TLS (seguridad de la capa de transporte) y reenvía la solicitud.

server {
    listen 443 ssl;
    server_name lists.example.com;

    client_max_body_size 25m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

client_max_body_size debe aumentarse porque las importaciones de suscriptores y las cargas de archivos multimedia son solicitudes POST de archivos, y nginx rechaza de forma predeterminada cualquier solicitud superior a 1 MB con 413 Request Entity Too Large. Emita el certificado con certbot. certbot también escribe las líneas listen 443 ssl y configura por usted la redirección desde el puerto 80: los pasos se encuentran en la guía de certificados de Let's Encrypt para nginx. Abra los puertos 80 y 443, y mantenga cerrado el puerto 9000, porque el proxy accede a él mediante loopback. Si el firewall aún no está configurado, empiece por los conceptos básicos del firewall ufw.

A continuación, abra el panel de administración y establezca la URL raíz en Settings como https://lists.example.com. Una instalación nueva contiene http://localhost:9000, y Listmonk escribe ese valor en cada enlace de cancelación de suscripción y en cada URL multimedia que incluye en un correo electrónico. Si envía una campaña antes de cambiarlo, cada destinatario recibirá enlaces que apuntan a su propio equipo. Los enlaces no funcionarán para el lector y, para un filtro antispam, parecerán proceder de un remitente que no puede configurar su propio dominio.

Conectar SMTP, que no aparece en config.toml

Busque config.toml y no encontrará ninguna sección SMTP. La configuración del correo se almacena en la base de datos, en la tabla settings, y se edita en el panel de administración, en Settings y SMTP. Por eso el archivo generado es tan corto y también por eso un cambio de SMTP no requiere reiniciar el servicio.

Para el propio servidor SMTP hay dos opciones válidas. Puede ejecutar uno propio. En ese caso, la reputación depende completamente de usted y el proyecto requiere una administración específica: ejecutar su propio servidor de correo con Mailcow explica lo que implica. La otra opción es configurar Listmonk para usar un relay transaccional y delegar la gestión de la reputación de la IP.

En ambos casos, use el puerto 587 con STARTTLS o el puerto 465 con TLS implícito. No planifique usar el puerto saliente 25. La mayoría de los proveedores de VPS lo bloquean de forma predeterminada en las cuentas nuevas. Un puerto 25 bloqueado se comporta como una conexión bloqueada porque los paquetes se descartan en lugar de rechazarse. Por eso el cliente espera a que se agote el tiempo de espera en vez de fallar de inmediato.

Pruebe la configuración antes de confiar en ella. Cree una lista, añada su propia dirección como suscriptor y envíe una campaña a un único destinatario. Abra el mensaje recibido y lea las cabeceras completas. La cabecera Authentication-Results, añadida por el servidor receptor, indica si SPF y DKIM se validaron correctamente.

La entregabilidad es el trabajo completo

Listmonk genera el mensaje, gestiona la lista y entrega el correo. El proveedor receptor toma todas las decisiones sobre si ese correo llega a una bandeja de entrada. Para ello, utiliza la dirección IP de envío y el dominio de envío. Una IP nueva de un VPS no tiene ningún historial. Todos los grandes proveedores de correo consideran esa falta de historial como un indicio moderado de actividad sospechosa.

Hay cuatro elementos obligatorios:

  • Un registro SPF (sender policy framework) de tipo TXT que indique el host autorizado para enviar en nombre de su dominio.
  • Una clave DKIM (domainkeys identified mail) publicada como registro TXT. La firma debe realizarla el servidor de correo, no Listmonk.
  • Un registro DMARC (domain based message authentication, reporting and conformance), que indica a los receptores qué deben hacer cuando fallan los dos mecanismos anteriores.
  • Un buzón para mensajes rebotados que Listmonk lea. Así, las direcciones que rechazan el correo salen de la lista en lugar de recibir reintentos indefinidamente.

Después, envíe los mensajes lentamente al principio. Un dominio que nunca ha enviado correo y entrega de repente diez mil mensajes en una hora tiene exactamente el perfil de una cuenta comprometida, por lo que se filtra como tal. Empiece por los suscriptores más activos y aumente el volumen durante varios días.

Todas las plantillas también necesitan un enlace de cancelación de suscripción operativo. En una plantilla de Listmonk, ese enlace es {{ UnsubscribeURL }}. El cuerpo de la campaña se inserta donde aparece {{ template "content" . }}, que debe aparecer exactamente una vez en cada plantilla. Una campaña sin enlace de cancelación de suscripción genera quejas por spam en lugar de cancelaciones, y las quejas son la forma más rápida de perder una reputación de envío que ha tardado semanas en construir.

Copias de seguridad y requisitos reales de una restauración

Hay dos elementos que deben salir del servidor: el volcado de la base de datos y config.toml. Añada el directorio de medios si carga imágenes en las campañas.

sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dump

Ese volcado contiene los suscriptores, las campañas, las plantillas y toda la configuración, incluidas las credenciales SMTP. Cífrelo y guárdelo fuera de este servidor. La programación de las copias ya está resuelta: consulte copias de seguridad cifradas con restic en almacenamiento remoto. config.toml tiene sólo unas pocas líneas, pero contiene la contraseña de la base de datos, así que trátelo de la misma forma.

Las actualizaciones siguen un orden concreto. Detenga el servicio, cree un volcado, sustituya el binario en /usr/bin, ejecute listmonk --config /etc/listmonk/config.toml --upgrade y vuelva a iniciar el servicio. Las migraciones del esquema sólo avanzan, así que ese volcado es la única forma de volver atrás.

¿Por qué Listmonk no se inicia?

Lea primero el journal con journalctl -u listmonk -n 50 --no-pager. Casi todos los fallos de inicio aparecen en una línea del bloque [db].

pq: password authentication failed for user "listmonk" significa que la contraseña de [db] no coincide con el rol de Postgres. El prefijo pq indica que el controlador de Postgres informa del rechazo del servidor. Por tanto, la configuración se leyó correctamente y las credenciales eran incorrectas. Restablezca el rol con sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" y escriba la misma cadena en el archivo.

pq: database "listmonk" does not exist significa que el valor de database en [db] no corresponde a una base de datos existente. sudo -u postgres psql -l muestra las bases de datos disponibles en el servidor, incluida la escritura incorrecta que utilizó.

permission denied durante --install significa que el rol puede conectarse, pero no es propietario de la base de datos. Por eso no puede crear tablas en ella. Corríjalo con sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" y vuelva a ejecutar la instalación.

El servicio nunca se inicia y el journal indica el archivo de configuración. Un proceso que se ejecuta como listmonk no puede abrir un config.toml que tiene root:root con permisos 600. stat -c '%U:%G %a' /etc/listmonk/config.toml debería mostrar root:listmonk 640, y el directorio superior debería tener root:listmonk 750.

El panel funciona, pero no llega ningún correo. Eso no es un problema de inicio. Compruebe primero Settings y SMTP. Después revise el registro de la campaña en el panel de administración. Allí aparece el error que el servidor de correo devolvió en cada intento.

FAQ

¿Necesito mi propio servidor de correo para usar Listmonk?

No. Listmonk no es un servidor de correo. Necesita las credenciales SMTP de un servidor que acepte los mensajes y los entregue. Puede ser un relay transaccional o un servidor de correo que administre usted. Configure esas credenciales en Settings y SMTP del panel de administración, no en config.toml, porque la configuración de correo se almacena en la base de datos. Use el puerto 587 con STARTTLS o el puerto 465 con TLS implícito, ya que la mayoría de los proveedores de VPS bloquean el puerto saliente 25 en las cuentas nuevas.

¿Por qué los enlaces de mi campaña apuntan a localhost:9000?

La configuración de la URL raíz conserva el valor predeterminado de la instalación: http://localhost:9000. Listmonk escribe ese valor en los enlaces de cancelación de suscripción y en las URL de medios cuando envía una campaña. Abra Settings en el panel de administración, establezca la URL raíz con su dirección HTTPS real y guarde los cambios. Los mensajes que ya se entregaron no se pueden corregir. Envíese una campaña de prueba y haga clic en el enlace de cancelación de suscripción antes de enviar mensajes a una lista real.

¿Volver a ejecutar --install eliminará mis suscriptores?

Sí. --install es el instalador de la primera ejecución y elimina el esquema existente de Listmonk. --yes elimina la solicitud de confirmación que le habría advertido de ello. En cualquier script que pueda ejecutarse dos veces, use --install --idempotent --yes, que no hace nada si las tablas ya existen. Para aplicar los cambios de esquema de una versión nueva, detenga el servicio, cree un pg_dump y luego ejecute --upgrade.

¿Por qué Listmonk indica que falló la autenticación mediante contraseña para el usuario listmonk?

La contraseña del bloque [db] de /etc/listmonk/config.toml no coincide con la del rol de Postgres con el mismo nombre. La línea del journal es pq: password authentication failed for user "listmonk", y pq es el controlador de Postgres transmitiendo el rechazo del servidor. Esto significa que se encontró y leyó el archivo de configuración. Restablezca la contraseña del rol con sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", escriba la misma cadena en el archivo de configuración y luego ejecute sudo systemctl restart listmonk.