SSD Nodes Learn 8GB RAM — $66/taon
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-02

Paano Mag-self-host ng Listmonk Newsletter sa VPS

I-install ang Listmonk v6.2.0 sa Ubuntu 24.04 gamit ang PostgreSQL 16, config.toml, systemd at TLS. Alamin din ang SMTP setup at tunay na delivery cost.

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

Mga kailangan ng self-hosted newsletter sa Listmonk

Ang Listmonk ay isang self-hosted newsletter at mailing list manager: isang Go binary, isang PostgreSQL database, isang config file, at isang systemd unit. Kaya itong patakbuhin ng maliit na VPS nang walang malaking overhead, dahil iniimbak ng Listmonk ang mga subscriber at nagla-queue ng mga campaign, pero hindi nito direktang ipinapadala ang email. Ipinapasa nito ang bawat mensahe sa isang SMTP (simple mail transfer protocol) server. Samakatuwid, ang delivery rate ay nakadepende sa reputation ng server na iyon, hindi sa software na ito.

I-install ng gabay na ito ang Listmonk v6.2.0, ang kasalukuyang release noong July 2026, sa Ubuntu 24.04. Kailangan mo ng VPS na may public IP address, domain name na kontrolado mo, at PostgreSQL 12 o mas bago. Tumatagal nang humigit-kumulang isang oras ang installation. Tumatagal naman nang ilang linggo ang pagbuo ng sending reputation, at tinatalakay ang bahaging iyon malapit sa dulo.

I-install ang PostgreSQL at gawin ang database

Kasama sa sariling repository ng Ubuntu 24.04 ang PostgreSQL 16, na mas bago kaysa sa kinakailangan ng Listmonk.

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

Gawin ang role at database sa isang psql session. Pinatitigil ng -v ON_ERROR_STOP=1 ang psql sa unang statement na nabigo, kaya hindi ka maiiwan ng kalahating setup na mukhang kumpleto dahil lang sa typo.

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

Hindi palamuti ang OWNER listmonk. Gumagawa ang schema install ng mga table, type, index at function, kaya dapat pagmamay-ari ng role ang database. Kapag itinuro mo ang Listmonk sa database na pagmamay-ari ng ibang role, hihinto ang install at magpapakita ng permission denied, kahit naisagawa mo na ang GRANT CONNECT.

Tiyaking umiiral ang database bago magpatuloy.

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

Ipinapakita nito ang listmonk. Ibig sabihin ng blangkong linya na hindi naisagawa ang CREATE statement, kaya basahin muli ang output ng psql.

I-install ang Listmonk binary

Naglalabas ang Listmonk ng static binary para sa bawat architecture. Suriin muna ang architecture ng iyong system, dahil tatanggihan ng kernel na i-execute ang amd64 binary sa 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

Sa ARM VPS, palitan ang amd64 ng arm64 sa file name. Ang pag-print ng version string ng listmonk --version ang unang patunay na tugma ang binary sa machine.

Bumuo ng config.toml at higpitan ang access dito

Isinusulat ng --new-config ang config.toml sa kasalukuyang working directory. Kaya nasa loob ng sh -c ang cd, at hindi bago ang sudo.

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

Maikli ang nabuong file. Sa ilalim ng [app], ibinabind ng address = "localhost:9000" ang HTTP server sa loopback lamang, kaya hindi maa-access mula sa internet ang admin panel hangga't wala kang reverse proxy sa harap nito. Huwag baguhin ang linyang iyon. Sa ilalim ng [db], makikita mo ang host = "localhost", port = 5432, user = "listmonk", database = "listmonk" at ssl_mode = "disable". Tugma na ang mga default na iyon sa database na ginawa mo, kaya ang password lamang ang kailangang baguhin.

Tama ang ssl_mode = "disable" habang nakikinig ang Postgres sa loopback sa parehong machine, dahil hindi lumalabas sa machine ang traffic na iyon. Kung ililipat mo ang database sa ibang host, itakda ito sa require; kung hindi, tatawid sa network nang cleartext ang password.

I-edit ang linya ng password sa ilalim ng [db] upang tumugma ito sa role, pagkatapos ay likhain ang service account at alisin ang access sa file mula sa lahat ng iba pang login.

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

Mababasa na ngayon ng service account ang file, at wala nang ibang makakabasa nito.

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

