SSD Nodes Learn 🎉 VPS mulai $5.50/bln
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-13

Cara Self-Host Chatwoot di VPS dengan Docker

Pelajari cara menjalankan Chatwoot di VPS dengan Docker Compose dan Traefik, termasuk tag versi tetap, SMTP, backup PostgreSQL dan upload, serta upgrade aman.

Yang Anda bangun

Untuk melakukan self-hosting Chatwoot pada VPS, Anda menjalankan empat container: proses web Rails, worker latar belakang Sidekiq, PostgreSQL dengan ekstensi pgvector, dan Redis. Chatwoot adalah help desk dukungan pelanggan open source. Dengan demikian, Anda mendapatkan inbox tim bersama dan widget chat situs web pada server yang Anda kendalikan. Instalasi memerlukan waktu sekitar dua puluh menit. Setelah itu, pengiriman email, pencadangan, upgrade, dan penentuan ukuran resource menentukan apakah sistem ini masih berjalan satu tahun kemudian.

Setiap container memiliki satu tugas. Rails menyajikan dashboard agen dan API (application programming interface) widget. Sidekiq menjalankan pekerjaan yang memerlukan waktu lama: mengirim email, melakukan polling pada channel yang terhubung, menjalankan aturan otomatisasi, dan membuat laporan. Postgres menyimpan percakapan, kontak, akun agen, dan setiap pengaturan yang Anda ubah di dashboard. Redis menyimpan antrean Sidekiq dan channel pub/sub ActionCable yang mendorong pesan baru ke dashboard yang sedang terbuka tanpa memuat ulang halaman. Redis bukan cache sementara dalam konfigurasi ini, karena kehilangannya berarti kehilangan job yang masih berada dalam antrean.

Image Postgres pada file compose upstream adalah pgvector/pgvector:pg16, bukan image postgres standar, karena skema Chatwoot mengaktifkan ekstensi vector untuk fitur AI-nya. Jika Anda menggantinya dengan Postgres standar, proses database pertama berhenti dengan ERROR: extension "vector" is not available karena file kontrol ekstensi tersebut tidak ada dalam image itu. Gunakan image yang dirilis upstream.

Panduan ini mengasumsikan Docker dan reverse proxy sudah berfungsi pada server. Jika belum, mulai dari Docker Compose pada VPS, lalu kembali ke sini.

Berapa kapasitas VPS yang dibutuhkan Chatwoot yang di-hosting sendiri?

Per Agustus 2026, halaman persyaratan upstream meminta RAM 4 GB dan 4 core CPU sebagai minimum, dan menyatakan kapasitas tersebut dapat menangani hingga 10.000 percakapan per hari. Untuk 8 GB RAM dan 8 core, kapasitasnya hingga 20.000 percakapan per hari. Halaman tersebut juga meminta swap minimal 1 GB, dengan alasan yang dijelaskan secara langsung: agar mesin tidak kehabisan memori selama upgrade. Siapkan ruang disk 5 GB hingga 10 GB untuk Postgres, di luar ruang yang diperlukan untuk upload file.

Sekarang bagian yang perlu diperhatikan. VPS 2 GB dapat menjalankan Chatwoot, dan tampak baik jika hanya digunakan oleh dua agen dengan inbox yang sepi. Namun, VPS tersebut bermasalah dalam dua kondisi. Pertama adalah Sidekiq, yang menurut upstream menggunakan lebih dari 1 GB pada server yang sibuk. Lonjakan email atau proses pembuatan laporan dapat membuat mesin kehabisan memori sebelum Rails, Postgres, dan Redis menggunakan alokasinya masing-masing. Kedua adalah proses upgrade, karena db:chatwoot_prepare menjalankan proses Rails baru untuk menerapkan migrasi. Proses boot Rails pada image ini menggunakan ratusan megabyte sebelum melakukan pekerjaan yang berguna.

Anda tidak akan menerima peringatan yang jelas terlebih dahulu. OOM killer milik kernel mengirimkan SIGKILL ke proses terbesar. Docker melihat container tersebut berhenti, lalu restart: always menjalankannya kembali. docker compose ps kemudian menampilkan container yang terus kembali ke Exited (137). Kode 137 berarti proses dihentikan oleh signal 9. Konfirmasikan hal ini dengan sudo dmesg -T | grep -i "killed process", yang menampilkan nama proses yang dipilih kernel.

