Dealownia
Menu
sprawdzono – jak sprawdzamy oferty

listmonk: newsletter na własnym serwerze z zewnętrznym SMTP

listmonk w Dockerze na VPS: nginx i HTTPS, wysyłka przez zewnętrzny SMTP, SPF, DKIM i DMARC, import listy z CSV, double opt-in, wypisy jednym kliknięciem.

Aplikacje na własnym serwerzezaktualizowano 7 min czytania

Redakcja serwisu Dealownia · ceny i fakty ze stron dostawców, jak sprawdzamy

Newsletter bez abonamentu za subskrybentów: listmonk pod adresem https://news.example.pl z panelem do list i kampanii, publiczny formularz zapisu z potwierdzeniem e-mailem, zaimportowanych subskrybentów i wysyłkę przez zewnętrzny serwer SMTP z poprawnymi rekordami SPF, DKIM i DMARC. listmonk jest darmowy (licencja AGPLv3), nie ma limitu subskrybentów ani kampanii; płacisz za VPS i za wysyłkę u dostawcy SMTP. To ostatnie jest świadomym wyborem – niżej wyjaśniamy, dlaczego nie warto wysyłać newslettera z własnego serwera pocztowego.

Czego potrzebujesz

  • VPS z Ubuntu 24.04 LTS (albo Debianem 12 lub 13) przygotowany jak w poradniku od zera: użytkownik z sudo, ufw, nginx, Docker z Compose, certbot.
  • Minimum: 1 vCPU, 1 GB RAM, 10 GB dysku. Dokumentacja listmonk nie podaje wymagań sprzętowych; to jeden program w Go i baza PostgreSQL (w wersji 12 lub nowszej). Jeśli na serwerze działają już inne narzędzia, weź 2 GB.
  • Subdomenę news.example.pl z rekordem A i dostęp do strefy DNS domeny, z której wysyłasz (example.pl).
  • Konto u dostawcy SMTP do wysyłki masowej (transakcyjnej lub marketingowej), który pozwala zweryfikować domenę.

Dlaczego zewnętrzny SMTP

Własny serwer pocztowy na VPS-ie da się postawić, ale do newslettera to zła droga. Wielu dostawców VPS blokuje wychodzący port 25 – wspomina o tym dokumentacja listmonk. Adres IP taniego serwera często ma za sobą historię spamu albo leży w puli, którą skrzynki traktują z rezerwą. Do tego dochodzą rekord PTR, obsługa odbić i reputacja budowana tygodniami. Wymagania Gmaila dla nadawców powyżej 5000 wiadomości dziennie obejmują SPF i DKIM jednocześnie, DMARC, wypis jednym kliknięciem i odsetek zgłoszeń spamu poniżej 0,3%. Dostawca SMTP załatwia infrastrukturę, a Ty pilnujesz tylko DNS i jakości listy. Szersze porównanie opcji poczty jest w poradniku o poczcie na domenie.

Krok 1. Plik compose

Instalacja w dokumentacji zaczyna się od pobrania oficjalnego pliku. Dokumentacja pobiera go z gałęzi master, która zmienia się razem z rozwojem projektu (11.11.2026 były już na niej wydania testowe wersji 7). Dlatego pobieramy plik z ostatniego stabilnego wydania, v6.2.0 – opis zmian niżej dotyczy właśnie tej wersji pliku:

bash
sudo mkdir -p /opt/apps/listmonk && sudo chown deploy:deploy /opt/apps/listmonk
cd /opt/apps/listmonk
curl -LO https://github.com/knadh/listmonk/raw/v6.2.0/docker-compose.yml

W pliku zmień kilka rzeczy. Obraz aplikacji przypnij do tego samego wydania – image: listmonk/listmonk:v6.2.0 zamiast latest – i podnoś numer świadomie, po kopii bazy. Port aplikacji opublikuj tylko lokalnie (Docker omija ufw):

yaml
    ports:
      - "127.0.0.1:9000:9000"

