SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-10-06

Установка Listmonk на Ubuntu 24.04: пошаговое руководство

Разверните Listmonk v6.2.0 на VPS с PostgreSQL и systemd. В статье разобрана настройка SMTP, конфигурация TLS и реальные затраты на обеспечение доставляемости писем.

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

Что необходимо для self-hosted рассылки на базе Listmonk

Listmonk — это self-hosted менеджер рассылок и списков адресатов: один бинарный файл на 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 (transport layer security) termination и перенаправляет запросы.

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.

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

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

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

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

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

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

Доставляемость — это основная задача

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

Четыре компонента являются обязательными:

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

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

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

Резервное копирование и требования к восстановлению

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

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.

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

FAQ

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

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

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

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

Удалит ли повторный запуск --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.

Была ли эта статья полезной?