SSD Nodes Learn 8GB RAM — $66/год
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-01

Как установить Listmonk на VPS с Ubuntu 24.04

Пошагово установите Listmonk v6.2.0 на Ubuntu 24.04: PostgreSQL, config.toml, systemd, TLS и SMTP. Разберите, почему VPS не отвечает за доставляемость.

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

Что нужно для самостоятельного запуска рассылки на Listmonk

Listmonk — это самостоятельный менеджер рассылок и списков адресатов: один бинарный файл Go, одна база данных PostgreSQL, один файл конфигурации и один модуль systemd. Небольшой VPS без проблем запускает его, поскольку Listmonk хранит подписчиков и ставит кампании в очередь, но сам не доставляет почту. Он передает каждое сообщение на SMTP-сервер (simple mail transfer protocol), поэтому доставляемость определяется репутацией этого сервера, а не этого программного обеспечения.

В этом руководстве описана установка Listmonk v6.2.0 — текущего выпуска по состоянию на июль 2026 года — на Ubuntu 24.04. Вам понадобятся VPS с публичным IP-адресом, доменное имя под вашим управлением и PostgreSQL 12 или новее. Установка занимает около часа. Формирование репутации отправителя занимает несколько недель. Этому посвящен раздел ближе к концу руководства.

Установите PostgreSQL и создайте базу данных

Ubuntu 24.04 поставляется с PostgreSQL 16 в собственном репозитории. Эта версия значительно новее минимальной версии, необходимой Listmonk.

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

Создайте роль и базу данных в одном сеансе psql. -v ON_ERROR_STOP=1 заставляет psql завершать работу после первой ошибочной инструкции. Поэтому опечатка не оставит частично выполненную настройку, которая выглядит завершённой.

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 имеет практическое значение. При установке схемы создаются таблицы, типы, индексы и функции. Поэтому роль должна владеть базой данных. Если указать Listmonk базу данных, принадлежащую другой роли, установка завершится с ошибкой permission denied, даже после выполнения GRANT CONNECT.

Перед продолжением убедитесь, что база данных существует.

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

Эта команда выводит listmonk. Пустая строка означает, что инструкция CREATE не выполнялась. Снова просмотрите вывод psql.

Установите бинарный файл Listmonk

Listmonk выпускает статический бинарный файл для каждой архитектуры. Сначала проверьте архитектуру вашей системы: бинарный файл amd64 на ARM VPS — это файл, который ядро отказывается выполнять.

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

На ARM VPS замените amd64 на arm64 в имени файла. Если listmonk --version выводит строку с версией, это первое подтверждение того, что бинарный файл соответствует машине.

Создайте config.toml и ограничьте к нему доступ

--new-config записывает config.toml в текущий рабочий каталог. Поэтому cd находится внутри sh -c, а не перед sudo.

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

Созданный файл небольшой. В разделе [app] параметр address = "localhost:9000" привязывает HTTP-сервер только к loopback-интерфейсу. Поэтому панель администрирования недоступна из интернета, пока перед сервером не будет настроен reverse proxy. Не изменяйте эту строку. В разделе [db] находятся host = "localhost", port = 5432, user = "listmonk", database = "listmonk" и ssl_mode = "disable". Эти значения по умолчанию уже соответствуют созданной базе данных. Поэтому необходимо изменить только строку с паролем.

ssl_mode = "disable" подходит, пока Postgres принимает соединения на loopback-интерфейсе на том же сервере, поскольку этот трафик не покидает машину. Если база данных находится на другом узле, задайте require. В противном случае пароль передаётся по сети в открытом виде.

Измените строку с паролем в разделе [db], чтобы пароль соответствовал роли. Затем создайте сервисную учётную запись и запретите доступ к файлу всем остальным пользователям.

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

Теперь сервисная учётная запись может читать файл, а остальные пользователи — нет.

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

Первая команда выводит readable. Вторая выводит root:listmonk 640. Если другая непривилегированная учётная запись попытается выполнить тот же cat, она получит Permission denied. Это важно: файл содержит пароль базы данных в открытом виде, а на сервере обычно есть несколько учётных записей. То же правило относится ко всем запускаемым сервисам. Поэтому ознакомьтесь с материалом сервисные пользователи с минимальными привилегиями и применяйте этот принцип везде.

Создание схемы с помощью --install

--install создает таблицы и добавляет стандартные настройки. Задайте данные для первого входа администратора с помощью переменных среды, чтобы учетная запись была создана до того, как панель станет доступна.

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

--yes подтверждает запрос. Перед автоматизацией один раз прочитайте этот запрос, поскольку --install выполняется установщиком впервые и удаляет существующую схему Listmonk. Повторный запуск для рабочей базы данных уничтожит данные подписчиков. В любом сценарии, который может выполняться повторно, используйте --install --idempotent --yes. Эта команда ничего не делает, если таблицы уже существуют. Изменения схемы, включенные в новый выпуск, применяются с помощью --upgrade, а не --install.

Проверьте результат со стороны базы данных, а не в браузере.

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

