SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-07

VPS پر Listmonk newsletter خود host کرنے کا طریقہ

Ubuntu 24.04 پر Listmonk v6.2.0، PostgreSQL 16، config.toml، systemd اور TLS ترتیب دیں، SMTP جوڑیں اور جانیں کہ delivery reputation بنانے میں کئی ہفتے لگتے ہیں۔

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

خود میزبانی شدہ newsletter کے لیے Listmonk کو درکار چیزیں

Listmonk خود میزبانی شدہ newsletter اور mailing list manager ہے: ایک Go binary، ایک PostgreSQL database، ایک config file، اور ایک systemd unit۔ ایک چھوٹا VPS اسے آسانی سے چلا سکتا ہے، کیونکہ Listmonk subscribers کو محفوظ اور campaigns کو queue کرتا ہے، لیکن خود email deliver نہیں کرتا۔ یہ ہر message ایک SMTP (simple mail transfer protocol) server کو بھیجتا ہے، اس لیے آپ کی delivery rate کا فیصلہ اس server کی reputation کرتی ہے، اس software کا نہیں۔

یہ guide Ubuntu 24.04 پر Listmonk v6.2.0 انسٹال کرتی ہے، جو July 2026 تک موجودہ release ہے۔ آپ کو public IP address والا VPS، اپنے اختیار میں ایک domain name، اور PostgreSQL 12 یا اس کے بعد کا ورژن درکار ہے۔ انسٹالیشن میں تقریباً ایک گھنٹہ لگتا ہے۔ Sending reputation بنانے میں کئی ہفتے لگتے ہیں، اور اس حصے کا احاطہ آخر میں کیا گیا ہے۔

PostgreSQL انسٹال کریں اور database بنائیں

Ubuntu 24.04 کی اپنی repository میں PostgreSQL 16 شامل ہے، جو Listmonk کی ضرورت سے کافی نیا ہے۔

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

ایک ہی psql session میں role اور database بنائیں۔ -v ON_ERROR_STOP=1 سے پہلی ناکام statement پر psql خارج ہو جاتا ہے، اس لیے typo کی وجہ سے آدھی configuration مکمل دکھائی نہیں دیتی۔

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 محض ظاہری چیز نہیں ہے۔ Schema installation میں tables، types، indexes اور functions بنتے ہیں، اس لیے role کا database کا مالک ہونا ضروری ہے۔ Listmonk کو ایسے database کی طرف متوجہ کریں جس کا مالک کوئی دوسرا role ہو تو installation permission denied کے ساتھ رک جاتی ہے، چاہے آپ GRANT CONNECT چلا چکے ہوں۔

آگے بڑھنے سے پہلے تصدیق کریں کہ database موجود ہے۔

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

اس سے listmonk ظاہر ہوگا۔ خالی سطر کا مطلب ہے کہ CREATE statement چلی ہی نہیں، اس لیے psql کا output دوبارہ پڑھیں۔

Listmonk بائنری انسٹال کریں

Listmonk ہر architecture کے لیے ایک static binary جاری کرتا ہے۔ پہلے اپنے architecture کی تصدیق کریں، کیونکہ ARM VPS پر amd64 binary ایسی file ہوتی ہے جسے kernel execute کرنے سے انکار کر دیتا ہے۔

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 پر file name میں amd64 کو arm64 سے تبدیل کریں۔ listmonk --version سے version string ظاہر ہونا اس بات کا پہلا ثبوت ہے کہ binary مشین کے مطابق ہے۔

config.toml بنائیں اور اس کی رسائی محدود کریں

--new-config موجودہ working directory میں 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 server کو صرف loopback پر bind کرتا ہے، اس لیے جب تک آپ اس کے سامنے reverse proxy نہ رکھیں، admin panel internet سے قابلِ رسائی نہیں ہوتا۔ اس لائن کو تبدیل نہ کریں۔ [db] کے تحت آپ کو host = "localhost"، port = 5432، user = "listmonk"، database = "listmonk" اور ssl_mode = "disable" ملتے ہیں۔ یہ defaults پہلے بنائے گئے database سے مطابقت رکھتے ہیں، اس لیے آپ کو صرف password والی لائن تبدیل کرنی ہے۔