Ipinapakita ng unang command ang readable. Ipinapakita naman ng pangalawa ang root:listmonk 640. Makakakuha ng Permission denied ang anumang iba pang unprivileged account na susubok sa parehong cat. Iyan ang layunin: nasa file na ito ang database password nang cleartext, at karaniwang may higit sa isang login ang server. Pareho ang prinsipyong ito sa bawat service na pinapatakbo mo, kaya basahin ang mga service user na may least privilege at ilapat ito sa lahat ng service.

Gumawa ng schema gamit ang --install

--install ang gumagawa ng mga table at nagse-set ng default settings. Itakda ang unang admin login gamit ang environment variables upang umiiral na ang account bago pa man maging reachable ang panel.

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

--yes ang sumasagot sa confirmation prompt. Basahin muna nang isang beses ang prompt bago ito i-automate, dahil ang --install ay para sa unang pag-install at binubura nito ang umiiral na Listmonk schema. Kapag pinatakbo ito ulit sa live database, mabubura ang iyong mga subscriber. Sa anumang script na maaaring tumakbo nang dalawang beses, gamitin ang --install --idempotent --yes. Wala itong ginagawa kapag mayroon na ang mga table. Ang mga pagbabago sa schema na inilabas sa bagong release ay inilalapat gamit ang --upgrade, hindi gamit ang --install.

Suriin ang resulta mula sa database side sa halip na mula sa browser.

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

Inililista ng una ang mga table ng Listmonk, kabilang ang subscribers, lists, campaigns, templates at bounces. Ini-print ng ikalawa ang admin. Kapag walang laman ang resulta ng ikalawa, hindi nakarating sa process ang environment variables. Dahil dito, hihilingin ng panel na gumawa ka ng unang user sa browser.

Patakbuhin ang Listmonk sa ilalim ng systemd

Isulat ang /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

Mahalaga ang WorkingDirectory dahil nire-resolve ng Listmonk ang mga relative path, kabilang ang filesystem media upload path, kaugnay ng path na ito. Inuutos lamang ng After=postgresql.service ang pagsisimula; hindi nito hinihintay na tumanggap ng mga connection ang Postgres. Sinasaklaw ng Restart=on-failure ang sitwasyong masyadong maagang nagsimula ang Listmonk at hindi ito makakonekta.

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

Dapat ipakita ng ss ang 127.0.0.1:9000 sa LISTEN state. Ang anumang HTTP status line na ibinabalik ng curl ay nangangahulugang sumasagot ang server. Kapag nabigo ang curl gamit ang Connection refused, namatay ang process habang nagsisimula, at sasabihin ng journalctl -u listmonk -n 50 --no-pager kung bakit. Tandaan na ang enable --now ang bahaging nananatili pagkatapos ng reboot: mawawala ang prosesong manu-manong sinimulan pagkatapos ng susunod na kernel upgrade.

Ilagay ang nginx at TLS sa unahan

Nagsasalita ang Listmonk ng plain HTTP sa loopback, kaya tina-terminate ng nginx ang TLS (transport layer security) at ipinapasa ang request.

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;
    }
}

Kailangang itaas ang client_max_body_size dahil mga file post ang pag-import ng subscriber at pag-upload ng media. Bilang default, nire-reject ng nginx ang anumang lampas sa 1 MB gamit ang 413 Request Entity Too Large. I-issue ang certificate gamit ang certbot. Isinusulat din nito ang mga linyang listen 443 ssl at ang redirect mula sa port 80. Para sa mga hakbang, tingnan ang gabay sa Let's Encrypt certificate para sa nginx. Buksan ang ports 80 at 443, at panatilihing sarado ang 9000 dahil ina-access ito ng proxy sa pamamagitan ng loopback. Kung hindi pa na-configure ang firewall, magsimula sa mga pangunahing kaalaman sa ufw firewall.

Pagkatapos, buksan ang admin panel at itakda ang root URL sa ilalim ng Settings bilang https://lists.example.com. May taglay na http://localhost:9000 ang bagong install. Isinusulat ng Listmonk ang value na iyon sa bawat unsubscribe link at media URL na inilalagay nito sa isang email. Kung magpapadala ka ng campaign bago ito baguhin, makakatanggap ang bawat recipient ng mga link na tumuturo sa sarili nilang machine. Hindi gumagana ang mga ito para sa mambabasa. Para sa spam filter, mukha itong sender na hindi kayang i-configure ang sarili nitong domain.

Ikonekta ang SMTP na wala sa config.toml