Первая команда выводит список таблиц Listmonk. В него входят subscribers, lists, campaigns, templates и bounces. Вторая команда выводит admin. Пустой результат второй команды означает, что переменные среды не были переданы процессу. В этом случае панель предложит создать первого пользователя в браузере.

Запуск Listmonk через systemd

Создайте /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 важен, поскольку Listmonk разрешает относительные пути, включая путь к загрузкам медиафайлов в файловой системе, относительно этого каталога. After=postgresql.service только задаёт порядок запуска и не ожидает, пока Postgres начнёт принимать подключения. Поэтому Restart=on-failure обрабатывает ситуацию, когда Listmonk запускается слишком рано и не может подключиться.

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

ss должен показывать 127.0.0.1:9000 в состоянии LISTEN. curl, возвращающий любую строку состояния HTTP, означает, что сервер отвечает. Если curl завершается с Connection refused, это означает, что процесс завершился во время запуска; причина будет указана в journalctl -u listmonk -n 50 --no-pager. Обратите внимание, что именно enable --now обеспечивает запуск после перезагрузки: процесс, запущенный вручную, завершится после следующего обновления ядра.

Установите nginx и TLS перед приложением

Listmonk использует обычный HTTP через loopback, поэтому nginx завершает TLS (защиту транспортного уровня) и перенаправляет запрос.

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 необходимо увеличить, поскольку импорт подписчиков и загрузка медиафайлов выполняются через отправку файлов, а nginx по умолчанию отклоняет всё, что превышает 1 MB, с ошибкой 413 Request Entity Too Large. Выпустите сертификат с помощью certbot. Он также добавит строки listen 443 ssl и настроит перенаправление с порта 80. Инструкции приведены в руководстве по сертификату Let's Encrypt для nginx. Откройте порты 80 и 443, а порт 9000 оставьте закрытым, поскольку прокси обращается к нему через loopback. Если правила брандмауэра ещё не настроены, начните с основ настройки брандмауэра ufw.

Затем откройте панель администратора и в разделе Settings задайте корневой URL: https://lists.example.com. В новой установке используется значение http://localhost:9000. Listmonk записывает его во все ссылки для отписки и URL медиафайлов, которые добавляет в письмо. Если отправить кампанию до изменения этого значения, каждый получатель получит ссылки, указывающие на его собственный компьютер. Для получателя они не работают, а для спам-фильтра выглядят так, будто отправитель не умеет настроить собственный домен.

Подключение SMTP, которого нет в config.toml

В config.toml нет раздела SMTP. Настройки почты хранятся в базе данных, в таблице settings. Изменяйте их в панели администратора в разделе Settings и SMTP. Поэтому сгенерированный файл остается таким коротким. По этой же причине после изменения SMTP перезапуск не требуется.

Для самого SMTP-сервера есть два практичных варианта. Запустите собственный сервер. В этом случае репутация полностью зависит от вас, а сам запуск становится отдельным полноценным проектом: в материале Запуск собственного почтового сервера с Mailcow описано, что для этого требуется. Либо укажите для Listmonk транзакционный relay и передайте управление репутацией IP-адреса другому провайдеру.

В любом случае используйте порт 587 с STARTTLS или порт 465 с неявным TLS. Не планируйте отправку через исходящий порт 25. Большинство VPS-провайдеров по умолчанию блокируют его для новых учетных записей. Заблокированный порт 25 выглядит как зависшее соединение: пакеты отбрасываются, а не отклоняются, поэтому клиент ждет тайм-аута вместо немедленного завершения с ошибкой.

Проверьте SMTP до того, как начнете ему доверять. Создайте список, добавьте свой адрес как подписчика и отправьте кампанию одному получателю. Откройте полученное сообщение и прочитайте все заголовки. Заголовок Authentication-Results, добавленный принимающей стороной, показывает, прошли ли проверки SPF и DKIM.

Доставка сообщений — основная задача

Listmonk формирует сообщение, отслеживает список и передает письмо дальше. Решение о том, попадет ли письмо во входящие, принимает принимающий провайдер. Он учитывает IP-адрес отправителя и домен отправителя. У нового IP-адреса VPS полностью отсутствует история. Все крупные провайдеры почтовых ящиков считают отсутствие истории умеренно подозрительным.

Обязательны четыре компонента:

  • TXT-запись SPF (sender policy framework), в которой указан хост, которому разрешено отправлять письма от имени вашего домена.
  • Ключ DKIM (domainkeys identified mail), опубликованный в виде TXT-записи. Подпись должен выполнять почтовый сервер, а не Listmonk.
  • Запись DMARC (domain based message authentication, reporting and conformance), которая сообщает принимающим серверам, что делать при сбое первых двух проверок.
  • Почтовый ящик для сообщений о возврате, который читает Listmonk. Тогда адреса, отклонившие письмо, удаляются из списка, а не получают бесконечные повторные попытки отправки.

Сначала отправляйте сообщения медленно. Домен, с которого раньше не отправляли письма и который внезапно доставляет десять тысяч сообщений за час, выглядит как взломанная учетная запись. Поэтому такие сообщения фильтруются соответствующим образом. Начните с наиболее вовлеченных подписчиков и увеличивайте объем в течение нескольких дней.