جب Postgres اسی machine پر loopback پر listen کر رہا ہو تو ssl_mode = "disable" درست ہے، کیونکہ یہ traffic machine سے باہر نہیں جاتا۔ Database کو کسی دوسرے host پر منتقل کریں تو اسے require پر set کریں، ورنہ password network پر cleartext میں منتقل ہوگا۔

[db] کے تحت password والی لائن میں ایسی قدر لکھیں جو role سے match کرے، پھر service account بنائیں اور فائل کو ہر دوسرے 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

اب service account فائل پڑھ سکتا ہے اور کوئی دوسرا اسے نہیں پڑھ سکتا۔

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

پہلی command readable print کرتی ہے۔ دوسری root:listmonk 640 print کرتی ہے۔ کوئی بھی دوسرا unprivileged account اسی cat کو چلانے کی کوشش کرے تو اسے Permission denied ملتا ہے۔ یہی مقصد ہے: اس فائل میں database password cleartext میں موجود ہے، اور ایک server پر عموماً ایک سے زیادہ login ہوتے ہیں۔ یہی اصول ہر service پر لاگو ہوتا ہے، اس لیے کم از کم مراعات والے service users کے بارے میں ایک بار پڑھیں اور اسے ہر جگہ نافذ کریں۔

--install کے ساتھ schema بنائیں

--install tables بناتا ہے اور default settings شامل کرتا ہے۔ environment variables کے ذریعے پہلا admin login مقرر کریں، تاکہ panel کے قابلِ رسائی ہونے سے پہلے ہی account موجود ہو۔

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

--yes confirmation prompt کا جواب دیتا ہے۔ اسے automate کرنے سے پہلے اس prompt کو ایک بار پڑھیں، کیونکہ --install پہلی بار installer ہے اور موجودہ Listmonk schema حذف کر دیتا ہے۔ live database پر اسے دوسری بار چلانے سے آپ کے subscribers ختم ہو جاتے ہیں۔ ایسی کسی script میں جو دوبارہ چل سکتی ہو، --install --idempotent --yes استعمال کریں؛ tables پہلے سے موجود ہوں تو یہ کچھ نہیں کرتا۔ نئی release میں شامل schema changes کو --upgrade کے ذریعے apply کریں، --install کے ذریعے نہیں۔

نتیجہ browser کے بجائے database کی طرف سے check کریں۔

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

پہلی command Listmonk tables کی فہرست دکھاتی ہے، جن میں subscribers، lists، campaigns، templates اور bounces شامل ہیں۔ دوسری admin print کرتی ہے۔ دوسری command کا خالی نتیجہ ظاہر کرتا ہے کہ environment variables process تک نہیں پہنچے۔ ایسی صورت میں panel browser میں پہلا user بنانے کو کہے گا۔

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 متعلقہ paths، بشمول filesystem media upload path، اسی path کے نسبت سے resolve کرتا ہے۔ After=postgresql.service صرف start کا order متعین کرتا ہے؛ یہ Postgres کے connections قبول کرنے تک انتظار نہیں کرتا۔ اس لیے Restart=on-failure اس صورت کو handle کرتا ہے جب Listmonk کچھ پہلے start ہو جائے اور connect نہ کر سکے۔

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 state میں دکھائی دینا چاہیے۔ curl سے کوئی بھی HTTP status line واپس آنے کا مطلب ہے کہ server جواب دے رہا ہے۔ اگر curl، Connection refused کے ساتھ fail ہو تو اس کا مطلب ہے کہ process startup کے دوران ختم ہو گیا؛ journalctl -u listmonk -n 50 --no-pager وجہ بتائے گا۔ یاد رکھیں کہ reboot کے بعد برقرار رہنے والا حصہ enable --now ہے: ہاتھ سے start کیا گیا process اگلے kernel upgrade کے بعد ختم ہو جاتا ہے۔

nginx اور TLS سامنے رکھیں

