Jak zainstalować Listmonk na VPS z Ubuntu 24.04
Instrukcja instalacji Listmonk 6.2.0 na Ubuntu 24.04. Konfiguracja bazy PostgreSQL, pliku config.toml, jednostki systemd oraz TLS. Dowiedz się, jak poprawnie skonfigurować SMTP.
Wymagania dla własnego serwera newslettera opartego na Listmonk
Listmonk to samodzielnie hostowany menedżer newsletterów i list mailingowych: jeden plik binarny Go, jedna baza danych PostgreSQL, jeden plik konfiguracyjny i jedna jednostka systemd. Mały VPS obsługuje go bez wysiłku, ponieważ Listmonk przechowuje subskrybentów i kolejkuje kampanie, ale sam nie dostarcza poczty. Przekazuje każdą wiadomość do serwera SMTP (simple mail transfer protocol), więc wskaźnik dostarczalności zależy od reputacji tego serwera, a nie od samego oprogramowania.
Niniejszy przewodnik opisuje instalację Listmonk w wersji 6.2.0, aktualnego wydania na lipiec 2026 roku, w systemie Ubuntu 24.04. Wymagany jest VPS z publicznym adresem IP, posiadana domena oraz PostgreSQL w wersji 12 lub nowszej. Instalacja zajmuje około godziny. Budowanie reputacji nadawcy trwa tygodnie, a ten aspekt został omówiony pod koniec przewodnika.
Instalacja PostgreSQL i utworzenie bazy danych
Ubuntu 24.04 zawiera w swoich repozytoriach PostgreSQL 16, co znacznie przewyższa wymagania Listmonk.
sudo apt update
sudo apt install -y postgresql curl
sudo systemctl enable --now postgresqlUtwórz rolę oraz bazę danych w jednej sesji psql. Flaga -v ON_ERROR_STOP=1 wymusza zakończenie działania psql po pierwszym nieudanym poleceniu, dzięki czemu literówka nie pozostawi częściowo skonfigurowanego środowiska, które sprawia wrażenie gotowego.
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;
SQLOpcja OWNER listmonk nie jest zbędna. Instalacja schematu tworzy tabele, typy, indeksy oraz funkcje, dlatego rola musi być właścicielem bazy danych. Wskazanie Listmonk bazy danych należącej do innej roli spowoduje przerwanie instalacji z błędem permission denied, nawet jeśli wykonano już GRANT CONNECT.
Przed przejściem dalej potwierdź istnienie bazy danych.
sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datname='listmonk';"Polecenie to wyświetli listmonk. Pusta linia oznacza, że instrukcja CREATE nie została wykonana, więc należy ponownie przeanalizować dane wyjściowe psql.
Instalacja pliku binarnego Listmonk
Listmonk udostępnia statyczny plik binarny dla każdej architektury. Należy najpierw sprawdzić architekturę systemu, ponieważ plik binarny amd64 na serwerze VPS z architekturą ARM nie zostanie uruchomiony przez jądro systemu.
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 --versionW przypadku serwera VPS z architekturą ARM należy zamienić amd64 na arm64 w nazwie pliku. Wyświetlenie ciągu wersji przez listmonk --version stanowi pierwsze potwierdzenie, że plik binarny jest zgodny z maszyną.
Generowanie pliku config.toml i zabezpieczanie dostępu
--new-config zapisuje config.toml w bieżącym katalogu roboczym. Dlatego cd znajduje się wewnątrz sh -c, a nie przed sudo.
sudo install -d -m 750 /etc/listmonk
sudo sh -c 'cd /etc/listmonk && listmonk --new-config'Wygenerowany plik jest krótki. W sekcji [app] parametr address = "localhost:9000" wiąże serwer HTTP wyłącznie z interfejsem loopback, dzięki czemu panel administracyjny nie jest dostępny z Internetu, dopóki nie zostanie przed nim umieszczony reverse proxy. Nie należy zmieniać tej linii. W sekcji [db] znajdują się host = "localhost", port = 5432, user = "listmonk", database = "listmonk" oraz ssl_mode = "disable". Te wartości domyślne są już zgodne z utworzoną bazą danych, więc jedyną linią wymagającą zmiany jest hasło.
ssl_mode = "disable" jest poprawnym ustawieniem, gdy Postgres nasłuchuje na interfejsie loopback na tej samej maszynie, ponieważ ruch ten nie opuszcza serwera. W przypadku przeniesienia bazy danych na inny host należy ustawić require, w przeciwnym razie hasło będzie przesyłane przez sieć otwartym tekstem.
Należy edytować linię z hasłem w sekcji [db], aby pasowała do roli, a następnie utworzyć konto serwisowe i odebrać uprawnienia do pliku wszystkim pozostałym użytkownikom.
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.tomlTeraz konto serwisowe może odczytać plik, a nikt inny nie ma takiej możliwości.
sudo -u listmonk cat /etc/listmonk/config.toml > /dev/null && echo readable
stat -c '%U:%G %a' /etc/listmonk/config.tomlPierwsze polecenie wyświetla readable. Drugie wyświetla root:listmonk 640. Każde inne nieuprzywilejowane konto próbujące wykonać to samo cat otrzyma Permission denied, co jest zamierzonym efektem: plik ten przechowuje hasło do bazy danych otwartym tekstem, a na serwerze zazwyczaj istnieje więcej niż jedno konto użytkownika. To samo rozumowanie dotyczy każdej uruchamianej usługi, dlatego warto zapoznać się z zasadą najmniejszych uprawnień dla kont serwisowych i stosować ją wszędzie.
Utworzenie schematu za pomocą --install
--install tworzy tabele i wypełnia je domyślnymi ustawieniami. Skonfiguruj pierwszy login administratora za pomocą zmiennych środowiskowych, aby konto istniało, zanim panel stanie się dostępny.
sudo -u listmonk env LISTMONK_ADMIN_USER=admin \
LISTMONK_ADMIN_PASSWORD='another-long-random-password' \
listmonk --config /etc/listmonk/config.toml --install --yes--yes odpowiada na monit potwierdzenia. Przeczytaj ten monit przed automatyzacją, ponieważ --install to instalator pierwszego uruchomienia, który usuwa istniejący schemat Listmonk. Uruchomienie go ponownie na działającej bazie danych spowoduje utratę subskrybentów. W każdym skrypcie, który może zostać wywołany dwukrotnie, użyj --install --idempotent --yes, który nie wykonuje żadnych działań, jeśli tabele już istnieją. Zmiany schematu dostarczone w nowym wydaniu należy stosować za pomocą --upgrade, a nigdy za pomocą --install.
Sprawdź wynik po stronie bazy danych, zamiast w przeglądarce.
sudo -u postgres psql -d listmonk -c '\dt'
sudo -u postgres psql -d listmonk -tAc "SELECT username FROM users;"Pierwsze polecenie wyświetla listę tabel Listmonk, w tym subscribers, lists, campaigns, templates oraz bounces. Drugie polecenie wypisuje admin. Pusty wynik drugiego polecenia oznacza, że zmienne środowiskowe nie dotarły do procesu, więc panel poprosi o utworzenie pierwszego użytkownika w przeglądarce.
Uruchamianie Listmonk przez systemd
Należy utworzyć /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.targetWorkingDirectory jest istotne, ponieważ Listmonk rozwiązuje ścieżki względne, w tym ścieżkę do przesyłania plików multimedialnych, względem tego katalogu. After=postgresql.service jedynie ustala kolejność uruchamiania i nie czeka, aż Postgres zacznie akceptować połączenia, dlatego Restart=on-failure obsługuje przypadek, w którym Listmonk uruchamia się zbyt wcześnie i nie może nawiązać połączenia.
sudo systemctl daemon-reload
sudo systemctl enable --now listmonk
ss -ltnp | grep 9000
curl -sI http://127.0.0.1:9000/ss powinno wykazać, że 127.0.0.1:9000 znajduje się w stanie LISTEN. curl zwracające dowolną linię statusu HTTP oznacza, że serwer odpowiada. curl kończące się błędem Connection refused oznacza, że proces zakończył działanie podczas uruchamiania, a journalctl -u listmonk -n 50 --no-pager wskaże przyczynę. Należy pamiętać, że enable --now to element, który przetrwa restart systemu: proces uruchomiony ręcznie zostanie zamknięty po kolejnej aktualizacji jądra.
Umieszczenie nginx i TLS przed aplikacją
Listmonk obsługuje zwykły protokół HTTP na interfejsie loopback, dlatego nginx wykonuje terminację TLS (transport layer security) i przekazuje żądania dalej.
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;
}
}Wartość client_max_body_size musi zostać zwiększona, ponieważ import subskrybentów oraz przesyłanie plików multimedialnych to operacje typu file post, a nginx domyślnie odrzuca żądania przekraczające 1 MB z błędem 413 Request Entity Too Large. Certyfikat należy wygenerować za pomocą certbot, który automatycznie dopisze linie listen 443 ssl oraz konfigurację przekierowania z portu 80: odpowiednie kroki opisano w przewodniku po certyfikatach Let's Encrypt dla nginx. Należy otworzyć porty 80 oraz 443, pozostawiając port 9000 zamknięty, ponieważ proxy uzyskuje do niego dostęp przez interfejs loopback. Jeśli zapora sieciowa nie została jeszcze skonfigurowana, warto zacząć od podstaw obsługi zapory ufw.
Następnie należy otworzyć panel administracyjny i w sekcji Settings ustawić główny adres URL na https://lists.example.com. Świeża instalacja posiada wartość http://localhost:9000, a Listmonk umieszcza tę wartość w każdym linku do rezygnacji z subskrypcji oraz w adresach URL multimediów zawartych w wiadomościach e-mail. Wysłanie kampanii przed zmianą tego ustawienia spowoduje, że każdy odbiorca otrzyma linki wskazujące na własny komputer. Linki te nie zadziałają u czytelnika, a w oczach filtrów antyspamowych nadawca będzie wyglądał na osobę, która nie potrafi poprawnie skonfigurować własnej domeny.
Konfiguracja SMTP poza plikiem config.toml
Wyszukaj config.toml w poszukiwaniu sekcji SMTP, a nie znajdziesz jej. Ustawienia poczty znajdują się w bazie danych, w tabeli settings, a edytuje się je w panelu administratora w sekcji Settings oraz SMTP. Dlatego wygenerowany plik pozostaje krótki i dlatego zmiana ustawień SMTP nie wymaga restartu.
Istnieją dwie uczciwe opcje dotyczące samego serwera SMTP. Można uruchomić własny, co przenosi pełną odpowiedzialność za reputację na administratora i stanowi samodzielny projekt: uruchomienie własnego serwera pocztowego z Mailcow opisuje, co się z tym wiąże. Alternatywnie można wskazać Listmonk na przekaźnik transakcyjny i powierzyć reputację adresu IP podmiotowi zewnętrznemu.
W obu przypadkach należy użyć portu 587 z STARTTLS lub portu 465 z niejawnym TLS. Nie należy planować korzystania z wychodzącego portu 25. Większość dostawców VPS domyślnie blokuje go na nowych kontach, a zablokowany port 25 wygląda dokładnie jak zawieszone połączenie, ponieważ pakiety są odrzucane, a nie odsyłane z informacją o odmowie, przez co klient czeka na przekroczenie limitu czasu zamiast szybko zgłosić błąd.
Przetestuj konfigurację przed jej użyciem. Utwórz listę, dodaj własny adres jako subskrybenta i wyślij kampanię do jednego odbiorcy. Otwórz otrzymaną wiadomość i przeczytaj pełne nagłówki. Nagłówek Authentication-Results dodany przez stronę odbierającą informuje, czy weryfikacja SPF i DKIM zakończyła się powodzeniem.
Dostarczalność to kluczowe zadanie
Listmonk przygotowuje treść wiadomości, zarządza listą adresową i przekazuje pocztę do wysyłki. O tym, czy wiadomość trafi do skrzynki odbiorczej, decyduje dostawca poczty odbiorcy, analizując adres IP oraz domenę nadawcy. Nowy adres IP serwera VPS nie posiada żadnej historii, a brak historii jest traktowany przez każdego dużego dostawcę poczty jako sygnał lekko podejrzany.
Cztery elementy są obowiązkowe:
- Rekord TXT typu SPF (sender policy framework), wskazujący hosta uprawnionego do wysyłki w imieniu Twojej domeny.
- Klucz DKIM (domainkeys identified mail) opublikowany jako rekord TXT, przy czym podpisywanie wiadomości musi być realizowane przez serwer pocztowy, a nie przez Listmonk.
- Rekord DMARC (domain based message authentication, reporting and conformance), który informuje odbiorców, jakie działania podjąć w przypadku niepowodzenia weryfikacji SPF lub DKIM.
- Skrzynka pocztowa do obsługi zwrotów (bounce mailbox), z której Listmonk pobiera informacje, aby adresy odrzucające pocztę były usuwane z listy zamiast ciągłego ponawiania prób wysyłki.
Na początku wysyłaj wiadomości powoli. Domena, która nigdy nie wysyłała poczty, a nagle dostarcza dziesięć tysięcy wiadomości w ciągu godziny, wykazuje wzorzec typowy dla przejętego konta, przez co jest filtrowana jako spam. Zacznij od najbardziej zaangażowanych subskrybentów i zwiększaj wolumen wysyłki stopniowo w ciągu kolejnych dni.
Każdy szablon musi zawierać działający link rezygnacji z subskrypcji. W szablonie Listmonk jest to {{ UnsubscribeURL }}, a treść kampanii umieszcza się w miejscu, gdzie znajduje się {{ template "content" . }}, który musi wystąpić w szablonie dokładnie raz. Kampania pozbawiona linku rezygnacji generuje zgłoszenia spamu zamiast wypisów, a zgłoszenia te są najszybszą drogą do utraty reputacji nadawcy, na którą pracowałeś tygodniami.
Kopie zapasowe i wymagania dotyczące przywracania danych
Dwa elementy muszą opuścić serwer: zrzut bazy danych oraz config.toml. Należy dołączyć katalog z mediami, jeśli do kampanii przesyłane są obrazy.
sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dumpZrzut zawiera subskrybentów, kampanie, szablony oraz wszystkie ustawienia, w tym dane uwierzytelniające SMTP, dlatego należy go zaszyfrować i przechowywać poza tym serwerem. Harmonogramowanie tego procesu jest rozwiązane: zobacz szyfrowane kopie zapasowe restic do zdalnej pamięci masowej. Plik config.toml składa się z kilku linii, ale zawiera hasło do bazy danych, więc należy traktować go w ten sam sposób.
Aktualizacje przebiegają w określonej kolejności. Zatrzymaj usługę, wykonaj zrzut, zastąp plik binarny w /usr/bin, uruchom listmonk --config /etc/listmonk/config.toml --upgrade, a następnie uruchom usługę. Migracje schematu działają tylko w przód, więc wspomniany zrzut jest jedyną drogą powrotną.
Dlaczego Listmonk nie uruchamia się?
Najpierw należy sprawdzić dziennik za pomocą journalctl -u listmonk -n 50 --no-pager. Prawie każda awaria podczas uruchamiania jest opisana w jednym wierszu w bloku [db].
pq: password authentication failed for user "listmonk" oznacza, że hasło w [db] nie pasuje do roli Postgres. Przedrostek pq to sterownik Postgres zgłaszający odrzucenie przez serwer, co oznacza, że konfiguracja została odczytana poprawnie, a poświadczenia były błędne. Należy zresetować rolę za pomocą sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" i umieścić identyczny ciąg znaków w pliku.
pq: database "listmonk" does not exist oznacza, że wartość database w [db] nie wskazuje na istniejącą bazę danych. sudo -u postgres psql -l wyświetla listę baz znajdujących się na serwerze, w tym błędną pisownię, która została użyta przez pomyłkę.
permission denied podczas --install oznacza, że rola może nawiązać połączenie, ale nie jest właścicielem bazy danych, więc nie może w niej tworzyć tabel. Należy naprawić to za pomocą sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" i ponownie uruchomić instalację.
Usługa nigdy się nie uruchamia, a dziennik wskazuje plik konfiguracyjny. Proces działający jako listmonk nie może otworzyć pliku config.toml pozostawionego jako root:root z uprawnieniami 600. stat -c '%U:%G %a' /etc/listmonk/config.toml powinno wyświetlić root:listmonk 640, a nadrzędny katalog powinien mieć uprawnienia root:listmonk 750.
Panel działa, ale poczta nie dociera. To nie jest problem z uruchamianiem. Należy najpierw sprawdzić ustawienia i SMTP, a następnie dziennik kampanii w panelu administracyjnym, który rejestruje błąd zwrócony przez serwer pocztowy dla każdej próby.
FAQ
Czy do korzystania z Listmonk wymagany jest własny serwer pocztowy?
Nie. Listmonk nie jest serwerem pocztowym. Wymaga danych uwierzytelniających SMTP do serwera, który przyjmuje i dostarcza pocztę; może to być przekaźnik transakcyjny lub samodzielnie utrzymywany serwer pocztowy. Dane te należy wprowadzić w panelu administracyjnym w sekcji Settings oraz SMTP, a nie w config.toml, ponieważ ustawienia poczty są przechowywane w bazie danych. Należy użyć portu 587 z STARTTLS lub portu 465 z implicit TLS, ponieważ większość dostawców VPS blokuje ruch wychodzący na porcie 25 dla nowych kont.
Dlaczego linki w kampanii wskazują na localhost:9000?
Ustawienie root URL nadal posiada domyślną wartość instalacyjną http://localhost:9000. Listmonk zapisuje tę wartość w linkach rezygnacji z subskrypcji oraz adresach URL mediów w momencie wysyłki kampanii. Należy otworzyć Settings w panelu administracyjnym, ustawić root URL na właściwy adres HTTPS i zapisać zmiany. Wiadomości już dostarczone nie podlegają korekcie, dlatego przed wysyłką do rzeczywistej listy należy wysłać kampanię testową i sprawdzić działanie linku rezygnacji.
Czy ponowne uruchomienie --install usunie subskrybentów?
Tak. --install to instalator pierwszego uruchomienia, który usuwa istniejący schemat Listmonk, a --yes wyłącza monit ostrzegawczy. W skryptach, które mogą zostać uruchomione wielokrotnie, należy użyć --install --idempotent --yes, który nie wykonuje żadnych działań, jeśli tabele już istnieją. Aby zastosować zmiany schematu w nowej wersji, należy zatrzymać usługę, wykonać pg_dump, a następnie uruchomić --upgrade.
Dlaczego Listmonk zgłasza błąd uwierzytelniania hasłem dla użytkownika listmonk?
Hasło w bloku [db] pliku /etc/listmonk/config.toml nie jest zgodne z rolą Postgres o tej samej nazwie. Wiersz dziennika to pq: password authentication failed for user "listmonk", a pq to sterownik Postgres przekazujący odmowę serwera, co oznacza, że plik konfiguracyjny został odnaleziony i odczytany. Należy zresetować hasło roli za pomocą sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", wpisać identyczny ciąg znaków do pliku konfiguracyjnego, a następnie uruchomić sudo systemctl restart listmonk.