Skip to main content

Overview

This guide covers common issues you may encounter with self-hosted Chatwoot and their solutions.

Health Check and Diagnostics

Quick Health Check

#!/bin/bash
# Quick diagnostic script

echo "=== Chatwoot Health Check ==="
echo ""

# 1. Web server
echo "[1/6] Checking web server..."
if curl -sf http://localhost:3000/health > /dev/null; then
  echo "✓ Web server is running"
else
  echo "✗ Web server is not responding"
fi

# 2. Database
echo "[2/6] Checking database connection..."
if psql -U postgres -d chatwoot_production -c "SELECT 1" > /dev/null 2>&1; then
  echo "✓ Database is accessible"
else
  echo "✗ Database connection failed"
fi

# 3. Redis
echo "[3/6] Checking Redis..."
if redis-cli PING > /dev/null 2>&1; then
  echo "✓ Redis is running"
else
  echo "✗ Redis is not responding"
fi

# 4. Sidekiq
echo "[4/6] Checking Sidekiq..."
if ps aux | grep -v grep | grep -q sidekiq; then
  echo "✓ Sidekiq process is running"
else
  echo "✗ Sidekiq is not running"
fi

# 5. Disk space
echo "[5/6] Checking disk space..."
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -lt 90 ]; then
  echo "✓ Disk usage: ${DISK_USAGE}%"
else
  echo "⚠ Disk usage critical: ${DISK_USAGE}%"
fi

# 6. Ports
echo "[6/6] Checking ports..."
if netstat -tuln | grep -q ":3000"; then
  echo "✓ Port 3000 is listening"
else
  echo "✗ Port 3000 is not listening"
fi

echo ""
echo "=== Diagnostic Complete ==="

Application Issues

Service Won’t Start

Symptom

Rails server or Sidekiq fails to start

Diagnosis

# Check service status
systemctl status chatwoot-web
systemctl status chatwoot-worker

# View recent logs
journalctl -u chatwoot-web -n 100
journalctl -u chatwoot-worker -n 100

# Check application logs
tail -100 /home/chatwoot/chatwoot/log/production.log

# For Docker
docker-compose logs rails
docker-compose logs sidekiq

Common Causes & Solutions

Missing environment variables:
# Verify required variables
env | grep -E "POSTGRES|REDIS|SECRET_KEY_BASE"

# Generate missing SECRET_KEY_BASE
bundle exec rails secret
# Add to .env file
echo "SECRET_KEY_BASE=$(bundle exec rails secret)" >> .env
Database connection failure:
# Test database connection
psql -h localhost -U postgres -d chatwoot_production -c "SELECT 1"

# Check database exists
psql -h localhost -U postgres -c "\l" | grep chatwoot

# Create if missing
RAILS_ENV=production bundle exec rails db:create
RAILS_ENV=production bundle exec rails db:migrate
Redis connection failure:
# Test Redis connection
redis-cli -u "$REDIS_URL" PING

# Check Redis is running
systemctl status redis
# or
ps aux | grep redis

# Start if not running
systemctl start redis
Port already in use:
# Check what's using port 3000
lsof -i :3000
netstat -tuln | grep 3000

# Kill conflicting process
kill -9 <PID>

# Or use different port
export PORT=3001
bundle exec rails s -p 3001

500 Internal Server Error

Diagnosis

# Check production logs for stack trace
tail -f log/production.log

# Enable debug logging temporarily
export RAILS_LOG_LEVEL=debug
systemctl restart chatwoot-web

# Check for specific errors
grep -A 10 "ERROR" log/production.log | tail -50

Common Causes

Database migration pending:
# Check migration status
RAILS_ENV=production bundle exec rails db:migrate:status

# Run pending migrations
RAILS_ENV=production bundle exec rails db:migrate

# Restart services
systemctl restart chatwoot-web chatwoot-worker
Asset compilation failed:
# Recompile assets
RAILS_ENV=production bundle exec rails assets:clobber
RAILS_ENV=production bundle exec rails assets:precompile

