Docker سے VPS پر Chatwoot self-host کرنے کا طریقہ
Docker Compose اور Traefik کے ساتھ VPS پر Chatwoot چلائیں: pinned tags، قابلِ اعتماد SMTP، Postgres اور uploads backups، اور محفوظ upgrades کی مکمل ترتیب۔
آپ کیا بنا رہے ہیں
VPS پر Chatwoot کو self-host کرنے کے لیے آپ چار containers چلاتے ہیں: Rails web process، Sidekiq background worker، PostgreSQL جس میں pgvector extension شامل ہے، اور Redis۔ Chatwoot ایک open source customer support desk ہے، اس لیے آپ کو اپنے زیرِ انتظام سرور پر shared team inbox اور website chat widget ملتا ہے۔ تنصیب میں تقریباً twenty minutes لگتے ہیں۔ اس کے بعد mail delivery، backups، upgrades اور sizing یہ طے کرتے ہیں کہ یہ سسٹم ایک سال بعد بھی چل رہا ہوگا یا نہیں۔
ہر container کا ایک کام ہے۔ Rails agent dashboard اور widget API (application programming interface) فراہم کرتا ہے۔ Sidekiq سست کام چلاتا ہے: email بھیجنا، منسلک channels کو poll کرنا، automation rules چلانا اور reports بنانا۔ Postgres conversations، contacts، agent accounts اور dashboard میں تبدیل کی جانے والی ہر setting محفوظ کرتا ہے۔ Redis Sidekiq queues اور ActionCable pub/sub channel محفوظ کرتا ہے۔ یہی channel نیا message کھلے ہوئے dashboard میں page reload کے بغیر پہنچاتا ہے۔ یہاں Redis عارضی cache نہیں ہے، کیونکہ اسے کھونے کا مطلب queued jobs کھونا ہے۔
upstream compose file میں Postgres image عام postgres image کے بجائے pgvector/pgvector:pg16 ہے، کیونکہ Chatwoot کا schema اپنی AI features کے لیے vector extension فعال کرتا ہے۔ stock Postgres استعمال کرنے سے database کی پہلی run ERROR: extension "vector" is not available پر رک جاتی ہے، کیونکہ اس image میں extension کی control file موجود نہیں ہوتی۔ وہی image استعمال کریں جو upstream release کرتا ہے۔
یہ guide فرض کرتی ہے کہ Docker اور reverse proxy پہلے سے اس server پر درست طور پر کام کر رہے ہیں۔ اگر ایسا نہیں ہے تو VPS پر Docker Compose سے شروع کریں اور پھر واپس آئیں۔
self-hosted Chatwoot کے لیے کتنے وسائل والا VPS درکار ہے؟
August 2026 تک upstream requirements page کم از کم 4 GB RAM اور 4 CPU cores تجویز کرتا ہے، اور اسے روزانہ 10,000 تک conversations کے لیے موزوں قرار دیتا ہے۔ اس کے مطابق 8 GB RAM اور 8 cores روزانہ 20,000 تک conversations کے لیے کافی ہیں۔ اس میں کم از کم 1 GB swap کی شرط بھی ہے، اور وجہ بھی واضح کی گئی ہے: upgrade کے دوران machine memory سے خالی نہ ہو۔ File uploads کو شمار کرنے سے پہلے Postgres کے لیے 5 GB سے 10 GB disk space رکھیں۔
اب اصل بات۔ 2 GB VPS پر Chatwoot boot ہو جاتا ہے، اور دو agents اور کم سرگرم inbox کے ساتھ بظاہر ٹھیک چلتا ہے۔ لیکن دو صورتوں میں یہ ناکام ہو جاتا ہے۔ پہلی صورت Sidekiq ہے، جسے upstream مصروف server پر 1 GB سے زیادہ memory استعمال کرنے والا بتاتا ہے۔ اس لیے email یا report job کا اچانک بوجھ machine کی memory ختم کر دیتا ہے، اس سے پہلے کہ Rails، Postgres اور Redis اپنا حصہ لے سکیں۔ دوسری صورت upgrade ہے، کیونکہ db:chatwoot_prepare migrations لاگو کرنے کے لیے نیا Rails process boot کرتا ہے، اور اس image میں Rails boot کسی مفید کام سے پہلے ہی سینکڑوں megabytes استعمال کرتا ہے۔
آپ کو پہلے کوئی واضح warning نہیں ملتی۔ Kernel کا out of memory killer سب سے بڑے process کو SIGKILL بھیج دیتا ہے، Docker container کے ختم ہونے کو دیکھتا ہے، اور restart: always اسے دوبارہ start کر دیتا ہے۔ docker compose ps پھر ایسا container دکھاتا ہے جو بار بار Exited (137) پر واپس آتا ہے، جہاں 137 کا مطلب signal 9 سے ختم ہونا ہے۔ sudo dmesg -T | grep -i "killed process" سے اس کی تصدیق کریں؛ یہ وہ process دکھاتا ہے جسے kernel نے منتخب کیا تھا۔
اگر 4 GB budget سے باہر ہو تو 2 GB machine کو 2 GB swap کے ساتھ چلائیں، اور یہ قبول کریں کہ load کے دوران response times بڑھ جائیں گے، بجائے اس کے کہ service مکمل طور پر بند ہو جائے۔ ہر service کے لیے hard memory ceiling مقرر کرنا بہرحال مفید ہے، تاکہ worker اپنے ساتھ database کو بھی بند نہ کر دے۔ Docker Compose میں memory limits دیکھیں۔
File uploads وہ حصہ ہیں جو آپ کی مقرر کردہ حد کے بغیر بڑھتا رہتا ہے۔ Customer کی منسلک کی ہوئی ہر screenshot storage volume میں محفوظ ہوتی ہے اور وہیں رہتی ہے، اس لیے یہ فرض نہ کریں کہ disk database کی وجہ سے بھر رہی ہے؛ docker system df -v کو monitor کریں۔
compose فائل حاصل کریں اور version tag مقرر کریں
mkdir -p ~/chatwoot && cd ~/chatwoot
wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example
wget -O docker-compose.yaml https://raw.githubusercontent.com/chatwoot/chatwoot/develop/docker-compose.production.yaml
chmod 600 .envآپ نے ابھی جو فائل ڈاؤن لوڈ کی ہے، اس میں image: chatwoot/chatwoot:latest درج ہے۔ کوئی اور کام کرنے سے پہلے اسے تبدیل کریں۔
services:
base: &base
image: chatwoot/chatwoot:v4.16.2
env_file: .env
volumes:
- storage_data:/app/storagelatest کا مطلب ہے کہ اگلا docker compose pull اس صبح شائع ہونے والی ہر چیز حاصل کرے گا۔ اس میں ایسی major version بھی شامل ہو سکتی ہے جس کی migrations کے بارے میں آپ نے کبھی نہیں پڑھا۔ عملی طور پر Chatwoot migrations کو واپس نہیں کیا جا سکتا، اس لیے غیر ارادی version jump کی صورت میں حل backup سے restore کرنا ہے، اسے undo کرنا نہیں۔ tag مقرر کریں اور اسے جان بوجھ کر تبدیل کریں۔ August 2026 تک v4.16.2 موجودہ release تھی؛ آج مقرر کیے جانے والے tag کے لیے releases page دیکھیں۔
base service ایک YAML anchor ہے، جسے rails اور sidekiq دونوں merge کرتے ہیں۔ اس لیے ایک جگہ tag تبدیل کرنے سے دونوں کے لیے tag تبدیل ہو جاتا ہے۔ فائل میں موجود ہونے کے دوران اوپر والی version: '3' line حذف کریں۔ جدید Compose اسے نظرانداز کرتا ہے اور ہر command پر the attribute 'version' is obsolete, it will be ignored دکھاتا ہے۔
.env فائل مکمل کریں
پہلے secret generate کریں۔ Upstream alphanumeric value مانگتا ہے، کیونکہ special characters کو shell یا YAML parser سے گزرتے وقت درست طور پر parse نہیں کیا جاتا۔
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 63 ; echo ''پھر .env میں یہ keys set کریں۔
SECRET_KEY_BASE=<the 63 characters you just generated>
FRONTEND_URL=https://support.example.com
FORCE_SSL=true
DEFAULT_LOCALE=en
ENABLE_ACCOUNT_SIGNUP=true
POSTGRES_HOST=postgres
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=<long random string>
POSTGRES_DATABASE=chatwoot
REDIS_URL=redis://redis:6379
REDIS_PASSWORD=<a different long random string>
RAILS_ENV=production
INSTALLATION_ENV=docker
ACTIVE_STORAGE_SERVICE=localPOSTGRES_HOST=postgres اور redis://redis:6379 Compose service names ہیں، جو project کے default network پر resolve ہوتے ہیں۔ FRONTEND_URL محض ظاہری configuration نہیں ہے۔ Chatwoot اسی value سے widget script URL اور outgoing email کے اندر موجود ہر link بناتا ہے۔ اس لیے غلط value سے password reset links ایسے host کی طرف جائیں گے جو جواب نہیں دیتا۔
اب upstream فائل میں موجود مسئلہ دیکھیں۔ postgres service .env کو read نہیں کرتی۔ اس کے اپنے environment block میں POSTGRES_PASSWORD= خالی ہے۔ اس لیے صرف .env میں password set کرنے سے database کے پاس password نہیں ہوگا، جبکہ application کے پاس password ہوگا۔ Service کو اسی variable کی طرف point کریں:
postgres:
image: pgvector/pgvector:pg16
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=chatwoot
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}Compose project directory سے .env read کرتا ہے تاکہ ${...} substitution ہو سکے۔ اس طرح دونوں طرف ایک ہی string استعمال ہوگی۔ اگر یہ غلط ہو تو Rails PG::ConnectionBad: FATAL: password authentication failed for user "postgres" کے ساتھ رک جاتا ہے۔
ایک رویہ تقریباً سب کو حیران کرتا ہے: Postgres image POSTGRES_PASSWORD کو صرف اس وقت apply کرتی ہے جب وہ empty data directory کو initialise کرتی ہے۔ بعد میں value تبدیل کرنے کا کوئی اثر نہیں ہوتا، کیونکہ initdb دوسری بار run نہیں ہوتا۔ اگر آپ stack پہلے ہی ایک بار start کر چکے ہیں تو اسے database کے اندر تبدیل کریں۔
docker compose exec postgres psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'the-new-password';"ENABLE_ACCOUNT_SIGNUP=true عارضی ہے۔ یہ public registration form کھولتا ہے تاکہ آپ پہلا account بنا سکیں۔ اپنا account بننے کے فوراً بعد اسے false پر set کریں اور docker compose up -d دوبارہ run کریں۔ بصورت دیگر URL تلاش کرنے والا کوئی بھی شخص آپ کے support desk پر register کر سکتا ہے۔ اس کے بعد agents invitation کے ذریعے شامل ہوں گے اور ان کے passwords صرف اسی app میں محفوظ رہیں گے۔ یہ اس وقت تک مناسب ہے جب تک آپ تقریباً آدھی درجن services نہ چلا رہے ہوں اور ہر service میں الگ account list برقرار رکھنے سے اکتا نہ جائیں۔ اس مرحلے پر Authentik جیسا self-hosted identity provider ان account lists کی جگہ لے سکتا ہے۔
.env اب اس stack کے تمام secrets plain text میں رکھتا ہے۔ اسے mode 600 پر رکھیں اور git سے باہر رکھیں۔ Compose env files کو کیسے read کرتا ہے اور secrets کہاں leak ہوتے ہیں میں اہم احتیاطیں بیان کی گئی ہیں، جن میں env_file اور environment کا فرق بھی شامل ہے۔
موجودہ Traefik کے پیچھے Chatwoot رکھیں
ایک ایپ کے لیے دوسرا reverse proxy نہ بنائیں۔ اگر Traefik پہلے ہی اس سرور پر موجود دیگر containers کے لیے TLS (transport layer security) termination کر رہا ہے تو Chatwoot ایک label block کے ذریعے اس میں شامل ہو جاتا ہے۔ اگر یہ انتظام ابھی موجود نہیں ہے تو پہلے اسے ایک بار متعدد Docker Compose ایپس کے سامنے Traefik کے مطابق ترتیب دیں، پھر یہاں واپس آئیں۔
Upstream کے docker-compose.yaml کو اصل ساخت کے قریب رکھیں تاکہ بعد میں اس کا نئے copy سے موازنہ کیا جا سکے، اور اپنی تبدیلیاں override file میں رکھیں۔ Compose خودکار طور پر docker-compose.override.yaml کو merge کرتا ہے، جبکہ Compose کو متعدد files میں تقسیم کرنا merge rules کی وضاحت کرتا ہے۔
services:
rails:
networks:
- default
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.chatwoot.rule=Host(`support.example.com`)"
- "traefik.http.routers.chatwoot.entrypoints=websecure"
- "traefik.http.routers.chatwoot.tls.certresolver=letsencrypt"
- "traefik.http.services.chatwoot.loadbalancer.server.port=3000"
networks:
proxy:
external: trueاپنے entrypoint اور certresolver کے نام استعمال کریں۔ Container کو Traefik کے اسی Docker network پر ہونا چاہیے؛ proxy entry یہی کام کرتی ہے۔ اسے default پر بھی برقرار رہنا چاہیے، ورنہ Postgres اور Redis سے اس کا رابطہ ختم ہو جائے گا۔ یہی وہ دوسری line ہے جسے لوگ اکثر بھول جاتے ہیں۔
ports: block میں تبدیلی نہ کریں۔ Upstream اسے 127.0.0.1:3000 سے bind کرتا ہے، جو صرف loopback ہے۔ اس لیے یہ internet سے قابل رسائی نہیں ہوتا اور curl -I http://127.0.0.1:3000 کے ذریعے اسی سرور کے اندر testing کے لیے مفید رہتا ہے۔
Agent dashboard براہ راست پیغامات کی ترسیل کے لیے /cable سے websocket connection کھلا رکھتا ہے۔ Traefik HTTP upgrade کو اضافی configuration کے بغیر forward کرتا ہے، اس لیے کچھ شامل کرنے کی ضرورت نہیں۔ اگر بعد میں Traefik کے سامنے CDN یا کوئی اور proxy رکھیں تو وہاں websockets کی اجازت دیں، کیونکہ اس کی علامت یہ ہے کہ dashboard معمول کے مطابق load ہوتا ہے، لیکن نئے messages صرف manual refresh کے بعد دکھائی دیتے ہیں۔
ڈیٹابیس شروع کریں اور stack چلائیں
پہلے data services شروع کریں اور Postgres کو پہلی بار کا عمل مکمل کرنے دیں۔
docker compose up -d postgres redis
docker compose logs postgres | tail -n 5database system is ready to accept connections کا انتظار کریں۔ پھر schema بنائیں۔
docker compose run --rm rails bundle exec rails db:chatwoot_prepareیہ command ڈیٹابیس موجود نہ ہونے کی صورت میں اسے بناتی ہے، پھر schema اور default seed data لوڈ کرتی ہے۔ یہ migration lines دکھا کر کامیابی سے بند ہو جاتی ہے۔ اگر یہ postgres:5432 - no response دکھاتے ہوئے رک جائے تو entrypoint ایسے ڈیٹابیس کا انتظار کر رہا ہے جو ابھی connections قبول نہیں کر رہا۔ پہلی بار عموماً اس کا مطلب ہوتا ہے کہ initdb ابھی کام کر رہا ہے۔ انتظار کریں، Postgres logs پڑھیں، پھر command دوبارہ چلائیں۔ اگر یہ vector extension پر رک جائے تو آپ نے pgvector image کو stock Postgres سے تبدیل کر دیا ہے۔
docker compose up -d
docker compose ps
docker compose logs --tail 30 railsچاروں containers کی حالت Up ہونی چاہیے، اور rails log کا اختتام Puma کی اس line پر ہونا چاہیے جو http://0.0.0.0:3000 پر listening دکھاتی ہے۔ پھر public path چیک کریں:
curl -sI https://support.example.com | head -n 1HTTP/2 200 کا مطلب ہے کہ پوری chain کام کر رہی ہے۔ Traefik سے 404 کا مطلب ہے کہ router rule match نہیں ہوئی، عموماً hostname میں typo کی وجہ سے۔ 502 کا مطلب ہے کہ Traefik نے router match کر لیا، لیکن container تک نہیں پہنچ سکا۔ اس کی تقریباً ہمیشہ وجہ missing proxy network یا ایسا loadbalancer.server.port ہوتا ہے جو 3000 نہیں ہے۔
URL کھولیں، /app/auth/signup پر اپنا account بنائیں، پھر ENABLE_ACCOUNT_SIGNUP=false set کریں اور form بند کرنے کے لیے docker compose up -d چلائیں۔
SMTP کے بغیر password reset اور email conversations کیوں ناکام ہوتی ہیں
SMTP (simple mail transfer protocol) settings کے بغیر Chatwoot ایسا support desk ہے جو mail نہیں بھیج سکتا، اور اس سے صرف notifications متاثر نہیں ہوتیں۔ Password reset کام کرنا بند کر دیتے ہیں، اس لیے lock out ہونے والا admin دوبارہ access حاصل نہیں کر پاتا۔ Agent invitations بھی کام نہیں کرتیں، کیونکہ invitation ایک email ہوتی ہے۔ Email conversation میں customer کو reply بھیجنا بند ہو جاتا ہے، اس لیے conversation صرف ایک طرفہ رہ جاتی ہے۔ لوگ یہ مرحلہ چھوڑ دیتے ہیں اور پھر مشکل ترین وقت میں اس کا مسئلہ سامنے آتا ہے۔
طریقۂ کار واضح ہے۔ SMTP settings نہ ہونے پر ActionMailer `localhost کو port 25 پر mail deliver کرنے کی default setting برقرار رکھتا ہے۔ Rails container کے اندر کوئی mail server نہیں ہوتا، اس لیے delivery job Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25` اٹھاتی ہے۔ Mail background job سے بھیجی جاتی ہے، اس لیے یہ line Sidekiq log میں آتی ہے، Rails log میں نہیں۔ دوسری طرف، "forgot password" پر click کرنے والے شخص کو کامیابی کا پیغام دکھائی دیتا ہے، لیکن اسے کوئی mail موصول نہیں ہوتی۔
MAILER_SENDER_EMAIL=Support <support@example.com>
SMTP_DOMAIN=example.com
SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=support@example.com
SMTP_PASSWORD=<the relay password>
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=trueSTARTTLS کے ساتھ port 587 استعمال کریں۔ یہ connection کو plain text میں کھولتا ہے اور authentication سے پہلے اسے encrypted connection میں upgrade کر دیتا ہے۔ زیادہ تر VPS providers spam محدود کرنے کے لیے outbound port 25 block کرتے ہیں، اس لیے port 587 پر relay عموماً واحد ایسا راستہ ہوتا ہے جو بالکل connect ہو پاتا ہے۔ `SMTP_DOMAIN` وہ domain ہے جس کا اعلان آپ کا server SMTP conversation کے دوران کرتا ہے، اور بعض relays اس سے مختلف domain کو reject کر دیتے ہیں۔
Settings apply کریں اور worker کو monitor کریں:
docker compose up -d rails sidekiq
docker compose logs -f sidekiqLogin page سے password reset شروع کریں۔ Delivery درست ہونے پر Sidekiq log میں mailer job معمول کے مطابق مکمل ہوتی دکھائی دے گی۔ ناکامی کی صورت میں پہلے exception class دکھائی دیتی ہے، پھر Sidekiq بڑھتے ہوئے backoff کے ساتھ retry کرتا ہے۔ اسی لیے خراب relay کئی گھنٹوں تک ہر چند منٹ بعد وہی error پیدا کرتا رہتا ہے۔
دو قسم کے rejections عام ہیں، اور ان میں سے کوئی بھی Chatwoot bug نہیں ہے۔ `535 Authentication failed کا مطلب ہے کہ اس relay کے لیے username یا password غلط ہے۔ بہت سے providers account password کے بجائے application password چاہتے ہیں۔ 550 Sender address rejected کا مطلب ہے کہ MAILER_SENDER_EMAIL` ایسا address ہے جس سے relay mail بھیجنے کی اجازت نہیں دیتا، اس لیے یہ ایسا mailbox یا domain ہونا چاہیے جسے آپ نے provider کے ساتھ verify کیا ہو۔
Conversation میں email وصول کرنا الگ کام ہے۔ اس کے لیے `MAILER_INBOUND_EMAIL_DOMAIN اور RAILS_INBOUND_EMAIL_SERVICE` کے ساتھ ایسا mail server بھی درکار ہے جو incoming messages کو Chatwoot کے حوالے کرے۔ Relay کرائے پر لینا تیز ترین راستہ ہے۔ اگر آپ پورا mail path خود manage کرنا چاہتے ہیں تو Mailcow کے ساتھ اپنا mail server چلانا اس commitment کی حقیقی ضروریات بیان کرتا ہے۔
کیا بیک اپ لیا جائے، اور restore کے کام کرنے کا ثبوت کیسے حاصل کریں
Chatwoot بیک اپ کے چار حصے ہوتے ہیں۔ ان میں سے کوئی ایک حصہ چھوڑنے سے restore کے بجائے دوبارہ تنصیب کرنا پڑتی ہے۔
- Postgres database، جس میں conversations، contacts، agent accounts اور تمام settings محفوظ ہوتی ہیں۔
storage_datavolume، کیونکہACTIVE_STORAGE_SERVICE=localuploaded files کو disk پر لکھتا ہے اور Postgres میں صرف ایک reference row رکھتا ہے۔.envfile، کیونکہ اس میںSECRET_KEY_BASEاورACTIVE_RECORD_ENCRYPTION_*keys محفوظ ہوتی ہیں۔- compose files، کیونکہ ان میں وہ exact image tag درج ہوتا ہے جس سے آپ کا database schema مطابقت رکھتا ہے۔
صرف database restore کرنے سے تمام conversations واپس آ جائیں گی، لیکن attachments خراب ہوں گی، کیونکہ rows ان files کی طرف اشارہ کرتی ہیں جو اب disk پر موجود نہیں ہیں۔
cd ~/chatwoot
docker compose exec -T postgres pg_dump -U postgres -Fc chatwoot > db-$(date +%F).dump-T اہم ہے۔ اس کے بغیر Compose ایک pseudo terminal مختص کرتا ہے، جو stream میں newline bytes کو تبدیل کر دیتا ہے۔ نتیجتاً ایسی dump file بنتی ہے جسے pg_restore مسترد کر دیتا ہے۔ -Fc custom format ہے۔ یہ compression فراہم کرتا ہے اور pg_restore کو منتخب طور پر کام کرنے دیتا ہے۔
docker run --rm -v chatwoot_storage_data:/data:ro -v "$PWD":/backup alpine \
tar czf /backup/storage-$(date +%F).tgz -C /data .volume کا نام آپ کے project directory name کے ساتھ _storage_data ملا کر بنتا ہے۔ اس command پر اعتماد کرنے سے پہلے docker volume ls | grep storage_data کے ذریعے اس کی تصدیق کریں، کیونکہ Docker ایسے volume کا نام دینے پر failure کے بجائے ایک empty volume بنا دیتا ہے جو موجود نہ ہو۔ آپ کو ایک درست مگر empty archive ملے گا اور کوئی error بھی نہیں آئے گا۔ اس کے بعد ls -lh storage-*.tgz سے اس کا size چیک کریں۔
اب دونوں files اسی disk پر موجود ہیں جس چیز کو وہ محفوظ کرتی ہیں۔ اس سے آپ کسی failure سے محفوظ نہیں ہوتے۔ انہیں server سے باہر منتقل کریں اور encrypt کریں، کیونکہ database dump میں ہر customer message plain text میں موجود ہوتا ہے۔ restic کے ذریعے encrypted off-site backups میں scheduling اور retention کا طریقہ بیان کیا گیا ہے۔
Restore drill: ضرورت پڑنے سے پہلے اسے چلائیں
Restore live server پر نہیں بلکہ دوسرے VPS پر کریں۔ .env، compose files اور دونوں archives وہاں copy کریں، پھر چلائیں:
docker compose up -d postgres
docker compose exec -T postgres pg_restore -U postgres -d chatwoot --clean --if-exists < db-2026-08-10.dump
docker run --rm -v chatwoot_storage_data:/data -v "$PWD":/backup alpine \
sh -c 'rm -rf /data/* && tar xzf /backup/storage-2026-08-10.tgz -C /data'
docker compose up -d--clean --if-exists load کرنے سے پہلے موجودہ objects کو delete کر دیتا ہے۔ اس لیے اسے صرف ایسے database پر چلائیں جسے ضائع کرنے پر آپ رضامند ہوں۔ اس کے بعد sign in کریں اور ایسی conversation کھولیں جس میں attachment موجود ہو۔ اگر message list load ہو جائے اور file download ہو جائے تو بیک اپ درست ہے۔
مختلف SECRET_KEY_BASE کے ساتھ restore کرنے سے ہر session cookie invalid ہو جاتی ہے، اس لیے تمام users sign out ہو جاتے ہیں۔ مختلف ACTIVE_RECORD_ENCRYPTION_* keys کے ساتھ restore کرنا اس سے بھی سنگین ہے: Chatwoot ان columns کو decrypt نہیں کر سکتا جن میں channel credentials محفوظ ہیں، اور ActiveRecord::Encryption::Errors::Decryption ظاہر کرتا ہے۔ اسی لیے .env بیک اپ list میں شامل ہے۔
نئے tag پر Chatwoot کو کیسے upgrade کریں
Commands کی نسبت ترتیب زیادہ اہم ہے۔
- اپنے tag اور target کے درمیان release notes پڑھیں اور مطلوبہ manual steps تلاش کریں۔
- نیا database dump اور storage archive بنائیں، پھر تصدیق کریں کہ دونوں file sizes مناسب ہیں۔
docker-compose.yamlمیںbaseservice کا image tag تبدیل کریں۔- نئی image pull کریں، stack stop کریں، migrations چلائیں، پھر دوبارہ start کریں۔
docker compose pull
docker compose down
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
docker compose up -d
docker compose imagesMigration چلانے سے پہلے image pull کریں، کیونکہ migration نئی image سے چلنی چاہیے۔ پرانی image میں نئی migration files موجود نہیں ہوتیں۔ Migration چلانے سے پہلے stack stop کریں، کیونکہ پرانا code اور نیا schema ایک دوسرے سے مطابقت نہیں رکھتے۔ اس لیے چلتا ہوا پرانا Rails process errors پیدا کر سکتا ہے یا ایسی rows لکھ سکتا ہے جنہیں نیا schema قبول نہ کرے۔ Stack stop کرنے سے migration کے لیے درکار memory بھی دستیاب ہو جاتی ہے۔ Upstream کی جانب سے swap کی درخواست کی یہی بنیادی وجہ ہے۔
docker compose images ہر container میں حقیقتاً چلنے والے tag کو دکھاتا ہے۔ اس سے یہ صورتِ حال سامنے آ جاتی ہے کہ آپ نے tag تو edit کیا، مگر image pull کرنا بھول گئے۔
ایک ساتھ کئی versions کو skip نہ کریں۔ پرانی installation کے لیے Upstream کا مشورہ ہے کہ intermediate tags سے مرحلہ وار upgrade کریں، کیونکہ migrations کو base schema میں شامل ہونے کے بعد ہٹا دیا جاتا ہے۔ اس لیے بہت پرانا database ایسی حالت تک پہنچ سکتا ہے جہاں آگے بڑھنے کا کوئی راستہ نہ ہو۔ ہر بار ایک minor version آگے جائیں اور ہر version کے بعد prepare step چلائیں۔
اگر migration چلنے سے پہلے Rails start ہو جائے تو وہ requests serve کرنے سے انکار کر دیتا ہے اور ActiveRecord::PendingMigrationError: Migrations are pending log کرتا ہے۔ restart: always set ہونے کی صورت میں container بار بار restart ہوتا ہے، اس لیے docker compose ps ایسا uptime دکھاتا ہے جو ہر چند seconds بعد reset ہو جاتا ہے۔ Prepare step چلانے سے یہ مسئلہ ختم ہو جاتا ہے۔
Rollback کے لیے پرانا tag واپس set کریں اور dump restore کریں۔ ایسا کوئی قابلِ اعتماد reverse migration path موجود نہیں جس پر آپ انحصار کر سکیں۔ اسی لیے step 2 ضروری ہے۔
ناکامی کی صورتیں اور نظر آنے والے strings
Traefik سے 502 Bad Gateway۔ Router نے درخواست match کی، لیکن backend نے جواب نہیں دیا۔ چیک کریں کہ docker compose ps میں rails کو Up دکھایا جا رہا ہے، پھر docker network inspect proxy چلائیں اور تصدیق کریں کہ rails container اس کی container list میں موجود ہے۔ جو container network سے attached نہ ہو، وہ Traefik کو نظر نہیں آتا۔ اس لیے درخواست router سے match ہونے کے بعد آگے نہیں پہنچتی۔
Dashboard لوڈ ہو جاتا ہے، لیکن نئے messages دیکھنے کے لیے refresh کرنا پڑتا ہے۔ /cable سے websocket connection قائم نہیں ہو رہا، یا FRONTEND_URL browser bar میں موجود address سے match نہیں کرتا۔ عدم مطابقت کا مطلب ہے کہ page کسی مختلف origin سے websocket کھولنے کی کوشش کر رہا ہے، جسے browser block کر دیتا ہے۔
FATAL: password authentication failed for user "postgres"۔ .env میں موجود password اور Postgres data volume میں محفوظ password مختلف ہیں۔ اسے چلتے ہوئے container کے اندر ALTER USER سے درست کریں، کیونکہ .env میں دوبارہ ترمیم کرنے سے پہلے سے initialised database تبدیل نہیں ہوگا۔
NOAUTH Authentication required. Redis --requirepass کے ساتھ چل رہا ہے، لیکن application نے password کے بغیر connection قائم کیا۔ اس لیے REDIS_PASSWORD، .env سے غائب ہے یا اسے load نہیں کیا گیا۔ اسے براہ راست docker compose exec redis redis-cli -a "$REDIS_PASSWORD" ping سے test کریں۔ اسے PONG کا جواب دینا چاہیے۔
Containers کا code 137 کے ساتھ exit ہونا۔ یہ SIGKILL ہے۔ چھوٹے server پر اس کی وجہ kernel کا out-of-memory killer ہوتا ہے۔ swap شامل کریں، ہر service کے لیے memory limits مقرر کریں، یا بڑے plan پر منتقل ہوں۔
FAQ
self-hosted Chatwoot VPS کے لیے کتنی RAM درکار ہے؟
August 2026 تک upstream کی کم از کم ضرورت 4 GB RAM اور 4 CPU cores ہے، جس پر روزانہ 10,000 conversations تک کا بوجھ متوقع ہے۔ 20,000 تک conversations کے لیے 8 GB RAM اور 8 cores درکار ہیں۔ کم از کم 1 GB swap بھی شامل کریں، کیونکہ upgrade کے دوران migrations لاگو کرنے کے لیے دوسرا Rails process چلتا ہے۔ کم وسائل والے VPS میں عموماً اسی مرحلے پر memory ختم ہو جاتی ہے۔ 2 GB VPS چند agents کے لیے boot ہو کر کام کر لیتا ہے، لیکن load کے دوران صرف Sidekiq ہی 1 GB سے زیادہ memory استعمال کر سکتا ہے۔ اس لیے مصروف اوقات اور upgrades کے دوران containers کے exit code 137 کے ساتھ بند ہونے کی توقع رکھیں۔
Chatwoot کی password reset emails کبھی موصول کیوں نہیں ہوتیں؟
کیونکہ SMTP settings configured نہیں ہیں۔ اس صورت میں ActionMailer port 25 پر localhost کو email بھیجنے کی کوشش کرتا ہے، لیکن container کے اندر کوئی mail server موجود نہیں ہوتا۔ Browser پھر بھی کامیابی کا پیغام دکھاتا ہے، جبکہ job Sidekiq میں Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25 کے ساتھ ناکام ہو جاتی ہے۔ SMTP_ADDRESS، SMTP_PORT، SMTP_USERNAME، SMTP_PASSWORD اور MAILER_SENDER_EMAIL کو .env میں set کریں، rails اور sidekiq services restart کریں، پھر reset trigger کرتے وقت docker compose logs -f sidekiq کو monitor کریں۔
Chatwoot بحال کرنے کے لیے کن چیزوں کا backup لینا ضروری ہے؟
Postgres database، storage_data Docker volume، .env file اور compose files کا backup لیں۔ صرف database کافی نہیں ہے، کیونکہ uploaded files volume میں محفوظ ہوتی ہیں اور Postgres میں ان کے صرف references موجود ہوتے ہیں۔ اس لیے صرف database بحال کرنے سے ایسی conversations ملتی ہیں جن کے attachments خراب ہوتے ہیں۔ .env اہم ہے، کیونکہ مختلف SECRET_KEY_BASE تمام users کو دوبارہ sign out کر دیتا ہے۔ مختلف ACTIVE_RECORD_ENCRYPTION_* keys encrypted columns کو ناقابل مطالعہ بنا دیتی ہیں۔
Database کو خراب کیے بغیر Chatwoot کو upgrade کیسے کروں؟
Backup لیں، اپنی compose file میں image tag تبدیل کریں، پھر docker compose pull، docker compose down، docker compose run --rm rails bundle exec rails db:chatwoot_prepare اور docker compose up -d چلائیں۔ پہلے image pull کریں، کیونکہ migrations نئی image سے چلنی چاہییں۔ Stack پہلے stop کریں، کیونکہ نئی schema کے ساتھ پرانا code چلانے سے errors پیدا ہوتے ہیں۔ پرانی installation میں ایک وقت میں صرف ایک minor version آگے بڑھیں، کیونکہ migrations کو base schema میں شامل کیے جانے کے بعد ہٹا دیا جاتا ہے۔
کیا pgvector کے بجائے standard postgres image استعمال کی جا سکتی ہے؟
نہیں۔ Chatwoot کی schema vector extension enable کرتی ہے۔ اس لیے stock postgres image db:chatwoot_prepare کے دوران ERROR: extension "vector" is not available کے ساتھ ناکام ہو جاتی ہے، کیونکہ اس image میں extension کی control file موجود نہیں ہوتی۔ upstream compose file میں pgvector/pgvector:pg16 برقرار رکھیں، یا ایسی دوسری image استعمال کریں جو آپ کے Postgres major version کے لیے pgvector فراہم کرتی ہو۔