Jika anggaran tidak mencukupi untuk 4 GB, jalankan mesin 2 GB dengan swap 2 GB dan terima bahwa waktu respons akan memburuk saat beban meningkat, alih-alih service berhenti sepenuhnya. Menetapkan batas memori yang tegas untuk setiap service tetap layak dilakukan. Dengan begitu, worker tidak dapat membuat database ikut berhenti. Lihat batas memori di Docker Compose.

Upload file adalah bagian yang terus bertambah tanpa batas yang Anda tetapkan. Setiap screenshot yang dilampirkan pelanggan disimpan di volume penyimpanan dan tetap berada di sana. Karena itu, pantau docker system df -v, bukan berasumsi bahwa database yang memenuhi disk.

Dapatkan file compose dan tetapkan tag versi

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

File yang baru saja Anda unduh berisi image: chatwoot/chatwoot:latest. Ubah bagian tersebut sebelum melakukan hal lain.

services:
  base: &base
    image: chatwoot/chatwoot:v4.16.2
    env_file: .env
    volumes:
      - storage_data:/app/storage

latest berarti docker compose pull berikutnya akan mengambil apa pun yang dipublikasikan pada pagi itu. Versi tersebut dapat berupa versi utama yang menyertakan migrasi yang belum pernah Anda baca. Dalam praktiknya, migrasi Chatwoot tidak dapat dibatalkan. Lompatan versi yang tidak disengaja mengharuskan pemulihan dari backup, bukan pembatalan perubahan. Tetapkan tag dan ubah secara sengaja. v4.16.2 adalah rilis saat ini pada Agustus 2026. Periksa halaman rilis untuk mengetahui tag yang harus Anda tetapkan hari ini.

Service base adalah anchor YAML yang digabungkan oleh rails dan sidekiq. Jadi, perubahan tag di satu tempat akan menerapkannya pada keduanya. Saat membuka file tersebut, hapus baris version: '3' di bagian paling atas. Compose modern mengabaikannya dan menampilkan the attribute 'version' is obsolete, it will be ignored pada setiap perintah.

Isi file .env

Buat secret terlebih dahulu. Upstream meminta nilai alfanumerik karena karakter khusus dapat berubah saat nilai melewati shell atau parser YAML.

head /dev/urandom | tr -dc A-Za-z0-9 | head -c 63 ; echo ''

Kemudian tetapkan key berikut di .env.

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=local

POSTGRES_HOST=postgres dan redis://redis:6379 adalah nama service Compose yang di-resolve pada jaringan default proyek. FRONTEND_URL bukan sekadar dekorasi. Chatwoot membentuk URL skrip widget dan setiap link dalam email keluar berdasarkan nilai ini. Jadi, nilai yang salah menghasilkan link reset password yang mengarah ke host yang tidak merespons.

Sekarang perhatikan jebakan dalam file upstream. Service postgres tidak membaca .env. Service tersebut memiliki blok environment sendiri dengan POSTGRES_PASSWORD= yang masih kosong. Jadi, menetapkan password hanya di .env membuat database tidak memiliki password, sementara aplikasi memilikinya. Arahkan service tersebut ke variable yang sama:

  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 membaca .env dari direktori proyek untuk substitusi ${...}. Dengan demikian, kedua sisi sekarang mendapatkan string yang sama. Jika nilainya salah, Rails berhenti dengan PG::ConnectionBad: FATAL: password authentication failed for user "postgres".

Satu perilaku hampir selalu mengejutkan pengguna: image Postgres hanya menerapkan POSTGRES_PASSWORD saat menginisialisasi direktori data yang kosong. Mengubah nilainya setelah itu tidak berpengaruh karena initdb tidak dijalankan untuk kedua kalinya. Jika stack sudah pernah dijalankan, ubah password tersebut langsung di dalam database.

docker compose exec postgres psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'the-new-password';"

ENABLE_ACCOUNT_SIGNUP=true bersifat sementara. Opsi ini membuka formulir pendaftaran publik agar Anda dapat membuat akun pertama. Ubah nilainya menjadi false dan jalankan kembali docker compose up -d segera setelah akun Anda tersedia. Jika tidak, siapa pun yang menemukan URL tersebut dapat mendaftar pada meja bantuan Anda. Setelah itu, agent masuk melalui undangan dan password mereka hanya tersimpan di aplikasi ini. Cara ini masih sesuai jika Anda hanya menjalankan beberapa service. Namun, ketika Anda menjalankan sekitar setengah lusin service dan lelah mengelola daftar akun terpisah di masing-masing service, identity provider self-hosted seperti Authentik dapat menggantikannya.