# Check for errors
ls -lh public/packs/manifest.json
Permission issues:
# Fix ownership
sudo chown -R chatwoot:chatwoot /home/chatwoot/chatwoot

# Fix log permissions
sudo chmod -R 755 /home/chatwoot/chatwoot/log
sudo chmod -R 755 /home/chatwoot/chatwoot/tmp

Authentication Failures

User can’t login

# Check user exists
RAILS_ENV=production bundle exec rails runner "puts User.find_by(email: '[email protected]').inspect"

# Reset password
RAILS_ENV=production bundle exec rails runner "
  user = User.find_by(email: '[email protected]')
  user.update(password: 'newpassword123')
  puts 'Password reset successful'
"

# Confirm user account
RAILS_ENV=production bundle exec rails runner "
  user = User.find_by(email: '[email protected]')
  user.confirm
  puts 'User confirmed'
"

API authentication issues

# Verify API token
curl -H "api_access_token: YOUR_TOKEN" http://localhost:3000/api/v1/profile

# Generate new token
RAILS_ENV=production bundle exec rails runner "
  user = User.find_by(email: '[email protected]')
  puts user.access_token.token
"

Database Issues

Connection Pool Exhausted

Symptom

ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds

Solution

# Check current connections
psql -U postgres -d chatwoot_production -c "
  SELECT count(*), state
  FROM pg_stat_activity
  WHERE datname = 'chatwoot_production'
  GROUP BY state;
"

# Increase pool size
export RAILS_MAX_THREADS=10
export SIDEKIQ_CONCURRENCY=20

# Update database.yml or environment
systemctl restart chatwoot-web chatwoot-worker

# Kill idle connections
psql -U postgres -d chatwoot_production -c "
  SELECT pg_terminate_backend(pid)
  FROM pg_stat_activity
  WHERE datname = 'chatwoot_production'
    AND state = 'idle'
    AND state_change < current_timestamp - INTERVAL '10 minutes';
"

Slow Database Queries

Diagnosis

-- Find slow queries
SELECT
  pid,
  now() - query_start AS duration,
  state,
  query
FROM pg_stat_activity
WHERE state = 'active'
  AND now() - query_start > interval '5 seconds'
ORDER BY duration DESC;

-- Check for locks
SELECT
  pg_stat_activity.pid,
  pg_stat_activity.query,
  pg_locks.granted
FROM pg_stat_activity
JOIN pg_locks ON pg_stat_activity.pid = pg_locks.pid
WHERE NOT pg_locks.granted;

Solutions

# Analyze database
RAILS_ENV=production bundle exec rails runner "ActiveRecord::Base.connection.execute('ANALYZE')"

# Vacuum full (requires downtime)
psql -U postgres -d chatwoot_production -c "VACUUM FULL ANALYZE;"

# Check for missing indexes
RAILS_ENV=production bundle exec rails runner "
  ActiveRecord::Base.connection.tables.each do |table|
    puts table
    puts ActiveRecord::Base.connection.indexes(table).inspect
  end
"

Database Disk Full

# Check database size
psql -U postgres -c "
  SELECT pg_size_pretty(pg_database_size('chatwoot_production'));
"

# Check table sizes
psql -U postgres -d chatwoot_production -c "
  SELECT schemaname, tablename,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
  FROM pg_tables
  WHERE schemaname = 'public'
  ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
  LIMIT 10;
"

# Vacuum to reclaim space
psql -U postgres -d chatwoot_production -c "VACUUM FULL;"

# Archive old data
RAILS_ENV=production bundle exec rails runner "
  # Example: Archive conversations older than 1 year
  Conversation.where('created_at < ?', 1.year.ago).where(status: 'resolved').destroy_all
"

Sidekiq Issues

Jobs Not Processing

Diagnosis

# Check Sidekiq is running
ps aux | grep sidekiq
systemctl status chatwoot-worker

