
Live chat usually starts small. You add a widget to your marketing site, route messages into a shared inbox, and set up a few automations. Then the bill shows up.
Per-seat pricing turns “add one more teammate” into a budget meeting. If you want an Intercom-style setup without per-agent fees, a practical move in 2026 is to deploy Chatwoot on a VPS you control.
Chatwoot is an open-source customer support platform (AGPL-3.0). It covers live chat, a shared inbox, light automation, and team collaboration.
You run it on your own infrastructure. You choose retention and decide where customer data lives.
The tradeoff is ownership. Updates, backups, and TLS are on you.
The upside is predictable costs and a repeatable install. Docker Compose makes that easier.
Chatwoot, in plain terms: what you get and who it fits
Chatwoot sits between a basic “chat bubble” plugin and a full helpdesk suite. It’s built for teams that need a shared inbox and real-time conversations.
It’s also a good fit if you don’t want to hand customer messages to a hosted SaaS. It’s a fit if you don’t want to pay per seat, either.
- Best fit: SaaS founders, agencies, e-commerce stores, and ops teams that want a team inbox + live chat on their own domain.
- Not ideal: teams that need deep ITSM workflows, complex ticket SLAs, or heavy CRM features out of the box.
Operationally, Chatwoot is a familiar three-piece stack: the web app, PostgreSQL, and Redis. That maps cleanly to a single VPS today.
You can scale later by splitting services out.
How Chatwoot compares to Intercom-style hosted chat
Hosted chat wins on convenience. You sign up, paste a snippet, and you’re done.
Self-hosting wins on predictable cost and tighter control of data.
- Cost model: Intercom-style tools commonly scale with seats and contacts. Chatwoot scales with your server resources and your time.
- Data and retention: with Chatwoot, your messages, contacts, and attachments stay on your infrastructure (or your chosen object storage).
- Customization: you control domain, branding, headers, and proxy rules. You can also place it behind private networking if needed.
- Operational responsibility: you patch it, monitor it, and back it up. If you want less of that burden, managed hosting becomes attractive.
If the main pain is per-seat pricing, self-hosted Chatwoot is usually the clean fix.
If the main pain is “I don’t want to run servers,” a hosted product will feel easier day to day.
Resource planning before you deploy Chatwoot on a VPS
The most common failure mode is a too-small VPS. Low RAM and slow disk quickly turn into “the app is laggy” complaints.
Chatwoot itself isn’t huge. PostgreSQL and background jobs still need steady memory and fast storage.
- Small team (1–5 agents): 2 vCPU, 4 GB RAM, 50+ GB NVMe storage.
- Medium team (5–20 agents): 4 vCPU, 8 GB RAM, 80–160 GB NVMe.
- Busy inbox + long retention: prioritize disk and PostgreSQL tuning; consider 8+ GB RAM and a dedicated database host later.
For networking, keep it simple. Expose 80/443 and lock down everything else.
If you’re hosting multiple apps on one VPS, plan a reverse proxy from day one. It prevents routing sprawl later.
If you’d rather spend time on support workflows instead of OS maintenance, managed VPS hosting keeps the server baseline handled while you still control the application.
Deployment approach: Docker Compose on Ubuntu or Debian
Chatwoot supports containerized deployment. For most teams, Docker Compose hits the right balance.
You get a repeatable setup and readable config. Updates are also straightforward.
The steps below assume Ubuntu or Debian on a VPS, plus a real domain pointed at the server.
If you still need to point DNS at your VPS, this HostMyCode guide walks through changes without avoidable downtime: migrate a domain to Cloudflare DNS without downtime.
Prerequisites (quick checklist)
- A VPS (Ubuntu or Debian recommended)
- A domain/subdomain like
chat.example.compointing to your VPS IP - Docker + Docker Compose plugin installed
- A plan for TLS termination (Caddy or Nginx)
Create a minimal Compose stack
Create a working directory, for example:
sudo mkdir -p /opt/chatwoot
sudo chown -R $USER:$USER /opt/chatwoot
cd /opt/chatwoot
Then create docker-compose.yml. This is a solid starting point for a single-host install with Postgres and Redis on the same VPS:
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: chatwoot
POSTGRES_USER: chatwoot
POSTGRES_PASSWORD: change-this-password
volumes:
- ./data/postgres:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7
command: ["redis-server", "--appendonly", "yes"]
volumes:
- ./data/redis:/data
restart: unless-stopped
chatwoot:
image: chatwoot/chatwoot:latest
depends_on:
- postgres
- redis
environment:
RAILS_ENV: production
NODE_ENV: production
SECRET_KEY_BASE: replace-with-a-long-random-string
FRONTEND_URL: https://chat.example.com
POSTGRES_HOST: postgres
POSTGRES_DATABASE: chatwoot
POSTGRES_USERNAME: chatwoot
POSTGRES_PASSWORD: change-this-password
REDIS_URL: redis://redis:6379
ENABLE_ACCOUNT_SIGNUP: "false"
volumes:
- ./data/storage:/app/storage
restart: unless-stopped
A few operator notes:
- Pin major versions for databases (Postgres 16, Redis 7) so upgrades are intentional.
- Keep storage on a real disk volume. Chat attachments and avatar uploads live under
/app/storage. - Disable public signups once your admin account exists. You don’t want random registrations.
Boot it once, then create your first admin
Bring the stack up:
docker compose up -d
Next, create an admin user. Chatwoot provides Rails tasks, but the exact task name can vary by image tag.
The safe approach is to exec into the container first. Then list tasks and look for the admin-related one:
docker compose exec chatwoot bash -lc "bundle exec rails -T | grep -i admin"
After you create the admin, keep ENABLE_ACCOUNT_SIGNUP set to false (as shown). Then restart:
docker compose up -d
Reverse proxy + HTTPS: Caddy (simple) or Nginx (familiar)
A reverse proxy keeps your container network private. It also handles TLS, HSTS, and sensible request limits.
Nginx and Caddy both work. If you want fewer moving parts, Caddy’s automatic Let’s Encrypt setup is usually the fastest route.
Option A: Caddy with automatic TLS
If you want a step-by-step setup, HostMyCode’s walkthrough is straightforward: Set Up Let’s Encrypt With Caddy for a VPS Site.
Example /etc/caddy/Caddyfile:
chat.example.com {
encode gzip zstd
reverse_proxy 127.0.0.1:3000
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
}
}
This assumes Chatwoot is listening on localhost port 3000.
If your container only exposes an internal port, publish it explicitly in Compose. For example: ports: - "127.0.0.1:3000:3000". That keeps it off the public internet.
Option B: Nginx with Let’s Encrypt
If you already standardize on Nginx across your VPS fleet, stick with it. These two troubleshooting posts tend to come in handy sooner or later:
- Nginx 502 Bad Gateway Fix on Ubuntu VPS (usually upstream/proxy settings or an app not listening)
- Nginx 413 Request Entity Too Large Fix On VPS (common when customers upload screenshots/files)
Don’t ignore upload limits. Live chat conversations routinely include screenshots and small files.
Operational basics: mail delivery, DNS, and firewall
Chatwoot sends invites, password resets, and notifications. If email deliverability is shaky, people will blame the chat tool.
Sort SMTP early. It prevents a lot of avoidable noise.
- SMTP: use a reputable transactional SMTP provider or your own relay.
- Domain auth: publish SPF and DKIM, then add DMARC. This reduces spam-folder delivery.
If you need a clean refresher on domain authentication, this guide stays practical: Set Up DKIM, SPF, And DMARC For A Domain.
On the firewall side, keep it boring and strict:
- Allow
22/tcp(or your SSH port),80/tcp, and443/tcp. - Block direct database access from the internet. Postgres should not be listening on a public interface.
- If you publish Chatwoot’s app port for the reverse proxy, bind it to
127.0.0.1only.
Backups that actually help: Postgres + uploads + config
“We back up the VPS” isn’t a recovery plan. For Chatwoot, you need three things: the Postgres database, the persistent uploads directory, and the config that defines your stack.
What to back up
- Database: conversations, contacts, inbox configs, user accounts.
- Uploads: attachments and stored assets under
/opt/chatwoot/data/storage(or your chosen path). - Config:
docker-compose.yml, environment variables, reverse proxy config.
A practical backup routine (example)
Create a backup folder:
sudo mkdir -p /var/backups/chatwoot
sudo chown -R root:root /var/backups/chatwoot
sudo chmod 700 /var/backups/chatwoot
Database dump (run from the VPS):
cd /opt/chatwoot
docker compose exec -T postgres pg_dump -U chatwoot chatwoot | gzip > /var/backups/chatwoot/chatwoot.sql.gz
Archive uploads + Compose files:
tar -C /opt/chatwoot -czf /var/backups/chatwoot/chatwoot-files.tgz docker-compose.yml data/storage
Then ship those backups offsite (object storage, another VPS, or a backup provider). Offsite is the whole point.
Local copies help with small mistakes. They won’t save you from a dead disk, a compromised server, or a broken snapshot chain.
Test restores, not just backups
Once a month, restore to a scratch VM or a second VPS. Log in and confirm recent conversations show up.
If you can’t restore on demand, you don’t have backups—you have archives.
Updating Chatwoot safely (without breaking your inbox)
Self-hosting feels easy until update day. You want a routine you can repeat, roll back from, and run without surprises.
- Read release notes: especially for database migrations.
- Back up first: DB dump + storage archive.
- Pull images and restart: keep downtime predictable.
Typical update flow:
cd /opt/chatwoot
docker compose pull
docker compose up -d
docker image prune -f
If a migration is required, Chatwoot will usually run it during startup.
Still, watch logs on the first boot after an update:
docker compose logs -f --tail=200 chatwoot
Keep the OS patched as well. If you want automated security updates on Ubuntu, HostMyCode lays out a sensible baseline here: Set Up Automated Security Updates on Ubuntu VPS.
Common pitfalls (and how to avoid them)
- Uploads fail with 413 errors: raise
client_max_body_sizein Nginx or your proxy equivalent. See the HostMyCode fix guide linked above. - Random “bad gateway” after reboot: your reverse proxy starts before containers or points to the wrong upstream. Confirm ports and container health.
- Email doesn’t arrive: missing SPF/DKIM, blocked outbound SMTP, or bad SMTP credentials. Test with a single password reset email and check logs.
- Public signups left enabled: bots will find it. Turn off account signup after initial setup.
- No offsite backups: a VPS snapshot is not enough if the account is compromised or the snapshot chain breaks.
Where Chatwoot fits in a real hosting stack
Chatwoot works fine as a one-VPS app. It also fits nicely into a small internal tooling set:
- Pair it with a status page: run Uptime Kuma on the same VPS (or a second one) to watch your public endpoints. HostMyCode has a guide: Self-Host Uptime Kuma on a VPS With Nginx HTTPS.
- Document support workflows: if your team needs internal docs, BookStack is a solid companion. See: Run BookStack on a VPS With Docker and TLS.
If you host multiple customer sites (agency or reseller model), consider isolating Chatwoot on its own VPS.
That way, a noisy neighbor can’t drag down your client sites.
Summary: a predictable-cost live chat stack you control
Chatwoot is a strong replacement for hosted live chat when pricing scales faster than your headcount. You get a shared inbox, live chat, and ownership of customer conversations.
In return, you take on the basics: TLS, updates, backups, and monitoring.
If you want to run it on clean, fast infrastructure, start with a HostMyCode VPS. If you’d rather not spend your week on patching and service restarts, choose managed VPS hosting and keep the operational baseline tight while you focus on support.
If you’re rolling out Chatwoot for customer support, put it on a VPS with enough RAM for Postgres, Redis, and peak chat traffic. HostMyCode offers VPS plans that fit small teams and managed VPS hosting when you want the OS maintenance handled for you.
FAQ: Chatwoot self-hosting questions that come up early
Does Chatwoot replace Intercom completely?
It covers the core “website chat + shared inbox” workflow well. If you depend on a deep CRM, advanced outbound campaigns, or complex product tours, you may still keep separate tools.
Can I run Chatwoot on shared hosting?
Not realistically. Chatwoot needs background jobs, Redis, and a database you control. A VPS or dedicated server is the right fit.
What’s the minimum VPS size that won’t feel slow?
For a real team inbox, aim for 2 vCPU and 4 GB RAM. It’ll run on less, but PostgreSQL and background jobs will feel constrained under load.
Do I need a separate database server?
No for most small and medium teams. Start with Postgres on the same VPS, keep daily dumps, and move it out later if disk I/O or RAM becomes tight.
How do I keep Chatwoot secure?
Use HTTPS only, disable public signups after setup, keep your OS updated, restrict ports with a firewall, and store backups offsite. Treat it like any production web app.