SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-07

Як встановити Listmonk на VPS з Ubuntu 24.04

Покроково встановіть Listmonk v6.2.0 на Ubuntu 24.04: PostgreSQL, config.toml, systemd, TLS і SMTP. Дізнайтеся, чому репутація відправника формується тижнями.

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, один конфігураційний файл і один unit systemd. Невеликий VPS без проблем запускає його, оскільки Listmonk зберігає підписників і ставить кампанії в чергу, але сам не доставляє листи. Він передає кожне повідомлення SMTP-серверу (simple mail transfer protocol), тому доставляння залежить від репутації цього сервера, а не від самого програмного забезпечення.

У цьому посібнику описано встановлення Listmonk v6.2.0 — актуального релізу станом на July 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. Якщо firewall ще не налаштовано, почніть із основ налаштування ufw.

Потім відкрийте адміністративну панель і в розділі Settings установіть кореневу URL-адресу https://lists.example.com. Після свіжого встановлення використовується http://localhost:9000. Listmonk записує це значення в кожне посилання для відписки та URL-адресу медіафайлу, які додає до електронного листа. Якщо надіслати кампанію до зміни цього значення, кожен одержувач отримає посилання на власний комп’ютер. Для одержувача вони не працюватимуть, а для spam filter виглядатимуть так, ніби відправник не здатен налаштувати власний домен.

Підключення SMTP, якого немає в config.toml

Пошукайте розділ SMTP у config.toml — його там не буде. Налаштування пошти зберігаються в базі даних, у таблиці settings, і редагуються в панелі адміністратора в розділі Settings → SMTP. Тому згенерований файл залишається таким коротким. Саме тому після зміни SMTP не потрібно перезапускати сервіс.

Для самого SMTP-сервера є два реалістичні варіанти. Запустити власний сервер. У такому разі репутація повністю залежить від вас, а сам проєкт потребує окремої роботи: у матеріалі як запустити власний поштовий сервер за допомогою Mailcow описано, що саме це передбачає. Або вказати для Listmonk транзакційний relay і передати керування репутацією IP-адреси іншому постачальнику.

У будь-якому разі використовуйте порт 587 із STARTTLS або порт 465 з implicit 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), який повідомляє одержувачам, що робити, якщо перші два механізми не пройшли перевірку.
  • Поштова скринька для bounce-повідомлень, яку читає 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.

Панель працює, але пошта не надходить. Це не проблема запуску. Спочатку перевірте Settings і SMTP, а потім перегляньте журнал самої кампанії в панелі адміністратора. У ньому для кожної спроби записано помилку, яку повернув поштовий сервер.

FAQ

Чи потрібен власний поштовий сервер для використання Listmonk?

Ні. Listmonk не є поштовим сервером. Йому потрібні облікові дані SMTP-сервера, який приймає вашу пошту та доставляє її одержувачам. Це може бути transactional relay або поштовий сервер, яким ви керуєте самостійно. Укажіть ці облікові дані в розділі Settings і SMTP адміністративної панелі, а не в config.toml, оскільки налаштування пошти зберігаються в базі даних. Використовуйте порт 587 із STARTTLS або порт 465 з implicit TLS, оскільки більшість VPS-провайдерів блокують вихідний порт 25 для нових облікових записів.

Чому посилання в моїй кампанії ведуть на localhost:9000?

Параметр root URL досі має стандартне значення після встановлення — http://localhost:9000. Listmonk записує це значення в посилання для скасування підписки та URL медіафайлів у момент надсилання кампанії. Відкрийте Settings в адміністративній панелі, укажіть справжню HTTPS-адресу в полі root 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.