# Check queue sizes
redis-cli LLEN queue:default
redis-cli LLEN queue:critical
redis-cli LLEN queue:high

# Check for failed jobs
redis-cli ZCARD retry
redis-cli ZCARD dead

# View Sidekiq web UI
# Login as super admin and visit /monitoring/sidekiq

Solutions

# Restart Sidekiq
systemctl restart chatwoot-worker

# Clear stuck jobs (CAUTION: This deletes all jobs)
redis-cli DEL queue:default

# Retry all failed jobs
RAILS_ENV=production bundle exec rails runner "
  require 'sidekiq/api'
  Sidekiq::RetrySet.new.retry_all
"

# Clear dead jobs
RAILS_ENV=production bundle exec rails runner "
  require 'sidekiq/api'
  Sidekiq::DeadSet.new.clear
"

High Memory Usage

# Check Sidekiq memory
ps aux | grep sidekiq | awk '{print $6}'

# Reduce concurrency
export SIDEKIQ_CONCURRENCY=5
systemctl restart chatwoot-worker

# Restart Sidekiq periodically via cron
0 */6 * * * systemctl restart chatwoot-worker

Jobs Timing Out

From sidekiq.yml: timeout is 25 seconds

# Check for long-running jobs
RAILS_ENV=production bundle exec rails runner "
  require 'sidekiq/api'
  workers = Sidekiq::Workers.new
  workers.each do |process_id, thread_id, work|
    puts work.inspect if Time.now - work['run_at'] > 60
  end
"

# Increase timeout in config/sidekiq.yml
# :timeout: 60

# Or optimize the job
# Break into smaller chunks
# Add proper error handling

Redis Issues

Redis Out of Memory

# Check Redis memory
redis-cli INFO memory | grep used_memory_human

# Check max memory
redis-cli CONFIG GET maxmemory

# Increase max memory
redis-cli CONFIG SET maxmemory 4gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru

# Make permanent in redis.conf
echo "maxmemory 4gb" | sudo tee -a /etc/redis/redis.conf
echo "maxmemory-policy allkeys-lru" | sudo tee -a /etc/redis/redis.conf
sudo systemctl restart redis

# Clear cache if needed (CAUTION: Clears all data)
redis-cli FLUSHDB

Redis Connection Refused

# Check Redis is running
systemctl status redis

# Start Redis
systemctl start redis

# Check Redis port
netstat -tuln | grep 6379

# Test connection
redis-cli PING

# Check REDIS_URL
echo $REDIS_URL

# Test with password
redis-cli -a your_password PING

High Redis Latency

# Check latency
redis-cli --latency

# Check slow log
redis-cli SLOWLOG GET 10

# Identify slow commands
redis-cli --bigkeys

# Disable persistence temporarily
redis-cli CONFIG SET save ""

File Upload Issues

Attachments Not Uploading

# Check storage directory permissions
ls -la /app/storage
sudo chown -R chatwoot:chatwoot /app/storage

# Check disk space
df -h /app/storage

# Check max upload size in nginx
# /etc/nginx/nginx.conf
# client_max_body_size 20M;

# Check Rails config
grep -r "max_file_size" config/

Active Storage Issues

# Check Active Storage service
RAILS_ENV=production bundle exec rails runner "puts ActiveStorage::Blob.service.inspect"

# Verify S3 credentials (if using S3)
export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret
export S3_BUCKET_NAME=your_bucket

# Test S3 connection
RAILS_ENV=production bundle exec rails runner "
  require 'aws-sdk-s3'
  s3 = Aws::S3::Client.new
  puts s3.list_buckets.inspect
"

# Check blob records
RAILS_ENV=production bundle exec rails runner "puts ActiveStorage::Blob.count"

Email Delivery Issues

Emails Not Sending

# Check SMTP configuration
env | grep SMTP

# Test email sending
RAILS_ENV=production bundle exec rails runner "
  ActionMailer::Base.mail(
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Test email',
    body: 'Test body'
  ).deliver_now
"