.env sekarang menyimpan semua secret stack ini dalam teks biasa. Tetapkan permission file ke mode 600 dan jangan masukkan file tersebut ke git. Cara Compose membaca file env dan lokasi secret dapat bocor membahas bagian yang perlu diperhatikan, termasuk perbedaan antara env_file dan environment.

Letakkan Chatwoot di belakang Traefik yang sudah ada

Jangan membuat reverse proxy kedua untuk satu aplikasi. Jika Traefik sudah menangani TLS (transport layer security) untuk container lain di server ini, Chatwoot dapat menggunakannya melalui blok label. Jika Anda belum menyiapkannya, lakukan satu kali melalui Traefik di depan beberapa aplikasi Docker Compose, lalu kembali ke sini.

Pertahankan docker-compose.yaml upstream sedekat mungkin dengan konfigurasi bawaan agar Anda dapat membandingkannya dengan salinan yang lebih baru nanti, lalu letakkan perubahan Anda dalam file override. Compose otomatis menggabungkan docker-compose.override.yaml, dan memisahkan Compose ke beberapa file menjelaskan aturan penggabungannya.

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

Gunakan nama entrypoint dan certresolver Anda sendiri. Container harus berada pada jaringan Docker yang sama dengan Traefik. Itulah fungsi entri proxy. Container juga harus tetap berada pada default. Jika tidak, koneksi ke Postgres dan Redis akan terputus. Baris kedua ini sering terlupakan.

Biarkan blok ports: apa adanya. Upstream mengikatnya ke 127.0.0.1:3000, yang hanya merupakan loopback. Karena itu, blok tersebut tidak dapat diakses dari Internet dan tetap berguna untuk pengujian dari dalam server menggunakan curl -I http://127.0.0.1:3000.

Dasbor agen mempertahankan koneksi websocket terbuka ke /cable untuk mengirimkan pesan secara langsung. Traefik meneruskan HTTP upgrade tanpa konfigurasi tambahan, jadi tidak ada yang perlu ditambahkan. Jika nanti Anda menempatkan CDN atau proxy lain di depan Traefik, izinkan websocket di sana. Gejalanya adalah dasbor dimuat secara normal, tetapi pesan baru hanya muncul setelah halaman dimuat ulang secara manual.

Inisialisasi database dan jalankan stack

Jalankan layanan data terlebih dahulu, lalu tunggu hingga Postgres menyelesaikan proses pertama kali.

docker compose up -d postgres redis
docker compose logs postgres | tail -n 5

Tunggu hingga database system is ready to accept connections. Setelah itu, buat skema.

docker compose run --rm rails bundle exec rails db:chatwoot_prepare

Perintah ini membuat database jika belum tersedia, lalu memuat skema dan data seed default. Perintah ini menampilkan baris migrasi dan selesai tanpa error. Jika proses terus menampilkan postgres:5432 - no response, entrypoint sedang menunggu database yang belum menerima koneksi. Pada proses pertama, biasanya initdb masih berjalan. Tunggu, baca log Postgres, lalu jalankan kembali perintah tersebut. Jika proses berhenti pada ekstensi vector, berarti Anda mengganti image pgvector dengan Postgres standar.

docker compose up -d
docker compose ps
docker compose logs --tail 30 rails

Keempat container harus menampilkan Up, dan log Rails harus diakhiri baris Puma yang listening pada http://0.0.0.0:3000. Selanjutnya, periksa path publik:

curl -sI https://support.example.com | head -n 1

HTTP/2 200 berarti seluruh rantai berfungsi. Respons 404 dari Traefik berarti aturan router tidak cocok, biasanya karena hostname salah ketik. Respons 502 berarti Traefik menemukan router, tetapi tidak dapat menjangkau container. Penyebabnya hampir selalu network proxy yang tidak ada atau loadbalancer.server.port yang nilainya bukan 3000.

Buka URL tersebut, buat akun Anda di /app/auth/signup, lalu tetapkan ENABLE_ACCOUNT_SIGNUP=false dan jalankan docker compose up -d untuk menutup formulir.

Mengapa reset kata sandi dan percakapan email gagal tanpa SMTP