Hanapin ang seksyong SMTP sa config.toml, ngunit wala kang makikitang ganito. Nasa database ang mga setting ng mail, sa talahanayang settings, at ine-edit ang mga ito sa admin panel sa ilalim ng Settings at SMTP. Dahil dito, maikli lang ang nabuong file, at hindi rin kailangan ng restart kapag nagbago ang SMTP.

May dalawang praktikal na opsyon para sa SMTP server mismo. Magpatakbo ng sarili mong server. Sa ganitong paraan, ikaw ang ganap na mamamahala sa reputation nito, ngunit isa itong hiwalay na proyekto: ipinaliliwanag ng pagpapatakbo ng sarili mong mail server gamit ang Mailcow kung ano ang kinakailangan. O ituro ang Listmonk sa isang transactional relay at ipaubaya sa ibang provider ang pamamahala sa IP reputation.

Anuman ang piliin mo, gamitin ang port 587 na may STARTTLS, o port 465 na may implicit TLS. Huwag umasa sa outbound port 25. Karamihan sa mga VPS provider ay nagba-block nito bilang default sa mga bagong account. Ang naka-block na port 25 ay eksaktong parang nakabinbing koneksyon dahil dini-drop ang mga packet sa halip na tanggihan. Kaya naghihintay ang client ng timeout sa halip na agad mabigo.

Subukan ito bago mo ito pagkatiwalaan. Gumawa ng list, idagdag ang sarili mong address bilang subscriber, at magpadala ng campaign sa isang recipient. Buksan ang natanggap na mensahe at basahin ang buong headers. Sasabihin sa iyo ng Authentication-Results header na idinagdag ng tumanggap na server kung pumasa ang SPF at DKIM.

Ang deliverability ang pangunahing gawain

Binubuo ng Listmonk ang mensahe, sinusubaybayan ang listahan, at ipinapasa ang mail. Ang receiving provider ang nagpapasya kung makararating ang mail sa inbox, gamit ang sending IP address at sending domain. Walang history ang bagong VPS IP, at itinuturing ito ng lahat ng malalaking mailbox provider na bahagyang kahina-hinala.

Hindi optional ang apat na bagay na ito:

  • Isang SPF (sender policy framework) TXT record na tumutukoy sa host na awtorisadong magpadala para sa iyong domain.
  • Isang DKIM (domainkeys identified mail) key na naka-publish bilang TXT record. Dapat ang mail server ang lumagda rito, hindi ang Listmonk.
  • Isang DMARC (domain based message authentication, reporting and conformance) record na nagsasabi sa mga receiver kung ano ang gagawin kapag nabigo ang unang dalawa.
  • Isang bounce mailbox na binabasa ng Listmonk, upang maalis sa listahan ang mga address na tumatanggi sa mail sa halip na paulit-ulit na subukan ang pagpapadala.

Pagkatapos, mabagal muna ang pagpapadala. Ang domain na hindi pa kailanman nagpadala ng mail at biglang naghahatid ng sampung libong mensahe sa loob ng isang oras ay eksaktong kahawig ng isang compromised account, kaya ifi-filter ito bilang ganoon. Magsimula sa mga subscriber na pinakamadalas makipag-ugnayan at dagdagan ang volume sa loob ng ilang araw.

Kailangan din ng bawat template ng gumaganang unsubscribe link. Sa isang Listmonk template, ito ay {{ UnsubscribeURL }}, at mapupunta ang campaign body sa puwesto ng {{ template "content" . }}, na dapat lumitaw nang eksaktong isang beses sa bawat template. Ang campaign na walang unsubscribe link ay nagdudulot ng spam complaints sa halip na mga unsubscribe, at ang mga complaint ang pinakamabilis na paraan para mawala ang sending reputation na ilang linggo mong binuo.

Mga Backup, at kung ano ang aktuwal na kailangan para sa restore

Dalawang bagay ang kailangang ilabas sa server: ang database dump at ang config.toml. Idagdag ang media directory kung nag-a-upload ka ng mga image sa mga campaign.

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

Nasa dump na iyon ang mga subscriber, campaign, template, at lahat ng setting, kabilang ang SMTP credentials. Kaya i-encrypt ito at itago sa labas ng server na ito. Nalutas na ang pag-schedule nito: tingnan ang mga naka-encrypt na restic backup sa remote storage. Kaunti lang ang laman ng config.toml, pero naglalaman ito ng database password, kaya ituring ito sa parehong paraan.