Listmonk loopback پر سادہ HTTP فراہم کرتا ہے، اس لیے nginx TLS (transport layer security) کو terminate کرتا ہے اور درخواست آگے بھیج دیتا ہے۔

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 کو بڑھانا ضروری ہے، کیونکہ subscriber imports اور media uploads فائل پوسٹس ہیں، جبکہ nginx ڈیفالٹ طور پر 1 MB سے بڑی ہر چیز کو 413 Request Entity Too Large کے ساتھ مسترد کرتا ہے۔ certbot کے ذریعے certificate جاری کریں؛ یہ آپ کے لیے listen 443 ssl والی سطریں اور port 80 سے redirect بھی لکھ دیتا ہے۔ طریقہ nginx کے لیے Let's Encrypt certificate guide میں موجود ہے۔ ports 80 اور 443 کھولیں، اور 9000 بند رکھیں، کیونکہ proxy اس تک loopback کے ذریعے پہنچتا ہے۔ اگر firewall میں ابھی تک کوئی configuration نہیں کی گئی تو ufw firewall basics سے شروع کریں۔

اس کے بعد admin panel کھولیں اور Settings کے تحت root URL کو https://lists.example.com پر set کریں۔ نئی installation میں http://localhost:9000 موجود ہوتا ہے، اور Listmonk ہر unsubscribe link اور media URL میں یہی value لکھتا ہے جو وہ email میں شامل کرتا ہے۔ اسے تبدیل کرنے سے پہلے campaign بھیجیں تو ہر recipient کو اپنے ہی machine کی طرف اشارہ کرنے والے links ملیں گے۔ یہ links قاری کے لیے کام نہیں کریں گے، اور spam filter کو بھیجنے والا ایسا شخص معلوم ہوگا جو اپنے domain کو configure نہیں کر سکتا۔

SMTP جو config.toml میں موجود نہیں ہے، منسلک کریں

config.toml میں SMTP کا section تلاش کریں؛ آپ کو یہ نہیں ملے گا۔ Mail settings database کے settings table میں محفوظ ہوتی ہیں، اور آپ انہیں admin panel میں Settings اور SMTP کے تحت edit کرتے ہیں۔ اسی لیے generated file اتنی مختصر رہتی ہے، اور SMTP میں تبدیلی کے لیے restart بھی درکار نہیں ہوتا۔

خود SMTP server کے لیے دو عملی options ہیں۔ اپنا server چلائیں، جس میں reputation مکمل طور پر آپ کی ذمہ داری ہوتی ہے اور جو بذاتِ خود ایک مکمل project ہے: Mailcow کے ساتھ اپنا mail server چلانا اس کے طریقۂ کار کی وضاحت کرتا ہے۔ یا Listmonk کو transactional relay کی طرف point کریں اور IP reputation کسی دوسرے provider کے سپرد کر دیں۔

دونوں صورتوں میں port 587 کو STARTTLS کے ساتھ، یا port 465 کو implicit TLS کے ساتھ استعمال کریں۔ outbound port 25 پر انحصار نہ کریں۔ زیادہ تر VPS providers نئے accounts پر اسے default طور پر block کرتے ہیں۔ blocked port 25 بالکل hung connection جیسا دکھائی دیتا ہے، کیونکہ packets refuse ہونے کے بجائے drop ہو جاتے ہیں۔ اس لیے client فوراً fail ہونے کے بجائے timeout کا انتظار کرتا ہے۔

اس پر اعتماد کرنے سے پہلے test کریں۔ ایک list بنائیں، اپنے address کو subscriber کے طور پر شامل کریں، اور ایک recipient campaign بھیجیں۔ موصول ہونے والا message کھولیں اور مکمل headers پڑھیں۔ receiving side کی جانب سے شامل کیا گیا Authentication-Results header بتاتا ہے کہ SPF اور DKIM pass ہوئے یا نہیں۔

ترسیل پذیری ہی پورا کام ہے

Listmonk پیغام تیار کرتا ہے، فہرست کو track کرتا ہے، اور mail آگے بھیج دیتا ہے۔ یہ فیصلہ کہ mail inbox تک پہنچے گی یا نہیں، receiving provider کرتا ہے، جو sending IP address اور sending domain استعمال کرتا ہے۔ نئے VPS IP کی کوئی سابقہ تاریخ نہیں ہوتی، اور ہر بڑا mailbox provider ایسی بے سابقہ تاریخ کو معمولی طور پر مشتبہ سمجھتا ہے۔