Chatwoot tanpa pengaturan SMTP (simple mail transfer protocol) adalah help desk yang tidak dapat mengirim email, dan dampaknya lebih luas daripada sekadar notifikasi. Reset kata sandi berhenti berfungsi, sehingga admin yang terkunci tetap tidak dapat masuk. Undangan agent berhenti berfungsi karena undangan dikirim melalui email. Membalas pelanggan dalam percakapan email juga berhenti berfungsi, sehingga percakapan hanya berjalan satu arah. Langkah ini sering dilewati, lalu masalahnya baru diketahui pada saat yang paling buruk.

Mekanismenya sederhana. Tanpa pengaturan SMTP, ActionMailer tetap menggunakan nilai default untuk mengirimkan email ke localhost pada port 25. Tidak ada mail server di dalam container Rails, sehingga tugas pengiriman memunculkan Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25. Email dikirim melalui background job, sehingga baris tersebut muncul di log Sidekiq, bukan di log Rails. Sementara itu, orang yang mengeklik "lupa kata sandi" melihat konfirmasi, tetapi tidak menerima email apa pun.

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=true

Gunakan port 587 dengan STARTTLS. Protokol ini membuka koneksi dalam teks biasa, lalu meningkatkannya menjadi koneksi terenkripsi sebelum autentikasi. Sebagian besar penyedia VPS memblokir port outbound 25 untuk membatasi spam, sehingga relay pada port 587 biasanya menjadi satu-satunya opsi yang dapat terhubung. SMTP_DOMAIN adalah domain yang diumumkan server Anda selama percakapan SMTP, dan beberapa relay menolak ketidaksesuaian domain tersebut.

Terapkan pengaturan, lalu pantau worker:

docker compose up -d rails sidekiq
docker compose logs -f sidekiq

Mulai reset kata sandi dari halaman login. Pengiriman yang berhasil menunjukkan tugas mailer selesai secara normal di log Sidekiq. Kegagalan menampilkan kelas exception, lalu Sidekiq mencoba kembali dengan jeda yang terus meningkat. Karena itu, relay yang rusak menghasilkan error yang sama setiap beberapa menit selama berjam-jam.

Dua penolakan berikut sering terjadi, dan keduanya bukan bug Chatwoot. 535 Authentication failed berarti username atau password untuk relay tersebut salah. Banyak penyedia mengharuskan penggunaan application password, bukan password akun. 550 Sender address rejected berarti MAILER_SENDER_EMAIL adalah alamat yang tidak diizinkan oleh relay untuk digunakan sebagai pengirim, sehingga alamat tersebut harus berupa mailbox atau domain yang telah Anda verifikasi kepada penyedia.

Menerima email ke dalam percakapan adalah tugas yang terpisah. Proses ini memerlukan MAILER_INBOUND_EMAIL_DOMAIN dan RAILS_INBOUND_EMAIL_SERVICE, serta mail server yang meneruskan pesan masuk ke Chatwoot. Menyewa relay adalah cara tercepat. Jika Anda ingin mengelola seluruh jalur email sendiri, menjalankan mail server sendiri dengan Mailcow menjelaskan komitmen yang sebenarnya diperlukan.

Hal yang perlu dicadangkan dan cara membuktikan bahwa pemulihan berhasil

Backup Chatwoot memiliki empat bagian. Jika salah satunya dilewati, pemulihan berubah menjadi pembangunan ulang.

  • Database Postgres, yang menyimpan percakapan, kontak, akun agen, dan semua pengaturan.
  • Volume storage_data, karena ACTIVE_STORAGE_SERVICE=local menulis file yang diunggah ke disk dan hanya menyimpan baris referensinya di Postgres.
  • File .env, karena file ini menyimpan SECRET_KEY_BASE dan key ACTIVE_RECORD_ENCRYPTION_*.
  • File compose, karena file tersebut mencatat tag image yang tepat dan sesuai dengan skema database Anda.

Jika database dipulihkan tanpa bagian lain, semua percakapan memang kembali, tetapi lampirannya rusak karena baris database merujuk ke file yang sudah tidak ada di disk.

cd ~/chatwoot
docker compose exec -T postgres pg_dump -U postgres -Fc chatwoot > db-$(date +%F).dump

-T penting. Tanpanya, Compose mengalokasikan pseudo-terminal yang mengubah byte newline dalam stream. Akibatnya, Anda mendapatkan file dump yang ditolak oleh pg_restore. -Fc adalah format kustom yang melakukan kompresi dan memungkinkan pg_restore bekerja secara selektif.

docker run --rm -v chatwoot_storage_data:/data:ro -v "$PWD":/backup alpine \
  tar czf /backup/storage-$(date +%F).tgz -C /data .

