Overview
Chatwoot is an open-source customer engagement platform — an embeddable live-chat widget, a shared email inbox, and an omnichannel agent desk in one application. This template deploys the Community Edition (-ce image, MIT core): a Rails web tier serving the dashboard, REST API, widget and WebSockets on port 3000, a Sidekiq worker that also runs database migrations, a bundled single-node Redis, and a pgvector-capable PostgreSQL — highly available by default, or single-instance with one flag. Attachments go to a persistent volume or to object storage.
--gvc GVC_NAME.What Gets Created
Prerequisites
Chatwoot signs its sessions and encrypts sensitive columns with four keys that you supply through a dictionary secret created before installing. The values never pass through Helm values.Create the keys secret
--gvc flag is involved:secrets.name to this name.Back the four values up
SECRET_KEY_BASE logs out every user, and rotating any ACTIVE_RECORD_ENCRYPTION_* key makes stored two-factor secrets undecryptable, locking out every agent who enabled MFA.Choose the two bundled passwords
postgres.credentials.password) and the Redis password (redis.auth.password) ship as change-me-… placeholders that the template uses as-is. Pick strong values and pass them at install time — both seed their component on first boot and are not updated by later value edits. The Redis password may contain only letters, digits, - and _.- Object-storage attachments — an existing bucket plus either a Control Plane cloud account (AWS S3) or a static-key dictionary secret (S3-compatible servers). See Attachment Storage. Required for more than one web replica.
- Authenticated SMTP — a dictionary secret holding
SMTP_USERNAMEandSMTP_PASSWORD. See Email. - Database backups — a bucket and access setup for AWS S3, Google Cloud Storage or an S3-compatible server. See Backing Up.
Installation
Once the keys secret exists, install into your existing GVC with the two bundled passwords set:UI
CLI
Terraform
Pulumi
Configuration
Each subsection shows the shipped defaults for one top-level values area.Chatwoot Web
chatwoot.image. Leave chatwoot.frontendUrl empty unless you front Chatwoot with a custom domain; both tiers then advertise the web workload’s public URL in links.
Sidekiq Worker
worker.concurrency, not replicas. It has no probes, so it reports ready as soon as it is scheduled, even while migrating — read its logs rather than its readiness:
Prerequisite Secret
Attachment Storage
- Local volume (default)
- AWS S3 (keyless)
- S3-compatible (MinIO and others)
/app/storage on the web workload and survive restarts, redeploys and upgrades under the same release name.The volume is attached to the web workload only, so the Sidekiq worker cannot read attachments in this mode — attachment emails and ActiveStorage analyze and purge jobs cannot succeed. Local storage also works only with a single web replica. Use object storage for production.smtp.auth.secretName to its name; the Chatwoot identity is granted reveal on exactly that secret:
Access
publicAccess.enabled: false for an internal-only instance; in-GVC callers still reach it according to internalAccess.type:
Database
Enable exactly one ofpostgresHA (default) and postgres — the chart refuses to render with both or neither. Chatwoot is wired to the active database automatically: the HAProxy leader endpoint in HA mode, or the single instance directly. In both modes the database credentials come from postgres.credentials.*: this template writes them into a dictionary secret named by postgresHA.config.credentialsSecretName or postgres.config.credentialsSecretName and hands that name to the bundled database. There is nothing for you to create.
postgresHA.* and postgres.*, with one exception: postgresHA.proxy.enabled must stay true, because the HAProxy endpoint is the address Chatwoot connects to.
Redis
redis.auth.password before installing; only letters, digits, - and _ are accepted because the value is embedded in a connection URL.
Connecting
3000 and query the readiness route, which reports the PostgreSQL and Redis status:
First Run
Chatwoot ships no default account. The first browser session to reach the endpoint runs the onboarding wizard, and the user it creates is the super admin.Wait for the web workload to report ready
Complete the onboarding wizard
RELEASE_NAME-chatwoot. It redirects to /installation/onboarding, where the form creates your account and the super admin user. Do this as soon as the workload is ready — the wizard is unauthenticated until it has been completed. For an install with publicAccess.enabled: false, reach the same page through cpln port-forward RELEASE_NAME-chatwoot 3000:3000 --gvc GVC_NAME at http://localhost:3000.Create an inbox
Configure email before inviting agents
https://<canonical>.cpln.app/super_admin; under Settings, ENABLE_ACCOUNT_SIGNUP controls whether visitors can create their own accounts. Self-serve signup is off on a fresh install — accounts come from the onboarding wizard and from agent invitations until you turn it on.
Operations
Backing Up
Database backups are optional and off by default. They cover the PostgreSQL database — conversations, contacts, inboxes and users. Attachments are not included: in object-storage mode they live in your bucket, in local mode on theRELEASE_NAME-chatwoot-storage volume set.
Enable backups with postgresHA.backup.enabled: true or postgres.backup.enabled: true (matching your database mode) and complete the storage setup for your provider before installing. The keys below are shown as backup.*; set them inside the enabled database block.
- AWS S3
- Google Cloud Storage
- S3-compatible (MinIO and others)
Create a bucket
backup.aws.bucket and backup.aws.region to match.Set up a cloud account
backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
YOUR_BUCKET_NAME), then set backup.aws.policyName to the policy’s name:backup.mode selects logical (a scheduled dump run by the RELEASE_NAME-postgres-ha-backup cron workload) or wal-g (continuous WAL archiving from the database workload). Single-instance mode takes scheduled logical dumps through RELEASE_NAME-postgres-backup. backup.*.prefix is the key prefix within the bucket, and the schedule is a standard cron expression in UTC.
Restoring a Backup
The database restore is the one documented for the bundled database: Restoring a Backup on the postgres-highly-available page (logical and WAL-G), or Restoring a Backup on the postgres page. In HA mode, connect throughRELEASE_NAME-postgres-ha-proxy.GVC_NAME.cpln.local so the restore targets the current leader; use the username and password from the secret named by *.config.credentialsSecretName.
Two Chatwoot-specific points:
-
The web and worker workloads must not be writing to the database while a logical dump is replayed. After the restore, force a redeployment of both so they reconnect and the cache is rebuilt:
-
Attachments are restored separately: copy them back into the bucket (object-storage mode) or onto the
RELEASE_NAME-chatwoot-storagevolume set (local mode).
Upgrading From 1.0.0
Version1.0.1 only updates the bundled highly available database to a release that compacts its etcd cluster. Without compaction, etcd’s backend grows with time alone and eventually goes read-only, taking PostgreSQL failover with it. Upgrade; see etcd History Compaction for the mechanism and the symptoms. Only installs running the HA database (postgresHA.enabled, the default) are affected. Compaction stops further growth but cannot shrink a backend that has already grown.
Upgrading From 1.0.1 or Earlier
Version1.1.0 changed the single-instance database path:
postgres.config.username,postgres.config.passwordandpostgres.config.databasemoved topostgres.credentials.username,postgres.credentials.passwordandpostgres.credentials.database. The newpostgres.config.credentialsSecretNamenames the dictionary secret this template now creates from those three values. Carrying the old keys fails the render withconfig.username was REMOVED in postgres 3.4.0— move the three keys and you are done, and ignore that message’s advice to create a secret yourself.postgres.backup.minio.accessKeyandpostgres.backup.minio.secretKeywere replaced bypostgres.backup.minio.credentialsSecretName, a prerequisite dictionary secret holdingaccessKeyandsecretKey— see Backing Up.
postgres.credentials.* equal to the values your database was initialised with; the running database still enforces them.
Upgrading From 1.1.0 or Earlier
Version1.2.0 moved the highly available database to postgres-highly-available 2.5.0, which no longer creates its own credentials secret:
postgresHA.postgres.username,postgresHA.postgres.passwordandpostgresHA.postgres.databasewere removed. Carrying them fails the render withthe postgres block was REMOVED in 2.5.0. Delete the block.- In HA mode the credentials now come from
postgres.credentials.*— the same keys the single-instance path uses — and this template writes them into the secret named by the newpostgresHA.config.credentialsSecretName.
Upgrading From 1.2.0 or Earlier
Version1.2.1 replaced postgresHA.backup.minio.accessKey and postgresHA.backup.minio.secretKey with postgresHA.backup.minio.credentialsSecretName, a prerequisite dictionary secret holding accessKey and secretKey. Only installs backing up the HA database to an S3-compatible server are affected — see Backing Up for the secret.
Scaling and Availability
-
Web tier —
chatwoot.replicassets how many web replicas run. Replicas share the database and the bundled Redis, so a message received by one replica reaches a WebSocket client connected to another, and no sticky sessions are needed. Anything above1requiresstorage.types3ors3-compatible; the chart refuses to render the combination with local storage. -
Worker and Redis — both are fixed at one replica. Scale background throughput with
worker.concurrency. -
Database — the default
postgresHApath keeps serving through a replica failure and a rolling restart; thepostgrespath has no failover and is for development or light use. The mode is an install-time choice. -
Helm upgrades — a
helm upgradecan restart the bundled datastores even when their values did not change, and the web tier is unready while Redis is down; upgrade in a quiet window. -
After any Redis restart, restart the web workload. Background jobs and the cache reconnect on their own, but the web tier’s live-update subscription does not: nothing is logged, the health endpoint stays green, and agents and visitors stop seeing new messages until they refresh. A forced redeployment of the web workload restores it:
Troubleshooting
The deployment never starts and cpln logs is empty
The deployment never starts and cpln logs is empty
RELEASE_NAME-chatwoot and RELEASE_NAME-chatwoot-worker never reach ready, and cpln logs returns zero lines.Cause: a secret referenced by name does not exist — usually the keys secret (secrets.name), or the storage or SMTP secret when those features are enabled. The container never starts, so there is nothing to log.Fix: read status.versions[].message, which names the missing secret, then create it. The deployment recovers on its own after several minutes, or force a redeployment to skip the wait.The web workload stays unready and logs waiting for the chatwoot schema
The web workload stays unready and logs waiting for the chatwoot schema
waiting for the chatwoot schema... and the readiness probe never passes.Cause: the web tier deliberately stays down until the worker has created the schema, so this means the worker’s migration has not completed. On a first HA install the worker restarts a few times with PG::ConnectionBad while the database cluster elects a leader, which is expected. A migration that keeps failing is not.Fix: read the worker’s log — the worker reports ready even while crash-looping, so its readiness is not a signal.Live updates stopped after a Redis restart
Live updates stopped after a Redis restart
/api still reports healthy and nothing is logged.Cause: the bundled Redis restarted (a redeploy, a reschedule or a Helm upgrade) and the web tier’s live-update subscription did not re-establish.Fix: force a redeployment of the web workload.Render fails with config.username was REMOVED in postgres 3.4.0
Render fails with config.username was REMOVED in postgres 3.4.0
helm upgrade fails before anything is applied, citing config.username was REMOVED in postgres 3.4.0.Cause: your values still carry the 1.0.x single-instance keys postgres.config.username, postgres.config.password or postgres.config.database.Fix: move the three keys to postgres.credentials.* as described in Upgrading From 1.0.1 or Earlier. Do not create a secret yourself — this template creates it.Render fails with the postgres block was REMOVED in 2.5.0
Render fails with the postgres block was REMOVED in 2.5.0
helm upgrade fails before anything is applied, citing the postgres block was REMOVED in 2.5.0.Cause: your values still carry postgresHA.postgres.username, postgresHA.postgres.password or postgresHA.postgres.database from version 1.1.0 or earlier.Fix: delete the postgresHA.postgres block and put the same three values under postgres.credentials.* — see Upgrading From 1.1.0 or Earlier.A second release is refused at install as managed by a different release
A second release is refused at install as managed by a different release
cannot be updated because it is being managed by a different release, and nothing is created.Cause: both releases use the same credentialsSecretName. Secret names are org-wide, and the first release owns that secret.Fix: give the second release its own postgresHA.config.credentialsSecretName (or postgres.config.credentialsSecretName). The first release is unaffected.Attachments upload but appear broken in the browser
Attachments upload but appear broken in the browser
storage.type: s3-compatible, uploads succeed but images and files fail to load for agents or visitors.Cause: Chatwoot serves an attachment by redirecting the browser to storage.s3Compatible.endpoint, and that address resolves only inside the GVC.Fix: point storage.s3Compatible.endpoint at an address your users’ browsers can reach, and run helm upgrade.Agent invitations and password-reset emails never arrive
Agent invitations and password-reset emails never arrive
smtp.enabled is false. Chatwoot then falls back to sendmail, which the image does not contain.Fix: configure smtp.* as described in Email and run helm upgrade.Render fails because replicas above 1 require object storage
Render fails because replicas above 1 require object storage
helm install or helm upgrade fails with chatwoot.replicas > 1 requires storage.type 's3' or 's3-compatible'.Cause: local attachments live on a volume set attached to one web replica, so a file uploaded through one replica would be missing from another.Fix: switch to object storage as described in Attachment Storage before raising chatwoot.replicas.Important Notes
- Create the keys secret before installing —
secrets.namemust name an existing dictionary secret holdingSECRET_KEY_BASEand the threeACTIVE_RECORD_ENCRYPTION_*keys; a missing secret wedges the deployment silently. - All four keys are write-once — rotating
SECRET_KEY_BASElogs out every user, and rotating anACTIVE_RECORD_ENCRYPTION_*key makes stored two-factor secrets undecryptable. Back the values up outside Control Plane. - Set
postgres.credentials.passwordandredis.auth.passwordat install time — both ship as placeholders, seed their component on first boot, and are not updated by later value edits. - Complete the onboarding wizard right after install — the first browser session to reach the endpoint creates the super admin, with no email confirmation.
- Restart the web workload after any Redis restart — live updates stop silently until it restarts.
- Choose the database mode before installing — switching
postgresHAandpostgreson a live release points Chatwoot at a different, empty database. - In single-instance mode the database image must carry pgvector — keep
postgres.imageon a pgvector build; the chart refuses a stockpostgres:image. chatwoot.replicasabove1requires object storage — local attachments are per-replica.- In
localstorage mode the worker cannot read attachments — attachment emails and ActiveStorage analyze and purge jobs fail. Use object storage for production. - AWS S3 is keyless only — a cloud account plus a bucket-scoped IAM policy; static keys are accepted only for S3-compatible endpoints.
- With SMTP off, no mail is delivered — configure
smtp.*before inviting agents. - Do not scale the worker or Redis — both are fixed singletons; scale background throughput with
worker.concurrency. - Give each release its own
credentialsSecretName— secret names are org-wide and a second release on the default name is refused at install. - Self-serve signup is managed in the app — turn it on at
/super_adminunder Settings; it is off on a fresh install. - Enterprise features are not included — the
-ceimage omits SSO/SAML, audit logs, agent capacity management, custom branding, SLA policies and Captain AI. - Data survives restarts and upgrades — conversations live in the database volume sets and local attachments in
RELEASE_NAME-chatwoot-storage. Uninstalling deletes those volume sets; your keys secret survives an uninstall.