چار چیزیں لازمی ہیں:

  • ایک SPF (sender policy framework) TXT record، جس میں آپ کے domain کی طرف سے mail بھیجنے کی اجازت رکھنے والے host کا نام ہو۔
  • ایک DKIM (domainkeys identified mail) key، جو TXT record کے طور پر publish کی گئی ہو۔ Signing Listmonk کے بجائے mail server کرے۔
  • ایک DMARC (domain based message authentication, reporting and conformance) record، جو receivers کو بتائے کہ پہلی دو تصدیقات ناکام ہونے پر کیا کرنا ہے۔
  • ایک bounce mailbox جسے Listmonk پڑھ سکے، تاکہ mail مسترد کرنے والے addresses فہرست سے نکل جائیں اور انہیں ہمیشہ دوبارہ try نہ کیا جائے۔

اس کے بعد ابتدا میں آہستہ mail بھیجیں۔ ایسا domain جس نے پہلے کبھی mail نہ بھیجی ہو اور اچانک ایک گھنٹے میں دس ہزار messages deliver کر دے، بالکل compromised account جیسا دکھائی دیتا ہے، اس لیے اسے بھی اسی طرح filter کیا جاتا ہے۔ پہلے اپنے سب سے زیادہ engaged subscribers کو mail بھیجیں اور کئی دنوں میں volume بڑھائیں۔

ہر template میں working unsubscribe link بھی ضروری ہے۔ Listmonk template میں یہ {{ UnsubscribeURL }} ہوتا ہے، اور campaign body وہاں شامل ہوتی ہے جہاں {{ template "content" . }} موجود ہو۔ {{ template "content" . }} ہر template میں بالکل ایک بار ہونا چاہیے۔ جس campaign میں unsubscribe link نہ ہو، اس سے unsubscribes کے بجائے spam complaints موصول ہوتی ہیں، اور complaints اس sending reputation کو ختم کرنے کا تیز ترین طریقہ ہیں جسے بنانے میں آپ نے کئی ہفتے صرف کیے ہوں۔

بیک اپس، اور restore کے لیے درکار اصل چیزیں

دو چیزیں server سے باہر محفوظ ہونی چاہییں: database dump اور config.toml۔ اگر campaigns میں images upload کرتے ہیں تو media directory بھی شامل کریں۔

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

اس dump میں subscribers، campaigns، templates اور ہر setting شامل ہوتی ہے، جن میں SMTP credentials بھی شامل ہیں۔ اسے encrypt کریں اور اس server سے باہر محفوظ رکھیں۔ Scheduling کا مسئلہ حل شدہ ہے: remote storage کے لیے encrypted restic backups دیکھیں۔ config.toml چند lines پر مشتمل ہے، لیکن اس میں database password ہوتا ہے، اس لیے اسے بھی اسی طرح محفوظ رکھیں۔

Upgrades ایک مقررہ ترتیب کے مطابق کریں۔ Service stop کریں، dump لیں، /usr/bin میں binary replace کریں، listmonk --config /etc/listmonk/config.toml --upgrade چلائیں، پھر service start کریں۔ Schema migrations صرف آگے کی سمت چلتی ہیں، اس لیے واپس جانے کا واحد طریقہ یہی dump ہے۔

Listmonk شروع کیوں نہیں ہوتا؟

پہلے journalctl -u listmonk -n 50 --no-pager کے ذریعے journal پڑھیں۔ تقریباً ہر startup failure، [db] block میں موجود ایک سطر میں درج ہوتا ہے۔

pq: password authentication failed for user "listmonk" کا مطلب ہے کہ [db] میں موجود password، Postgres role سے مطابقت نہیں رکھتا۔ pq prefix اس بات کی نشاندہی کرتا ہے کہ Postgres driver نے server کا rejection رپورٹ کیا ہے، اس لیے config درست طور پر پڑھی گئی تھی اور credentials غلط تھے۔ sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" کے ذریعے role reset کریں اور file میں بالکل وہی string درج کریں۔