Nama volume terdiri atas nama direktori proyek Anda ditambah _storage_data. Konfirmasikan nama tersebut dengan docker volume ls | grep storage_data sebelum mempercayai perintah itu, karena Docker membuat volume kosong, bukan gagal, jika Anda menentukan nama volume yang tidak ada. Hasilnya adalah arsip kosong yang valid tanpa error sama sekali. Periksa ukurannya setelah itu dengan ls -lh storage-*.tgz.

Kedua file tersebut sekarang berada di disk yang sama dengan data yang dilindunginya. Kondisi ini tidak melindungi Anda dari apa pun. Salin file tersebut ke luar server dan enkripsi, karena dump database berisi semua pesan pelanggan dalam teks biasa. Backup terenkripsi di luar server dengan restic membahas penjadwalan dan retensi.

Lakukan uji pemulihan sebelum Anda membutuhkannya

Pulihkan ke VPS kedua, bukan ke VPS produksi. Salin .env, file compose, dan kedua arsip ke sana, lalu jalankan:

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 menghapus objek yang ada sebelum memuat data. Karena itu, arahkan perintah tersebut hanya ke database yang datanya boleh dihapus. Setelah itu, masuk dan buka percakapan yang memiliki lampiran. Jika daftar pesan dapat dimuat dan file dapat diunduh, backup tersebut benar-benar dapat dipulihkan.

Pemulihan dengan SECRET_KEY_BASE yang berbeda akan membatalkan semua cookie sesi sehingga semua pengguna keluar. Pemulihan dengan key ACTIVE_RECORD_ENCRYPTION_* yang berbeda lebih buruk: Chatwoot tidak dapat mendekripsi kolom yang menyimpan kredensial channel dan menampilkan ActiveRecord::Encryption::Errors::Decryption. Karena itu, .env harus termasuk dalam daftar backup.

Cara meningkatkan Chatwoot ke tag baru

Urutannya lebih penting daripada perintahnya.

  1. Baca catatan rilis antara tag Anda dan tag target. Cari langkah manual yang diwajibkan.
  2. Buat dump database dan arsip storage terbaru. Pastikan ukuran kedua file terlihat wajar.
  3. Edit tag image pada service base di docker-compose.yaml.
  4. Pull image baru, hentikan stack, jalankan migration, lalu jalankan stack kembali.
docker compose pull
docker compose down
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
docker compose up -d
docker compose images

Lakukan pull sebelum migration, karena migration harus dijalankan dari image baru. Image lama tidak berisi file migration baru. Hentikan stack sebelum migration, karena kode lama dan schema baru tidak kompatibel. Proses Rails lama yang masih berjalan dapat menghasilkan error atau menulis row yang tidak dapat diterima oleh schema baru. Penghentian stack juga membebaskan memory yang diperlukan migration. Inilah alasan upstream meminta swap.

docker compose images menampilkan tag yang benar-benar sedang dijalankan oleh setiap container. Ini membantu menemukan kasus ketika Anda telah mengedit tag tetapi lupa melakukan pull.

Jangan melewati banyak versi sekaligus. Untuk instalasi lama, upstream menyarankan agar Anda melewati tag perantara. Migration dapat dihapus setelah digabungkan ke base schema. Akibatnya, database yang sangat lama dapat mencapai kondisi tanpa jalur upgrade. Naikkan satu versi minor setiap kali, lalu jalankan langkah prepare setelah setiap upgrade.

Jika Rails start sebelum migration dijalankan, Rails menolak melayani request dan mencatat ActiveRecord::PendingMigrationError: Migrations are pending. Jika restart: always diatur, container akan terus restart. Karena itu, docker compose ps menampilkan uptime yang reset setiap beberapa detik. Jalankan langkah prepare untuk mengatasinya.

Rollback berarti mengembalikan tag lama dan memulihkan dump. Tidak ada jalur reverse migration yang dapat diandalkan. Itulah kegunaan langkah 2.

Mode kegagalan dan string yang akan Anda lihat

502 Bad Gateway dari Traefik. Router berhasil mencocokkan permintaan, tetapi backend tidak merespons. Periksa docker compose ps untuk memastikan rails ditampilkan sebagai Up, lalu jalankan docker network inspect proxy dan pastikan container rails muncul dalam daftar containernya. Container yang tidak terhubung tidak terlihat oleh Traefik. Akibatnya, permintaan mencocokkan router, tetapi tidak diteruskan ke mana pun.