May isang takdang pagkakasunod-sunod ang mga upgrade. Ihinto ang service, gumawa ng dump, palitan ang binary sa /usr/bin, patakbuhin ang listmonk --config /etc/listmonk/config.toml --upgrade, at pagkatapos ay simulan ang service. Pasulong lamang tumatakbo ang mga schema migration, kaya ang dump na iyon ang tanging paraan para makabalik sa dating estado.

Bakit hindi nagsisimula ang Listmonk?

Basahin muna ang journal gamit ang journalctl -u listmonk -n 50 --no-pager. Halos lahat ng startup failure ay makikita sa isang linya sa block na [db].

Ang pq: password authentication failed for user "listmonk" ay nangangahulugang hindi tugma ang password sa [db] sa Postgres role. Ang prefix na pq ay ulat ng Postgres driver tungkol sa pagtanggi ng server. Ibig sabihin, nabasa nang tama ang config ngunit mali ang credentials. I-reset ang role gamit ang sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" at ilagay ang kaparehong string sa file.

Ang pq: database "listmonk" does not exist ay nangangahulugang ang value na database sa [db] ay hindi tumutukoy sa isang aktuwal na database. Inililista ng sudo -u postgres psql -l ang mga database na tunay na nasa server, kasama ang maling spelling na nagamit mo.

Ang permission denied habang isinasagawa ang --install ay nangangahulugang nakakakonekta ang role ngunit hindi ito ang may-ari ng database, kaya hindi ito makagawa ng mga table dito. Ayusin ito gamit ang sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" at patakbuhin muli ang install.

Hindi kailanman nagsisimula ang service at binabanggit ng journal ang config file. Hindi mabuksan ng prosesong tumatakbo bilang listmonk ang config.toml kapag ang owner nito ay root:root at ang mode ay 600. Dapat i-print ng stat -c '%U:%G %a' /etc/listmonk/config.toml ang root:listmonk 640, at dapat root:listmonk 750 ang directory na nasa itaas nito.

Gumagana ang panel ngunit walang dumarating na mail. Hindi ito startup problem. Suriin muna ang Settings at SMTP, pagkatapos ay ang sariling log ng campaign sa admin panel. Itinatala nito ang error na ibinalik ng mail server sa bawat pagtatangka.

FAQ

Kailangan ko ba ng sarili kong mail server para magamit ang Listmonk?

Hindi. Ang Listmonk ay hindi mail server. Kailangan nito ng SMTP credentials para sa server na tumatanggap at naghahatid ng iyong mail. Maaari itong transactional relay o mail server na ikaw mismo ang nagpapatakbo. Itakda ang mga credential na ito sa Settings at SMTP sa admin panel, hindi sa config.toml, dahil nasa database ang mga mail setting. Gamitin ang port 587 na may STARTTLS o port 465 na may implicit TLS, dahil bina-block ng karamihan sa VPS provider ang outbound port 25 sa mga bagong account.

Nakatakda pa rin ang root URL sa default ng installation na http://localhost:9000. Isinusulat ng Listmonk ang halagang iyon sa mga unsubscribe link at media URL kapag ipinapadala ang campaign. Buksan ang Settings sa admin panel, itakda ang root URL sa iyong aktuwal na HTTPS address, at i-save ito. Hindi na maitatama ang mga mensaheng naihatid na, kaya magpadala muna ng test campaign sa iyong sarili at i-click ang unsubscribe link bago magpadala sa aktuwal na listahan.

Buburahin ba ng muling pagpapatakbo ng --install ang aking mga subscriber?

Oo. Ang --install ang installer sa unang pag-install at binabagsak nito ang kasalukuyang Listmonk schema. Inaalis naman ng --yes ang prompt na magbababala sa iyo tungkol dito. Sa anumang script na maaaring mapatakbo nang dalawang beses, gamitin ang --install --idempotent --yes. Wala itong ginagawa kapag mayroon na ang mga table. Para ilapat ang mga pagbabago sa schema sa isang bagong release, ihinto ang service, gumawa ng pg_dump, at pagkatapos ay patakbuhin ang --upgrade.

Bakit sinasabi ng Listmonk na nabigo ang password authentication para sa user na listmonk?

Hindi tugma ang password sa [db] block ng /etc/listmonk/config.toml sa Postgres role na may parehong pangalan. Ang journal line ay pq: password authentication failed for user "listmonk", at ang pq ang Postgres driver na nagpapasa ng pagtanggi ng server. Ibig sabihin nito, nakita at nabasa ang config file. I-reset ang password ng role gamit ang sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", isulat ang kaparehong string sa config file, at pagkatapos ay patakbuhin ang sudo systemctl restart listmonk.