pq: database "listmonk" does not exist کا مطلب ہے کہ [db] میں موجود database value کسی حقیقی database کا نام نہیں ہے۔ sudo -u postgres psql -l server پر موجود اصل databases کی فہرست دکھاتا ہے، جس میں وہ spelling بھی شامل ہو سکتی ہے جو آپ نے غلط استعمال کی تھی۔

permission denied، --install کے دوران ظاہر ہونے کا مطلب ہے کہ role connect کر سکتا ہے، لیکن database کا مالک نہیں ہے؛ اس لیے وہ اس میں tables نہیں بنا سکتا۔ sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" کے ذریعے اسے درست کریں اور install دوبارہ چلائیں۔

Service کبھی شروع نہیں ہوتی اور journal config file کا نام دکھاتا ہے۔ listmonk کے طور پر چلنے والا process، ایسی config.toml کو نہیں کھول سکتا جس کی ملکیت root:root کے طور پر مقرر ہو اور mode 600 ہو۔ stat -c '%U:%G %a' /etc/listmonk/config.toml کو root:listmonk 640 دکھانا چاہیے، اور اس کے اوپر موجود directory کو root:listmonk 750 ہونا چاہیے۔

Panel کام کرتا ہے، لیکن کوئی mail موصول نہیں ہوتی۔ یہ startup problem نہیں ہے۔ پہلے Settings اور SMTP چیک کریں، پھر admin panel میں campaign کا اپنا log دیکھیں۔ یہ ہر کوشش کے لیے mail server کی جانب سے واپس کیا گیا error درج کرتا ہے۔

FAQ

کیا Listmonk استعمال کرنے کے لیے اپنا mail server ضروری ہے؟

نہیں۔ Listmonk mail server نہیں ہے۔ اسے ایسے server کے SMTP credentials درکار ہوتے ہیں جو آپ کی mail قبول کرکے اسے deliver کرے۔ یہ transactional relay یا آپ کا اپنا mail server ہو سکتا ہے۔ Admin panel میں Settings اور SMTP کے تحت یہ credentials درج کریں، config.toml میں نہیں، کیونکہ mail settings database میں محفوظ ہوتی ہیں۔ STARTTLS کے ساتھ port 587 یا implicit TLS کے ساتھ port 465 استعمال کریں، کیونکہ زیادہ تر VPS providers نئے accounts پر outbound port 25 block کرتے ہیں۔

Root URL setting ابھی install کے default http://localhost:9000 پر ہے۔ Listmonk campaign بھیجے جانے کے وقت اس value کو unsubscribe links اور media URLs میں شامل کرتا ہے۔ Admin panel میں Settings کھولیں، root URL کو اپنے حقیقی HTTPS address پر set کریں، اور save کریں۔ پہلے سے deliver کیے گئے messages درست نہیں کیے جا سکتے، اس لیے حقیقی list کو mail کرنے سے پہلے خود کو test campaign بھیجیں اور اس میں unsubscribe link پر click کریں۔

کیا --install دوبارہ چلانے سے میرے subscribers حذف ہو جائیں گے؟

ہاں۔ --install پہلی بار چلانے والا installer ہے اور یہ موجودہ Listmonk schema حذف کر دیتا ہے، جبکہ --yes وہ prompt ہٹا دیتا ہے جو آپ کو خبردار کرتا۔ ایسی کسی script میں جو دوبارہ چل سکتی ہو، --install --idempotent --yes استعمال کریں۔ tables پہلے سے موجود ہوں تو یہ کچھ نہیں کرتا۔ نئی release میں schema changes لاگو کرنے کے لیے service روکیں، pg_dump لیں، پھر --upgrade چلائیں۔

Listmonk user listmonk کے لیے password authentication failed کیوں دکھاتا ہے؟

/etc/listmonk/config.toml کے [db] block میں موجود password اسی نام کے Postgres role کے password سے مطابقت نہیں رکھتا۔ Journal line pq: password authentication failed for user "listmonk" ہے، اور pq Postgres driver کی طرف سے server کے rejection کو آگے منتقل ہونے کی نشاندہی کرتا ہے۔ اس کا مطلب ہے کہ config file مل گئی اور پڑھی گئی۔ sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" کے ذریعے role کا password reset کریں، config file میں وہی string درج کریں، پھر sudo systemctl restart listmonk چلائیں۔