В каждом шаблоне также должна быть рабочая ссылка для отмены подписки. В шаблоне Listmonk это {{ UnsubscribeURL }}. Тело кампании размещается там, где находится {{ template "content" . }}. Этот маркер должен присутствовать в каждом шаблоне ровно один раз. Кампания без ссылки для отмены подписки приводит к жалобам на спам, а не к отменам подписки. Жалобы — самый быстрый способ потерять репутацию отправителя, на создание которой ушли недели.

Резервные копии и что действительно требуется для восстановления

С сервера необходимо вынести два объекта: дамп базы данных и config.toml. Добавьте каталог media, если загружаете изображения в кампании.

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

В этом дампе хранятся подписчики, кампании, шаблоны и все настройки, включая учетные данные SMTP. Зашифруйте его и храните не на этом сервере. Планирование таких резервных копий — решенная задача: см. зашифрованные резервные копии restic в удаленное хранилище. config.toml занимает несколько строк, но содержит пароль базы данных, поэтому обращайтесь с ним так же.

Обновления выполняются в определенном порядке. Остановите службу, создайте дамп, замените бинарный файл в /usr/bin, выполните listmonk --config /etc/listmonk/config.toml --upgrade, затем запустите службу. Миграции схемы выполняются только вперед, поэтому этот дамп — единственный способ вернуться к прежнему состоянию.

Почему Listmonk не запускается?

Сначала прочитайте журнал с помощью journalctl -u listmonk -n 50 --no-pager. Почти каждая ошибка запуска указана одной строкой в блоке [db].

pq: password authentication failed for user "listmonk" означает, что пароль в [db] не совпадает с ролью Postgres. Префикс pq означает, что драйвер Postgres сообщает об отклонении со стороны сервера. Следовательно, конфигурация прочитана правильно, а учетные данные указаны неверно. Сбросьте роль с помощью sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" и укажите в файле ту же строку без изменений.

pq: database "listmonk" does not exist означает, что значение database в [db] не соответствует существующей базе данных. Команда sudo -u postgres psql -l выводит список баз данных на сервере, включая название, которое было указано с ошибкой.

permission denied во время --install означает, что роль может подключиться, но не владеет базой данных и поэтому не может создать в ней таблицы. Исправьте это с помощью sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" и снова запустите установку.

Сервис не запускается, и журнал указывает файл конфигурации. Процесс, запущенный от имени listmonk, не может открыть файл config.toml, если для него установлен владелец root:root и режим 600. Команда stat -c '%U:%G %a' /etc/listmonk/config.toml должна вывести root:listmonk 640, а для каталога над этим файлом должно быть установлено значение root:listmonk 750.

Панель работает, но письма не доставляются. Это не проблема запуска. Сначала проверьте Settings и SMTP, затем собственный журнал кампании в панели администратора. В нем указана ошибка, которую почтовый сервер вернул для каждой попытки отправки.

FAQ

Нужен ли мне собственный почтовый сервер для использования Listmonk?

Нет. Listmonk не является почтовым сервером. Ему нужны учетные данные SMTP-сервера, который принимает ваши сообщения и доставляет их. Это может быть транзакционный relay или почтовый сервер, которым вы управляете самостоятельно. Укажите эти учетные данные в разделах Settings и SMTP панели администрирования, а не в config.toml, поскольку параметры почты хранятся в базе данных. Используйте порт 587 с STARTTLS или порт 465 с неявным TLS, поскольку большинство провайдеров VPS блокируют исходящий порт 25 для новых учетных записей.

Почему ссылки в моей кампании ведут на localhost:9000?

В параметре корневого URL все еще указано установочное значение по умолчанию http://localhost:9000. Listmonk записывает это значение в ссылки для отмены подписки и URL медиафайлов в момент отправки кампании. Откройте Settings в панели администрирования, укажите настоящий HTTPS-адрес в качестве корневого URL и сохраните изменения. Уже доставленные сообщения нельзя исправить, поэтому отправьте себе тестовую кампанию и перейдите по ссылке для отмены подписки в ней до отправки сообщения реальному списку.

Удалит ли повторный запуск --install моих подписчиков?

Да. --install — установщик, предназначенный для первоначального запуска; он удаляет существующую схему Listmonk, а --yes отключает запрос, который предупредил бы об этом. В любом скрипте, который может выполняться повторно, используйте --install --idempotent --yes. Этот параметр ничего не делает, если таблицы уже существуют. Чтобы применить изменения схемы в новом выпуске, остановите службу, создайте pg_dump, затем выполните --upgrade.

Почему Listmonk сообщает, что аутентификация по паролю для пользователя listmonk не выполнена?

Пароль в блоке [db] файла /etc/listmonk/config.toml не совпадает с паролем роли Postgres с таким же именем. Строка журнала имеет вид pq: password authentication failed for user "listmonk", а pq — это драйвер Postgres, передающий отказ сервера. Это означает, что файл конфигурации был найден и прочитан. Сбросьте пароль роли с помощью sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", запишите ту же строку в файл конфигурации, затем выполните sudo systemctl restart listmonk.