Dashboard dimuat, tetapi pesan baru memerlukan refresh. Websocket ke /cable tidak berhasil diteruskan, atau FRONTEND_URL tidak cocok dengan alamat pada bilah browser. Ketidakcocokan ini berarti halaman mencoba membuka websocket ke origin yang berbeda, sehingga diblokir oleh browser.

FATAL: password authentication failed for user "postgres". Password dalam .env berbeda dengan password yang tersimpan di volume data Postgres. Perbaiki dengan ALTER USER di dalam container yang sedang berjalan, karena mengedit .env lagi tidak akan mengubah database yang sudah diinisialisasi.

NOAUTH Authentication required. Redis berjalan dengan --requirepass, tetapi aplikasi terhubung tanpa password. Ini berarti REDIS_PASSWORD tidak ada dalam .env atau tidak diterapkan. Uji secara langsung dengan docker compose exec redis redis-cli -a "$REDIS_PASSWORD" ping. Perintah tersebut seharusnya memberikan respons PONG.

Container keluar dengan kode 137. Kode tersebut berarti SIGKILL. Pada mesin dengan sumber daya terbatas, penyebabnya adalah out-of-memory killer milik kernel. Tambahkan swap, tetapkan batas memori untuk setiap service, atau pindah ke paket yang lebih besar.

FAQ

Berapa RAM yang diperlukan VPS Chatwoot yang di-host sendiri?

Per Agustus 2026, upstream menetapkan 4 GB RAM dan 4 core CPU sebagai minimum, dengan kapasitas hingga 10,000 percakapan per hari, serta 8 GB dan 8 core untuk hingga 20,000 percakapan. Tambahkan swap minimal 1 GB, karena proses upgrade menjalankan proses Rails kedua untuk menerapkan migrasi dan pada tahap inilah VPS dengan spesifikasi kecil kehabisan memori. VPS 2 GB dapat melakukan boot dan berfungsi untuk beberapa agen, tetapi Sidekiq saja dapat menggunakan lebih dari 1 GB saat beban tinggi. Karena itu, perkirakan container dihentikan dengan exit code 137 selama periode sibuk dan saat upgrade.

Mengapa email reset password Chatwoot tidak pernah sampai?

Karena tidak ada pengaturan SMTP yang dikonfigurasi, sehingga ActionMailer mencoba mengirim email ke localhost pada port 25, tetapi tidak ada mail server di dalam container. Job gagal di Sidekiq dengan Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25, sementara browser tetap menampilkan pesan sukses. Tetapkan SMTP_ADDRESS, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, dan MAILER_SENDER_EMAIL di .env, restart service rails dan sidekiq, lalu monitor docker compose logs -f sidekiq saat Anda memicu reset.

Apa saja yang perlu dicadangkan untuk memulihkan Chatwoot?

Database Postgres, volume Docker storage_data, file .env, dan file compose. Database saja tidak cukup, karena file yang diunggah berada di volume, sedangkan Postgres hanya menyimpan referensi ke file tersebut. Akibatnya, pemulihan yang hanya menggunakan database menghasilkan percakapan dengan lampiran yang rusak. .env penting karena SECRET_KEY_BASE yang berbeda akan mengeluarkan semua pengguna dari sesi mereka, sedangkan ACTIVE_RECORD_ENCRYPTION_* yang berbeda membuat kolom terenkripsi tidak dapat dibaca.

Bagaimana cara meng-upgrade Chatwoot tanpa merusak database?

Buat cadangan, ubah tag image di file compose, lalu jalankan docker compose pull, docker compose down, docker compose run --rm rails bundle exec rails db:chatwoot_prepare, dan docker compose up -d. Lakukan pull terlebih dahulu karena migrasi harus dijalankan dari image baru. Hentikan stack terlebih dahulu karena kode lama yang mengakses schema baru dapat menimbulkan error. Pada instalasi lama, naikkan satu versi minor setiap kali, karena migrasi akan dihapus setelah digabungkan ke dalam schema dasar.

Dapatkah saya menggunakan image postgres standar sebagai pengganti pgvector?

Tidak. Schema Chatwoot mengaktifkan extension vector, sehingga image postgres standar gagal saat db:chatwoot_prepare dengan ERROR: extension "vector" is not available, karena file kontrol extension tersebut tidak tersedia di dalam image itu. Pertahankan pgvector/pgvector:pg16 dari file compose upstream, atau gunakan image lain yang menyertakan pgvector untuk major version Postgres Anda.

#chatwoot#self-hosting#docker-compose#support-desk#smtp#backups