Self-Hosting Chatwoot: Customer Support 2026
Chatwoot is the open source Intercom and Zendesk alternative. Self-hosting gives you unlimited agents, unlimited conversations, and omnichannel support — website live chat, email, WhatsApp, Facebook, Twitter, Telegram, and more.
Why Self-Host Chatwoot
Intercom's pricing has become a running joke in the startup community. Their Starter plan at $74/month covers only 1 seat with basic features. The Pro plan — required for automation and multiple inboxes — starts at $395/month and scales per seat. For a 10-person support team using Intercom Pro, expect to spend $4,000-8,000 annually. Zendesk Suite Professional runs $115/agent/month, making a 5-agent team $6,900/year.
Self-hosting Chatwoot on a €8/month Hetzner server costs approximately $96/year total — regardless of how many agents you add or how many conversations you handle. The math is stark: a 10-agent team saves upward of $4,000-7,000 annually compared to Intercom or Zendesk.
Omnichannel without per-channel fees. Intercom and Zendesk charge extra for WhatsApp, Twitter, and other channels. Chatwoot includes all channel types in the core product. Website live chat, email inboxes, WhatsApp Business via 360dialog, Facebook Messenger, Twitter DMs, Telegram, Line, and SMS via Twilio — all configurable from a single Chatwoot instance at no additional license cost.
Conversation data belongs to you. Customer support conversations often contain your most sensitive business data — complaints, billing disputes, user credentials in screenshots, private product roadmap discussions. Hosting on your infrastructure means that data never touches a third-party SaaS provider's servers. This is particularly important for companies with enterprise customers who have data processing agreements in their contracts.
Customization at the code level. Because Chatwoot is open source (MIT licensed), you can fork it and customize the agent interface, add custom integrations with internal tools, or modify the conversation routing logic. This level of customization is impossible with SaaS products regardless of plan tier.
When NOT to self-host Chatwoot: Chatwoot is a Ruby on Rails application with multiple services (Sidekiq for background jobs, PostgreSQL, Redis). It requires more maintenance than simpler tools. If your support team needs reliable on-call coverage and lacks engineering resources to handle incidents, the guaranteed uptime of Intercom or Zendesk may justify the cost. Also, some enterprise integrations (Salesforce, Zendesk ticket sync) are more polished in commercial products.
Prerequisites
Chatwoot requires 4 GB RAM minimum due to Ruby on Rails memory usage, plus PostgreSQL and Redis running alongside it. Server selection significantly impacts performance. Review VPS options for self-hosters with these constraints in mind.
Server specs: 4 GB RAM is the floor for Chatwoot in production. With 1-5 agents, 4 GB works. For 5-20 agents with active conversation volume, 8 GB RAM prevents Sidekiq from competing with the Rails app for memory. Ruby processes are notoriously memory-hungry — monitor memory usage after the first week of production use and scale up if needed.
Operating system: Ubuntu 22.04 LTS. Chatwoot's official Docker setup and community documentation assume Ubuntu. The official install script targets Ubuntu specifically.
Sidekiq for background jobs: Chatwoot runs a separate Sidekiq process that handles email sending, webhook delivery, automation triggers, and notification processing. Both the main app container and the Sidekiq container must be running for Chatwoot to function fully — a common source of confusion when email notifications stop working.
SMTP configuration: Email channel integration and notification delivery require working SMTP. Configure this before inviting agents — their account activation emails and conversation notifications depend on it.
Object storage for scale: By default, Chatwoot stores attachments locally. For a team receiving file attachments in conversations (screenshots, documents), local storage fills up quickly. Plan to migrate to S3-compatible object storage (Cloudflare R2 or AWS S3) before you hit storage limits.
Skills required: Comfortable with multi-service Docker Compose, Rails console commands for initial setup, and basic understanding of background job queues. The initial setup requires running a Rails console command to create the first admin account.
Requirements
- VPS with 4 GB RAM minimum (8 GB recommended)
- Docker and Docker Compose
- Domain name (e.g.,
support.yourdomain.com) - 20+ GB disk
- SMTP service for email
Step 1: Clone and Configure
# Download Chatwoot Docker setup
git clone https://github.com/chatwoot/chatwoot.git
cd chatwoot
# Copy environment file
cp .env.example .env
Step 2: Configure Environment
Edit .env:
# App
SECRET_KEY_BASE=your-random-secret-key-here
FRONTEND_URL=https://support.yourdomain.com
DEFAULT_LOCALE=en
# Database
POSTGRES_HOST=postgres
POSTGRES_USERNAME=chatwoot
POSTGRES_PASSWORD=your-strong-password
POSTGRES_DATABASE=chatwoot
# Redis
REDIS_URL=redis://redis:6379
# SMTP
MAILER_SENDER_EMAIL=support@yourdomain.com
SMTP_ADDRESS=smtp.resend.com
SMTP_PORT=587
SMTP_USERNAME=resend
SMTP_PASSWORD=re_your_api_key
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true
# Storage (local or S3)
ACTIVE_STORAGE_SERVICE=local
Generate secret key:
openssl rand -hex 64
Step 3: Docker Compose Setup
# docker-compose.yml
services:
chatwoot:
image: chatwoot/chatwoot:latest
container_name: chatwoot
restart: unless-stopped
ports:
- "3000:3000"
env_file: .env
environment:
- RAILS_ENV=production
- NODE_ENV=production
volumes:
- chatwoot_storage:/app/storage
depends_on:
- postgres
- redis
command: bundle exec rails s -p 3000 -b 0.0.0.0
sidekiq:
image: chatwoot/chatwoot:latest
container_name: chatwoot-sidekiq
restart: unless-stopped
env_file: .env
environment:
- RAILS_ENV=production
volumes:
- chatwoot_storage:/app/storage
depends_on:
- postgres
- redis
command: bundle exec sidekiq -C config/sidekiq.yml
postgres:
image: postgres:16-alpine
container_name: chatwoot-db
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=chatwoot
- POSTGRES_USER=chatwoot
- POSTGRES_PASSWORD=your-strong-password
redis:
image: redis:7-alpine
container_name: chatwoot-redis
restart: unless-stopped
volumes:
- redis_data:/data
volumes:
chatwoot_storage:
postgres_data:
redis_data:
Step 4: Initialize and Start
# Start services
docker compose up -d
# Run database migrations
docker exec chatwoot bundle exec rails db:chatwoot_prepare
# Create admin account
docker exec -it chatwoot bundle exec rails console
# In console:
# SuperAdmin.create!(email: 'admin@yourdomain.com', password: 'your-password')
# exit
Step 5: Reverse Proxy (Caddy)
# /etc/caddy/Caddyfile
support.yourdomain.com {
reverse_proxy localhost:3000
}
sudo systemctl restart caddy
Step 6: Set Up Channels
Website Live Chat:
- Settings → Inboxes → Add Inbox → Website
- Set your website domain
- Customize widget appearance
- Copy the widget script:
<script>
(function(d,t) {
var BASE_URL="https://support.yourdomain.com";
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=BASE_URL+"/packs/js/sdk.js";
g.defer = true;
g.async = true;
s.parentNode.insertBefore(g,s);
g.onload=function(){
window.chatwootSDK.run({
websiteToken: 'YOUR_WEBSITE_TOKEN',
baseUrl: BASE_URL
})
}
})(document,"script");
</script>
Email Channel:
- Settings → Inboxes → Add Inbox → Email
- Configure IMAP for receiving emails
- Configure SMTP for sending replies
WhatsApp (via 360dialog or Twilio):
- Settings → Inboxes → Add Inbox → WhatsApp
- Enter API key from your WhatsApp Business provider
Additional channels: Facebook, Twitter, Telegram, Line, SMS (via Twilio)
Step 7: Configure Team
- Settings → Agents → invite team members
- Settings → Teams → create teams (Sales, Support, Billing)
- Settings → Automation → set up auto-assignment rules
Useful automations:
| Trigger | Action |
|---|---|
| New conversation | Auto-assign to available agent |
| Message contains "billing" | Assign to Billing team |
| No response in 1 hour | Send reminder to agent |
| Conversation resolved | Send satisfaction survey |
Step 8: Canned Responses
Set up quick responses for common questions:
- Settings → Canned Responses
- Create shortcuts like
/greeting,/pricing,/hours - Agents type the shortcut to insert the full response
Production Hardening
S3 Storage (for file attachments at scale):
ACTIVE_STORAGE_SERVICE=amazon
S3_BUCKET_NAME=your-bucket
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_REGION=us-east-1
Backups:
# Database backup (daily cron)
docker exec chatwoot-db pg_dump -U chatwoot chatwoot > /backups/chatwoot-$(date +%Y%m%d).sql
# File storage backup
docker cp chatwoot:/app/storage /backups/chatwoot-storage-$(date +%Y%m%d)
For offsite backups, pair local pg_dump with automated server backups using restic. Customer conversation history is critical business data — daily backups pushed to Backblaze B2 give you a reliable recovery path.
Updates:
docker compose pull
docker compose up -d
docker exec chatwoot bundle exec rails db:chatwoot_prepare
Monitoring:
- Monitor port 3000 with Uptime Kuma
- Monitor Sidekiq queue depth (Redis)
- Set up disk space alerts
Resource Usage
| Agents | RAM | CPU | Disk |
|---|---|---|---|
| 1-5 | 4 GB | 2 cores | 20 GB |
| 5-20 | 8 GB | 4 cores | 50 GB |
| 20-50 | 16 GB | 8 cores | 100 GB |
VPS Recommendations
| Provider | Spec (10 agents) | Price |
|---|---|---|
| Hetzner | 4 vCPU, 8 GB RAM | €8/month |
| DigitalOcean | 4 vCPU, 8 GB RAM | $48/month |
| Linode | 4 vCPU, 8 GB RAM | $48/month |
Production Security Hardening
Customer support software handles some of the most sensitive data in your business — user complaints, billing information, private communications. The self-hosting security checklist covers foundational server security; here are Chatwoot-specific priorities.
UFW firewall: Block all direct service access; only expose Caddy's ports.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 3000/tcp # Block direct Chatwoot app access
sudo ufw enable
Fail2ban for SSH protection:
sudo apt install fail2ban -y
/etc/fail2ban/jail.local:
[sshd]
enabled = true
maxretry = 5
bantime = 3600
findtime = 600
Protect the .env file: Your .env contains the SECRET_KEY_BASE and SMTP credentials. If this key changes, all existing sessions become invalid and users must log in again.
chmod 600 .env
echo ".env" >> .gitignore
Disable SSH password authentication: Edit /etc/ssh/sshd_config:
PasswordAuthentication no
PermitRootLogin no
Restart: sudo systemctl restart sshd
Automatic security updates:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
Chatwoot-specific: Lock down access to the admin panel by IP address if your support team works from fixed office IPs. Use Caddy's remote_ip matcher to restrict access. Regularly rotate agent credentials and disable accounts immediately when agents leave the team.
Troubleshooting Common Issues
Live chat widget loads but conversations don't appear in the inbox
The most common cause is a mismatch between the FRONTEND_URL environment variable and the actual URL. Chatwoot uses this URL to validate WebSocket connections from the widget. Verify FRONTEND_URL=https://support.yourdomain.com exactly (no trailing slash) and restart the chatwoot container.
Emails not being delivered from email inboxes
Chatwoot's email sending runs through Sidekiq, not the main Rails process. If Sidekiq isn't running, emails queue up indefinitely. Check: docker ps to confirm chatwoot-sidekiq is running and docker logs chatwoot-sidekiq for errors. Sidekiq and the main app must share the same Redis instance and the same .env file.
WhatsApp integration shows "Webhook verification failed"
WhatsApp webhooks require HTTPS with a valid SSL certificate. Verify Caddy has issued a certificate: curl -I https://support.yourdomain.com should return a valid cert. Also, the webhook URL registered in your 360dialog or Twilio account must exactly match your Chatwoot installation's webhook URL. Check the Chatwoot docs for the exact path format.
"500 Internal Server Error" after updating
After pulling a new Chatwoot image, database migrations must run: docker exec chatwoot bundle exec rails db:chatwoot_prepare. If you skip this step after updates, new features that depend on schema changes fail with 500 errors. Always run migrations after docker compose up -d following an update.
File attachments not saving after switching to S3
After changing ACTIVE_STORAGE_SERVICE to amazon, existing local attachments are no longer accessible. There's no automatic migration. If switching mid-deployment, either migrate existing files manually to S3 (using the Rails console to re-attach blobs) or accept that old attachments will be inaccessible and only new ones go to S3. Plan storage backend choice before going live.
Ongoing Maintenance and Operations
A self-hosted customer support platform requires more operational attention than most tools because it's customer-facing — downtime directly impacts your customers' ability to reach you.
Uptime is critical. Unlike internal tools where brief downtime is inconvenient, a customer support chat being down means customers can't get help. Monitor with multi-location uptime checks (Uptime Kuma or Better Uptime) and configure alerts to go to multiple channels — your own Mattermost or Slack, email, and SMS. Set up automatic restart on failure: restart: unless-stopped in Docker Compose handles most cases, but a systemd watchdog for the entire Docker Compose stack provides an additional recovery layer.
Conversation assignment workflows. Effective Chatwoot usage depends on keeping conversations from falling through the cracks. Configure automation rules that auto-assign conversations to specific agents or teams based on inbox, keywords, or time of day. For round-robin assignment, install the Auto Assignment feature in your team settings. Review unassigned conversations in your daily standup — any open conversation without an assignee is a customer waiting for a response.
CSAT (Customer Satisfaction) surveys. Enable satisfaction surveys in Settings → Account Settings → Integrations → CSAT. Chatwoot sends a satisfaction survey via email after conversations are resolved. Track your weekly CSAT score and use low scores as a signal to review how specific conversations were handled. This data is only available in self-hosted Chatwoot — you own the full dataset.
Agent performance reporting. Chatwoot's reports section shows first response time, resolution time, and conversation volume per agent. Review these metrics weekly with your support team. Long first response times indicate staffing gaps; high re-open rates suggest resolutions are too quick without fully addressing the issue.
Webhook integrations. Chatwoot can post conversation events (new conversation, message created, resolved) to external webhooks. Use this to sync support data to your CRM, create internal tickets in Jira or Linear when SLA thresholds are breached, or build custom reporting dashboards. Configure webhooks in Settings → Integrations → Webhooks.
Archiving old conversations. PostgreSQL performance can degrade as the conversation table grows to millions of rows without proper maintenance. Add a partial index on frequently-queried columns (inbox_id, status, assignee_id) to maintain query performance. Chatwoot's development team has acknowledged performance issues at high conversation volumes — monitor query times using docker exec chatwoot-db psql -U chatwoot -c "SELECT pid, query, state FROM pg_stat_activity WHERE state != 'idle';" if you notice dashboard slowness.
Team onboarding. Chatwoot's agent interface is intuitive but benefits from a brief orientation. Create a written guide covering: keyboard shortcuts (J/K to navigate conversations, R to reply), how canned responses work, and your team's escalation process. This reduces the time new agents spend figuring out the tool and gets them handling conversations faster.
Compare customer support platforms on OSSAlt — channels, features, and pricing side by side.
See open source alternatives to Chatwoot on OSSAlt.