Hasło do bazy jest w oficjalnym pliku ustawione na listmonk. Podmień je na losowe, wpisując w bloku x-db-credentials linię POSTGRES_PASSWORD: &db-password ${LISTMONK_DB_PASSWORD}. Postgres w tym pliku słucha na 127.0.0.1:5432 – jeśli na serwerze działa już inny Postgres na tym porcie, usuń sekcję ports z usługi db; aplikacja łączy się z bazą przez wewnętrzną sieć Dockera. Ustaw też strefę TZ: Europe/Warsaw w usłudze app, żeby godziny w harmonogramie kampanii były polskie.

Hasła i dane pierwszego administratora trzymaj w .env:

bash
cat > .env <<EOF
LISTMONK_DB_PASSWORD=$(openssl rand -hex 24)
LISTMONK_ADMIN_USER=redakcja
LISTMONK_ADMIN_PASSWORD=$(openssl rand -base64 18)
EOF
chmod 600 .env && cat .env
docker compose up -d
docker compose logs -f app

Oficjalny plik przy każdym starcie uruchamia --install --idempotent (tworzy tabele tylko w pustej bazie) i --upgrade (migracje po pobraniu nowego obrazu). Jeśli LISTMONK_ADMIN_USER i LISTMONK_ADMIN_PASSWORD są ustawione przy pierwszym starcie, konto Super Admin powstaje automatycznie. Po zalogowaniu usuń hasło administratora z .env.

Krok 2. nginx, HTTPS i adres główny

Plik /etc/nginx/sites-available/news.example.pl:

