--- title: "How to Install Chatwoot on Ubuntu 24.04 with Docker" description: "Deploy the Chatwoot customer support platform on Ubuntu 24.04 with Docker Compose, publish it over HTTPS with Nginx, set up SMTP and add a website live chat." category: "Web Applications Hosting" language: en source: https://cubepath.com/docs/web-applications-hosting/chatwoot-customer-support-installation updated: 2026-09-25 --- # How to Install Chatwoot on Ubuntu 24.04 with Docker Chatwoot is an open-source customer support platform that brings website live chat, email, WhatsApp, Telegram and other channels into a single shared inbox for your team. In this tutorial you will deploy Chatwoot on Ubuntu 24.04 using the official production Docker Compose file (Rails app, Sidekiq worker, PostgreSQL and Redis), publish it through Nginx with a Let's Encrypt certificate, configure outgoing email and add a live chat widget to a website. ## Prerequisites To follow this tutorial you need: - A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 4 GB of RAM (Rails, Sidekiq, PostgreSQL and Redis together use around 2 GB at idle) and 20 GB of free disk space. - A non-root user with `sudo` privileges. - Docker Engine and the Docker Compose plugin installed from Docker's official repository. `docker compose version` must print a v2 version. - A domain or subdomain (this guide uses `chat.your_domain`) with a DNS `A` record pointing to `your_server_ip`. - SMTP credentials for sending email (invitations, password resets and conversation notifications). ## Step 1 - Downloading the Chatwoot configuration Create a directory for the deployment: ```bash sudo mkdir -p /opt/chatwoot sudo chown $USER:$USER /opt/chatwoot cd /opt/chatwoot ``` Chatwoot maintains an example environment file and a production Compose file in its repository. Download both: ```bash 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 ``` The Compose file defines four services: `rails` (web app), `sidekiq` (background jobs), `postgres` and `redis`. The Rails port is published only on `127.0.0.1:3000`, so the app is reachable from the Internet only through Nginx. Confirm it: ```bash grep "3000:3000" docker-compose.yaml ``` ```output - '127.0.0.1:3000:3000' ``` ## Step 2 - Setting secrets and the public URL Generate the Rails secret, the PostgreSQL password and the Redis password, and write them into `.env`: ```bash sed -i "s|^SECRET_KEY_BASE=.*|SECRET_KEY_BASE=$(openssl rand -hex 64)|" .env sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 24)|" .env sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -hex 24)|" .env ``` Now open the file to set the public URL, disable open sign-ups and configure email: ```bash nano /opt/chatwoot/.env ``` Find and adjust these variables, replacing the placeholders with your values: ```ini FRONTEND_URL=https://chat.your_domain ENABLE_ACCOUNT_SIGNUP=false MAILER_SENDER_EMAIL=Support SMTP_DOMAIN=your_domain SMTP_ADDRESS=smtp.your_provider.com SMTP_PORT=587 SMTP_USERNAME=your_smtp_user SMTP_PASSWORD=your_smtp_password SMTP_AUTHENTICATION=login SMTP_ENABLE_STARTTLS_AUTO=true ``` - `FRONTEND_URL` is used to build links in emails and the widget script, so it must be the exact HTTPS URL. - `ENABLE_ACCOUNT_SIGNUP=false` prevents strangers from creating accounts on your instance. You will create the first account through the installation onboarding. Leave `POSTGRES_HOST=postgres` and `REDIS_URL=redis://redis:6379` as they are: they point to the service names in the Compose file. Check the values you set: ```bash grep -E '^(FRONTEND_URL|ENABLE_ACCOUNT_SIGNUP|POSTGRES_HOST|POSTGRES_DATABASE|REDIS_URL|SMTP_ADDRESS)=' .env ``` ```output FRONTEND_URL=https://chat.your_domain ENABLE_ACCOUNT_SIGNUP=false POSTGRES_HOST=postgres POSTGRES_DATABASE=chatwoot_production REDIS_URL=redis://redis:6379 SMTP_ADDRESS=smtp.your_provider.com ``` The `postgres` container creates its superuser from the `POSTGRES_PASSWORD` set in the Compose file, not from `.env`. Print the generated password and copy it: ```bash grep '^POSTGRES_PASSWORD=' .env ``` Open `docker-compose.yaml`, find the `environment` list of the `postgres` service and set the same value on its `POSTGRES_PASSWORD` line, leaving the other lines as they are: ```bash nano /opt/chatwoot/docker-compose.yaml ``` ```yaml - POSTGRES_PASSWORD=paste_the_generated_password_here ``` Validate the file: ```bash docker compose config --quiet && echo "docker-compose.yaml OK" ``` ## Step 3 - Preparing the database and starting Chatwoot Run the database preparation task once. It starts PostgreSQL and Redis, creates the database and runs the migrations: ```bash docker compose run --rm rails bundle exec rails db:chatwoot_prepare ``` The first run pulls the images and takes a few minutes. When it finishes without errors, start all services: ```bash docker compose up -d docker compose ps ``` ```output NAME SERVICE STATUS PORTS chatwoot-postgres-1 postgres Up 2 minutes 127.0.0.1:5432->5432/tcp chatwoot-rails-1 rails Up 40 seconds 127.0.0.1:3000->3000/tcp chatwoot-redis-1 redis Up 2 minutes 127.0.0.1:6379->6379/tcp chatwoot-sidekiq-1 sidekiq Up 40 seconds ``` Rails needs about 30 seconds to boot. Then check that the API answers: ```bash curl -sI http://127.0.0.1:3000/api | head -n 1 ``` ```output HTTP/1.1 200 OK ``` If it does not, read the logs with `docker compose logs --tail=50 rails`. ## Step 4 - Configuring Nginx and HTTPS Install Nginx and Certbot and open the web ports: ```bash sudo apt install nginx certbot python3-certbot-nginx sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` Chatwoot uses Action Cable (WebSockets on `/cable`) to push new messages to agents and to the chat widget, so the proxy must forward the `Upgrade` headers. Its API also uses an `api_access_token` header, which contains underscores; Nginx drops such headers unless `underscores_in_headers` is enabled. Create the server block: ```bash sudo nano /etc/nginx/sites-available/chatwoot ``` ```nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; listen [::]:80; server_name chat.your_domain; underscores_in_headers on; client_max_body_size 40M; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3600s; } } ``` `client_max_body_size` allows agents and customers to upload attachments. Enable the site and reload Nginx: ```bash sudo ln -s /etc/nginx/sites-available/chatwoot /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` Request the certificate. Certbot adds the TLS configuration and an HTTP to HTTPS redirect: ```bash sudo certbot --nginx -d chat.your_domain ``` Verify the public endpoint: ```bash curl -sI https://chat.your_domain/api | head -n 1 ``` ```output HTTP/2 200 ``` The `certbot.timer` systemd timer renews the certificate automatically; `sudo certbot renew --dry-run` confirms it. ## Step 5 - Creating the administrator account Open `https://chat.your_domain`. On a fresh installation Chatwoot shows an onboarding form. Enter your name, company name, email and a strong password. This creates the first account and a **super admin** user. After logging in you land on the conversations dashboard. The super admin console, where you manage accounts, users and instance-wide settings, is at `https://chat.your_domain/super_admin`. ## Step 6 - Adding a website live chat inbox An inbox is a channel through which customers reach you. To add live chat to a website: 1. Go to **Settings > Inboxes** and click **Add Inbox**. 2. Choose **Website**, enter the website name and domain, and customize the widget color and welcome message. 3. Select the agents who will answer this inbox and click **Add agents**. 4. Chatwoot shows a JavaScript snippet. Paste it before the closing `` tag of your website. Reload your website: a chat bubble appears in the corner. Send a test message from the widget and it shows up in **Conversations** in the Chatwoot dashboard. Reply from the dashboard and the answer appears in the widget in real time, which confirms that WebSockets work through Nginx. ## Step 7 - Inviting agents and organizing work - **Agents**: go to **Settings > Agents**, click **Add Agent**, enter a name and email and choose the **Agent** or **Administrator** role. The agent receives an invitation email, which also confirms that SMTP works. - **Teams**: under **Settings > Teams**, group agents (for example `Billing` and `Technical`) so conversations can be assigned to a team. - **Labels and automation**: create labels under **Settings > Labels**, and use **Settings > Automation** to assign or label conversations based on conditions such as the inbox or message content. If the invitation email does not arrive, check `docker compose logs --tail=100 sidekiq`: emails are sent by the Sidekiq worker, and SMTP errors are logged there. ## Step 8 - Backing up Chatwoot Conversations, contacts and settings live in PostgreSQL; attachments live in the `storage_data` volume (with the default `ACTIVE_STORAGE_SERVICE=local`). Create a backup directory and dump the database, using the database name from `POSTGRES_DATABASE` in `.env`: ```bash sudo install -d -m 700 -o $USER /var/backups/chatwoot cd /opt/chatwoot docker compose exec -T postgres pg_dump -U postgres chatwoot_production | gzip > /var/backups/chatwoot/chatwoot-db-$(date +%F).sql.gz ``` Find the full name of the storage volume, which Compose prefixes with the project name: ```bash docker volume ls --filter name=storage ``` ```output DRIVER VOLUME NAME local chatwoot_storage_data ``` Archive it: ```bash docker run --rm -v chatwoot_storage_data:/data:ro -v /var/backups/chatwoot:/backup alpine \ tar czf /backup/chatwoot-storage-$(date +%F).tar.gz -C /data . ls -lh /var/backups/chatwoot ``` Keep a copy of `/opt/chatwoot/.env` and `docker-compose.yaml` together with these files, and copy everything off the server. ## Step 9 - Updating Chatwoot Take a backup first, then pull the new images, run the migrations and recreate the containers: ```bash cd /opt/chatwoot docker compose pull docker compose run --rm rails bundle exec rails db:chatwoot_prepare docker compose up -d docker image prune -f ``` Check the release notes before major upgrades, since new versions sometimes add required variables to `.env.example`. ## Troubleshooting - **Messages only appear after reloading the page**: WebSockets to `/cable` are not getting through. Check the `map` block and the `Upgrade`/`Connection` headers in Nginx. - **API calls with `api_access_token` return 401 through Nginx but work on port 3000**: `underscores_in_headers on;` is missing from the server block. - **`db:chatwoot_prepare` fails with a password authentication error**: the `POSTGRES_PASSWORD` in `.env` does not match the one in `docker-compose.yaml`. If the database volume was already initialized with another password, remove it with `docker compose down -v` (this deletes all data, so only do it on a fresh install) and run the task again. - **Links in emails point to the wrong host**: `FRONTEND_URL` is wrong. Fix it and run `docker compose up -d`. ## Conclusion Chatwoot is now running on Ubuntu 24.04 behind Nginx with HTTPS, with working email, a website live chat inbox and a backup and update routine. As next steps, connect an email inbox so customer emails become conversations, add canned responses for common questions, and schedule the backup commands with a systemd timer or cron.