# Check Sidekiq mailers queue
redis-cli LLEN queue:mailers

# View failed email jobs
grep "ActionMailer" log/production.log | tail -50

Email Configuration

# Required environment variables
SMTP_ADDRESS=smtp.gmail.com
SMTP_PORT=587
SMTP_DOMAIN=example.com
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=your_password
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true
MAILER_SENDER_EMAIL=[email protected]

WebSocket/Cable Issues

Real-time Updates Not Working

# Check Action Cable configuration
grep -r "cable" config/environments/production.rb

# Verify Redis connection for Action Cable
grep REDIS_URL .env

# Check browser console for errors
# Look for WebSocket connection failures

# Verify nginx WebSocket configuration
# Ensure proxy_set_header Upgrade $http_upgrade;
# Ensure proxy_set_header Connection "upgrade";

Performance Issues

High CPU Usage

# Identify process
top -c

# Check for runaway jobs
RAILS_ENV=production bundle exec rails runner "
  require 'sidekiq/api'
  Sidekiq::Workers.new.each { |p, t, w| puts w.inspect }
"

# Check database queries
# Look for N+1 queries in logs
grep "SELECT" log/production.log | wc -l

# Enable query logging
export RAILS_LOG_LEVEL=debug

High Memory Usage

# Check memory by process
ps aux --sort=-%mem | head -10

# Monitor memory over time
while true; do
  ps aux | grep -E "rails|sidekiq" | awk '{sum+=$6} END {print sum/1024 " MB"}'
  sleep 60
done

# Restart services to free memory
systemctl restart chatwoot-web chatwoot-worker

# Add memory limits in systemd
# MemoryLimit=2G in service file

Slow Response Times

# Enable request timing in logs
export RAILS_LOG_LEVEL=info

# Find slow requests
grep "Completed" log/production.log | awk '$NF>1000' | tail -20

# Check database query performance
psql -U postgres -d chatwoot_production -c "
  SELECT calls, mean_exec_time, query
  FROM pg_stat_statements
  ORDER BY mean_exec_time DESC
  LIMIT 10;
"

# Add database indexes
# See [Scaling Strategies](/self-hosting/scaling) for optimization tips

Docker-Specific Issues

Container Crashes

# Check container status
docker-compose ps

# View logs
docker-compose logs rails
docker-compose logs sidekiq

# Check resource limits
docker stats

# Restart containers
docker-compose restart rails sidekiq

# Rebuild if needed
docker-compose build
docker-compose up -d

Volume Permissions

# Check volume ownership
docker exec chatwoot-rails ls -la /app/storage

# Fix permissions
docker exec chatwoot-rails chown -R chatwoot:chatwoot /app/storage

# Or rebuild with correct UID/GID
# In Dockerfile:
# RUN useradd -u 1000 -m chatwoot

Getting Help

Gather Debug Information

#!/bin/bash
# debug-info.sh - Gather system information

echo "=== Chatwoot Debug Information ==="
echo ""

echo "Version:"
bundle exec rails runner "puts Chatwoot.config[:version]" 2>/dev/null || echo "Unable to determine"

echo "
Environment:"
env | grep -E "RAILS_ENV|NODE_ENV|POSTGRES|REDIS|STORAGE" | sort

echo "
Ruby Version:"
ruby --version

echo "
Rails Version:"
bundle exec rails --version

echo "
Database Status:"
psql -U postgres -d chatwoot_production -c "SELECT version()" 2>/dev/null || echo "Cannot connect"

echo "
Redis Status:"
redis-cli PING 2>/dev/null || echo "Cannot connect"

echo "
Recent Errors (last 20):"
grep -i error log/production.log | tail -20

echo "
Disk Usage:"
df -h

echo "
Memory Usage:"
free -h

Support Channels

When asking for help, provide:
  1. Chatwoot version
  2. Installation method (Docker/Source)
  3. Operating system
  4. Error messages from logs
  5. Steps to reproduce
  6. Output from debug script above

Build docs developers (and LLMs) love