nginx
server {
    listen 80;
    listen [::]:80;
    server_name news.example.pl;

    client_max_body_size 20m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_http_version 1.1;
        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;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/news.example.pl /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d news.example.pl

Zaloguj się na https://news.example.pl/admin/ i w Settings → General ustaw Root URL na https://news.example.pl (bez ukośnika na końcu). Z tego adresu listmonk buduje linki do wypisu, potwierdzenia zapisu i śledzenia kliknięć. Domyślne http://localhost:9000 trafiłoby do maili subskrybentów. W tym samym miejscu wpisz adres nadawcy, np. Newsletter Example <newsletter@example.pl>.

Krok 3. SMTP

W Settings → SMTP wpisz dane od dostawcy: host, port 587 z STARTTLS (albo 465 z TLS), login i hasło. Przyciskiem testowym wyślij wiadomość do siebie. W Settings → Performance ustaw tempo wysyłki zgodne z limitem dostawcy – przekroczenie skończy się odrzuconymi wiadomościami w logach.

Odbicia (adresy nieistniejące, pełne skrzynki) listmonk obsługuje w Settings → Bounces: przez skrzynkę POP3 albo przez webhooki od dostawców SMTP wymienionych w dokumentacji odbić. Włącz to – wysyłka na martwe adresy psuje reputację domeny.

Krok 4. SPF, DKIM i DMARC

Dostawca SMTP poda Ci konkretne rekordy po dodaniu domeny. Typowy zestaw w strefie example.pl:

tekst
example.pl.                     TXT    "v=spf1 include:spf.dostawca-smtp.example ~all"
s1._domainkey.example.pl.       CNAME  s1.dkim.dostawca-smtp.example.
_dmarc.example.pl.              TXT    "v=DMARC1; p=none; rua=mailto:dmarc@example.pl"
  • SPF: domena może mieć tylko jeden rekord SPF. Jeśli masz już v=spf1 dla poczty firmowej, dopisz include: dostawcy do istniejącego rekordu zamiast dodawać drugi – dwa rekordy SPF dają błąd (RFC 7208).
  • DKIM: selektor (s1 powyżej) i forma rekordu (CNAME albo TXT z kluczem) zależą od dostawcy. Przepisz je dokładnie.
  • DMARC: zacznij od p=none i raportów na adres rua, a po kilku tygodniach bez problemów zaostrz do quarantine. Szczegóły wszystkich trzech rekordów opisuje poradnik o poczcie na domenie.

Sprawdź po zmianach:

bash
dig +short TXT example.pl
dig +short TXT _dmarc.example.pl

W nagłówkach testowej wiadomości w Gmailu („Pokaż oryginał”) powinieneś zobaczyć SPF: PASS, DKIM: PASS i DMARC: PASS. Jak działają rekordy i TTL, opisuje poradnik o DNS.

Krok 5. Listy, zgody i import

Utwórz listę (Lists → New), ustaw typ publiczny (tylko do takiej list można zapisać się z formularza) i wybierz double opt-in. Według dokumentacji subskrybent takiej listy dostaje e-mail z prośbą o potwierdzenie i dopóki nie kliknie linku, nie otrzymuje kampanii. To jednocześnie dowód zgody: w bazie zostaje data i status confirmed. W polskim prawie informację handlową wolno wysłać e-mailem tylko za uprzednią zgodą odbiorcy, a RODO wymaga, żebyś umiał tę zgodę wykazać. To nie jest porada prawna – przy sprzedaży przez newsletter zapytaj prawnika.

Import (Subscribers → Import) przyjmuje plik CSV z nagłówkami email, name i opcjonalnie attributes (JSON):

tekst
email,name,attributes
anna@example.pl,"Anna Nowak","{""zrodlo"": ""formularz-2025""}"
jan@example.pl,"Jan Kowalski","{}"

Przy imporcie wybierasz tryb (zapis albo dodanie do listy blokad) i status subskrypcji. Importuj jako confirmed tylko osoby, które naprawdę wyraziły zgodę i umiesz to wykazać. Kupiona lub zebrana z internetu baza to prosta droga do blokady u dostawcy SMTP. Opcja nadpisywania statusu może ponownie zapisać osoby, które się wypisały – listmonk ostrzega o tym przy imporcie.

W Settings → Privacy włącz nagłówek List-Unsubscribe (wypis jednym kliknięciem w Gmailu i innych klientach). W stopce szablonu zostaw link {{ UnsubscribeURL }} – szablon domyślny już go ma.

Krok 6. Kopia bazy

bash
cat > /opt/apps/listmonk/backup.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
umask 077
cd /opt/apps/listmonk
install -d -m 700 backup
docker compose exec -T db pg_dump -U listmonk -Fc listmonk > "backup/listmonk-$(date +%F).dump"
find backup -name 'listmonk-*.dump' -mtime +14 -delete
EOF
chmod +x /opt/apps/listmonk/backup.sh && sudo /opt/apps/listmonk/backup.sh
echo "50 3 * * * root /opt/apps/listmonk/backup.sh >>/var/log/listmonk-kopia.log 2>&1" | sudo tee /etc/cron.d/listmonk-kopia

Dokumentacja aktualizacji każe zrobić kopię bazy przed każdą aktualizacją; samą aktualizację robisz, zmieniając numer wersji w image i wykonując docker compose down app && docker compose pull && docker compose up app -d. Baza z adresami subskrybentów to dane osobowe – kopię poza serwer wysyłaj zaszyfrowaną, np. jak w poradniku o restic i rclone.

Najczęstsze problemy

  • Linki w mailach prowadzą do localhost:9000. Nie ustawiony Root URL w Settings → General.
  • Test SMTP kończy się przekroczeniem czasu. Dostawca VPS blokuje porty wychodzące. Spróbuj portu 587 (zwykle otwarty) albo 2525, jeśli dostawca SMTP go obsługuje; port 25 do wysyłki z aplikacji nie jest potrzebny.
  • Wiadomości trafiają do spamu. Sprawdź nagłówki: brak DKIM: PASS albo SPF z dwoma rekordami to najczęstsza przyczyna. Adres nadawcy musi być w domenie zweryfikowanej u dostawcy.
  • Subskrybenci z formularza nie dostają kampanii. Lista jest double opt-in, a oni nie kliknęli potwierdzenia – mają status unconfirmed. Kampanie na listę double opt-in trafiają tylko do potwierdzonych.
  • Kontener app restartuje się po zmianie hasła bazy. Postgres ustawia hasło tylko przy pierwszej inicjalizacji wolumenu. Zmień je w bazie (ALTER USER) albo, na świeżej instalacji, usuń wolumen listmonk-data i uruchom od nowa.

Co dalej

Formularz zapisu wstawisz na swoją stronę z Lists → Forms – listmonk generuje gotowy kod HTML dla list typu publicznego. Dołóż monitoring dostępności dla adresu news.example.pl, bo bez działającego serwera nie działają linki wypisu. Serwer pod kilka takich narzędzi porównasz w rankingu VPS.

Powiązane poradniki