Deploy Chatwoot on Vultr Kubernetes Engine using Helm Charts

Updated on July 25, 2024
Deploy Chatwoot on Vultr Kubernetes Engine using Helm Charts header image

Introduction

Chatwoot is an open-source customer engagement platform designed to improve business processes. You can integrate the application with multiple communication channels such as email, website live chat, and social media applications to manage all customer communications in a single dashboard.

This guide explains how to deploy Chatwoot on a Vultr Kubernetes Engine (VKE) cluster using Helm Charts. To extend the Chatwoot functionalities, you will integrate Vultr Object Storage, a Vultr Managed Database for PostgreSQL, and a Vultr Managed Database for Caching to run the application in your cluster.

Prerequisites

Before you begin:

Set Up the Chatwoot Database

  1. Log in to your Vultr Managed Database for PostgreSQL. Replace vultradmin, postgres-334h.vultrdb.com, and 5432 with your actual database details.

    console
    $ psql -h postgres-334h.vultrdb.com -p 5432 -U vultradmin
    

    You can find your Vultr Database for PostgreSQL details in the connection details section on your cluster control panel.

    Get PostgreSQL URL

  2. Create a new Chatwoot database.

    sql
    defaultdb=> CREATE DATABASE chatwoot;
    
  3. Create a new database user. For example exampleuser with a strong password.

    sql
    defaultdb=> CREATE USER exampleuser WITH PASSWORD 'strong-password';
    
  4. Grant the user full privileges to the Chatwoot database.

    sql
    defaultdb=> GRANT ALL PRIVILEGES ON DATABASE chatwoot TO exampleuser;
    
  5. Exit the PostgreSQL database console.

    sql
    defaultdb=> \q
    

Set Up the VKE Cluster

To deploy Chatwoot to your cluster, install the Nginx Ingress controller to handle incoming requests, and Cert-Manager to handle the certificate issuance process to your configured domain name. Set up the project directory, download the default Chatwoot configuration file, and install all necessary packages to your cluster as described in the steps below.

  1. Create a new chatwoot-app directory.

    console
    $ mkdir chatwoot-app
    
  2. Switch to the directory.

    console
    $ cd chatwoot-app
    
  3. Download the default Chatwoot Helm configuration values file.

    console
    $ wget https://raw.githubusercontent.com/chatwoot/charts/main/charts/chatwoot/values.yaml
    

    The values.yaml file contains default configurations and environment variables you should modify before deploying Chatwoot in a cluster.

  4. Using Helm, add the Chatwoot repository to your server.

    console
    $ helm repo add chatwoot https://chatwoot.github.io/charts
    
  5. Add the Nginx Ingress Controller repository.

    console
    $ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    
  6. Add the Cert-Manager repository.

    console
    $ helm repo add jetstack https://charts.jetstack.io
    
  7. Update your Helm Repositories to fetch the latest Chart information.

    console
    $ helm repo update
    
  8. Install the Nginx Ingress Controller to your cluster.

    console
    $ helm install ingress-nginx ingress-nginx/ingress-nginx
    
  9. Install Cert-Manager to handle the SSL certificate operations.

    console
    $ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
    
  10. When successful, view the cluster services and verify the Load Balancer external IP address assigned to your Ingress Controller.

    console
    $ kubectl get services ingress-nginx-controller
    

    Output:

    NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
    ingress-nginx-controller   LoadBalancer   10.96.132.148   192.168.10.1   80:30827/TCP,443:30274/TCP   6m9s

    If the external IP is in <pending> state, wait for at least 3 minutes and view the cluster services again.

  11. Access your domain DNS records and create a new A record that points to your load balancer external IP address.

Modify the Chatwoot Configuration Values

  1. Using the OpenSSL utility, generate a random secret key.

    console
    $ openssl rand -hex 32
    

    Copy the random key generated in your output like the one below:

    632830c6d5a23e46d73bdc362dd05d34c85d969b4ab0f5f675e8ea6d7dfaa335
  2. Using a text editor such as Nano, open the values.yaml file.

    console
    $ nano values.yaml
    
  3. Find the SECRET_KEY_BASE declaration in the env section.

    yaml
    SECRET_KEY_BASE: replace_with_your_super_duper_secret_key_base
    

    Replace the default value with the string key you generated earlier. For example:

    yaml
    SECRET_KEY_BASE: 632830c6d5a23e46d73bdc362dd05d34c85d969b4ab0f5f675e8ea6d7dfaa335
    

    Save and close the file.

Configure Vultr Object Storage

Follow the steps in this section to add Vultr Block Storage to your Chatwoot configuration to store chat attachments within the application.

  1. Edit the values.yaml file.

    console
    $ nano values.yaml
    
  2. Find the ACTIVE_STORAGE_SERVICE declaration in the env: section, and change the value from local to s3_compatible.

    yaml
    ACTIVE_STORAGE_SERVICE: s3_compatible
    
  3. Scroll to the end of the file, and add the following declarations.Replace the example values with your actual Vultr Object Storage details:

    yaml
    STORAGE_BUCKET_NAME: chatwoot-prod
    STORAGE_ACCESS_KEY_ID: vultr-object-storage-access-key
    STORAGE_SECRET_ACCESS_KEY: vultr-object-storage-secret-key
    STORAGE_REGION: ewr1
    STORAGE_ENDPOINT: https://ewr1.vultrobjects.com
    

    Save and close the file.

    Below is what each of the above YAML declarations represent:

    • STORAGE_BUCKET_NAME: Your Vultr Object Storage bucket name
    • STORAGE_ACCESS_KEY_ID: Your Vultr Object Storage Access Key
    • STORAGE_SECRET_ACCESS_KEY: The Vultr Object Storage Secret Key
    • STORAGE_REGION: Defines your Vultr Object Storage deployment region. ewr1 represents the Vultr New Jersey region. You can identify your Object Storage region depending on your host URL. For example, the ewr1 region uses ewr1.vultrobjects.com
    • STORAGE_ENDPOINT: Sets your Vultr Object Storage Hostname with secure access over HTTPS

    You can find your Vultr Object Storage details in your instance Overview tab.

    Vultr Object Storage Credentials

Set Up the Vultr Managed Database for PostgreSQL Connection

  1. Edit the values.yaml file.

    console
    $ nano values.yaml
    
  2. Find the following postgresql section:

    yaml
    postgresql:
    enabled: true
    nameOverride: chatwoot-postgresql
    auth:
      username: postgres
      postgresPassword: postgres
      database: chatwoot_production
      # when existingSecret is defined auth.password, auth.PostgressPassword
      # is ignored.
      # existingSecret: secret-name
      # secretKeys:
      #   adminPasswordKey: postgres-password
      #   replicationPasswordKey: replication-password
      # The following variables are only used when internal PG is disabled
      # postgresqlHost: postgres
      # postgresqlPort: 5432
    
  3. Set the enabled value to false, and replace the default values with your actual Vultr Managed Database for PostgreSQL details similar to the ones below:

    yaml
    postgresql:
      enabled: false
      nameOverride: chatwoot-postgresql
      auth:
        username: exampleuser
        postgresPassword: strong-password
        database: chatwoot
        # when existingSecret is defined auth.password, auth.PostgressPassword
        # is ignored.
        # existingSecret: secret-name
        # secretKeys:
        #   adminPasswordKey: postgres-password
        #   replicationPasswordKey: replication-password
      # The following variables are only used when internal PG is disabled
      postgresqlHost: postgres-334h.vultrdb.com
      postgresqlPort: 5432
    

    Save and close the file.

    Below is what the PostgreSQL section declarations represent:

    • enabled: Sets the database type Chatwoot should use. When set to false, Chatwoot uses your Vultr Managed Database for PostgreSQL instead of deploying a cluster PostgreSQL pod
    • username: Defines your PostgreSQL database username
    • postgresPassword: Defines the PostgreSQL user password to use for connecting to the database
    • database: Sets the PostgreSQL Chatwoot database
    • postgresqlHost: Sets the Vultr Managed Database for PostgreSQL host URL to connect the Chatwoot database
    • postgresqlPort: Sets your PostgreSQL database port to connect using the database host URL

    You can find your Vultr Managed Database for PostgreSQL details in your cluster control panel connection details tab.

    PostgreSQL Connection Details

Enable the Vultr Managed Database for Caching Connection to Handle Queues and Cache Storage

  1. Edit the values.yaml file.

    console
    $ nano values.yaml
    
  2. Find the following redis section.

    yaml
    redis:
      enabled: true
      nameOverride: chatwoot-redis
      auth:
        password: redis
        # when defined the password field is ignored
        #    existingSecret: secret-name
        #    existingSecretPasswordKey: ""
      # The following variables are only used when internal Redis is disabled
      # host: redis
      # Just omit the password field if your redis cluster doesn't use password
      # password: redis
      # port: 6379
      master:
        persistence:
          enabled: true
          # If change pvc size redis.master.persistence.size: 20Gi
      replica:
        replicaCount: 1
    
  3. Set the enabled: value to false, and replace the default values with your actual Vultr Managed Database for Caching details.

    yaml
    redis:
      enabled: false
      nameOverride: chatwoot-redis
      auth:
        password: redis
      # The following variables are only used when internal Redis is disabled
      host: [VULTR_REDIS_HOSTNAME]
      # Just omit the password field if your redis cluster doesn't use password
      password: [VULTR_REDIS_PASSWORD]
      port: [VULTR_REDIS_PORT]
      master:
        persistence:
          enabled: true
      replica:
        replicaCount: 1
    

    Below is what the database values represent:

    • enabled: Sets the Chatwoot Redis® database server location. When set to false, Chatwoot uses the Vultr Managed Database values and disables the internal cluster Redis® pods
    • host: Defines your Vultr Managed Database for Caching host URL.
    • password: Sets your Vultr Managed Database for Caching password. Iignore the password declaration in the auth section because it's only used with the cluster Redis® installation.
    • port: Sets your Vultr Managed Database for Caching port to connect to the database host.

    You can find your Vultr Managed Database for Caching host URL, port, and password in the Connection Details section within your cluster control panel Overview tab.

    Redis® connection details

  4. Scroll to the env section and set the REDIS_TLS value to true.

    yaml
    REDIS_TLS: true
    

    Save and close the file.

Add Nginx Ingress Configurations to the Chatwoot Helm Configuration File

To correctly route and forward incoming external traffic to your Chatwoot application, modify the services and ingress sections as described in the steps below.

  1. Edit the values.yaml.

    console
    $ nano values.yaml
    
  2. Find the following services parameter.

    yaml
    services:
      name: chatwoot
      internalPort: 3000
      targetPort: 3000
      type: LoadBalancer
      annotations: {}
    

    Change the type declaration value from LoadBalancer to ClusterIP:

    yaml
    type: ClusterIP
    

    The modified services section should look like the one below:

    yaml
    services:
      name: chatwoot
      internalPort: 3000
      targetPort: 3000
      type: ClusterIP
      annotations: {}
    
  3. Find the following ingress section.

    yaml
    ingress:
      enabled: false
      # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
      # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
      # ingressClassName: nginx
      annotations: {}
        # kubernetes.io/ingress.class: nginx
        # kubernetes.io/tls-acme: "true"
      hosts:
        - host: ""
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: chatwoot
                  port:
                    number: 3000
      tls: []
      #  - secretName: chart-example-tls
      #    hosts:
      #      - chart-example.local
    

    Change the enabled value from false to true.

    yaml
    enabled: true
    

    Remove the # comment value on the ingressClassName declaration to activate the Nginx Ingress Controller.

    yaml
    ingressClassName: nginx
    

    Within the annotations section, uncomment the kubernetes.io/ingress.class annotation

    yaml
    annotations:
        kubernetes.io/ingress.class: nginx
    

    Scroll to the hosts section and replace the host value with your Chatwoot domain name. Replace chatwoot.example.com with your actual domain name that points to the Ingress Controller Load Balancer External IP Address.

    yaml
    hosts:
        - host: chatwoot.example.com
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: chatwoot
                  port:
                    number: 3000
    

    Save and close the file.

    The modified ingress section should look like the one below:

    yaml
    ingress:
      enabled: true
      # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
      # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
      ingressClassName: nginx
      annotations:
      kubernetes.io/ingress.class: nginx
        # kubernetes.io/tls-acme: "true"
      hosts:
        - host: chatwoot.example.com
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: chatwoot
                  port:
                    number: 3000
      tls: []
      #  - secretName: chart-example-tls
      #    hosts:
      #      - chart-example.local
    
  4. Using Helm, install Chatwoot with the values.yaml configurations to your Vultr Kubernetes Engine cluster.

    console
    $ helm install chatwoot chatwoot/chatwoot -f values.yaml
    

    When successful, your output should look like the one below:

    NAME: chatwoot
    LAST DEPLOYED: Mon Oct 16 16:05:24 2023
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    NOTES:
    Thank you for installing chatwoot.
    
        Your release is named chatwoot.
    
        To learn more about the release, try:
    
            $ helm status chatwoot
            $ helm get all chatwoot
    
        NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        You can watch the status by running
        'kubectl get svc -w chatwoot'
    
        export SERVICE_IP=$(kubectl get svc --namespace default chatwoot -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
        echo http://$SERVICE_IP:3000
    • The deployment should take about 10 minutes to complete depending on your cluster node type.

    • If you receive the following deployment error:

      Error: INSTALLATION FAILED: failed post-install: timed out waiting for the condition

    Verify and make changes to your Vultr Managed Database for PostgreSQL details in the values.yaml file.

  5. View your cluster pods and verify that all Chatwoot pods are running.

    console
    $ kubectl get pods
    

    Output:

    NAME                                        READY   STATUS    RESTARTS   AGE
    chatwoot-web-666b5bdb69-vp5bd               1/1     Running   0          2m55s
    chatwoot-worker-ffccccd4-4j8l4              1/1     Running   0          2m55s
    chatwoot-worker-ffccccd4-n6272              1/1     Running   0          2m55s
    ingress-nginx-controller-84bd4cb7ff-h8ght   1/1     Running   0          4m54s

    Verify that all pods are ready and running in your cluster to use your Chatwoot application.

Generate Let's Encrypt SSL Certificates using Cert-Manager

  1. Create a new Let's Encrypt issuer resource file. For example chatwoot-issuer to use as Let's Encrypt Issuer.

    console
    $ nano production-issuer.yaml
    
  2. Add the following configurations to the file. Replace admin@example.com with your actual email address.

    yaml
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: chatwoot-prod
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: admin@example.com
        privateKeySecretRef:
          name: chatwoot-prod
        solvers:
          - http01:
              ingress:
                class: nginx
    

    Save and close the file.

  3. Deploy the issuer to your cluster.

    console
    $ kubectl apply -f production-issuer.yaml
    
  4. View the cluster issuers and verify that the new resource is available.

    console
    $ kubectl get issuer
    

    Output:

    NAME               READY   AGE
    chatwoot-prod   True    39s
  5. To use the new Certificate Issuer, edit your values.yaml file.

    console
    $ nano values.yaml
    
  6. Find the ingress section and uncomment the tls declaration values.

    yaml
    tls:
    - secretName: chart-example-tls
      hosts:
        - chart-example.local
    

    Replace the default values with your actual details. For example, replace chart-example.local with your actual Chatwoot domain name, and chart-example-tls with your desired secret name.

    yaml
    tls:
    - secretName: chatwoot-cert-secret
      hosts:
        - chartwoot.example.com
    
  7. Add the cert-manager issuer annotation to your annotations section to use the new tls section values.

    yaml
    cert-manager.io/issuer: letsencrypt-prod
    

    Save and close the file.

    Your modified Ingress section should look like the one below:

    yaml
    ingress:
     enabled: true
     # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
     # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
     ingressClassName: nginx
     annotations:
     kubernetes.io/ingress.class: nginx
     cert-manager.io/issuer: letsencrypt-prod 
       # kubernetes.io/tls-acme: "true"
     hosts:
       - host: newchat.onlustech.com
         paths:
           - path: /
             pathType: Prefix
             backend:
               service:
                 name: chatwoot
                 port:
                   number: 3000
    tls:
    - secretName: chartwoot-cert-secret
      hosts:
        - chartwoot.example.com
    
  8. Upgrade the Chatwoot application with your new values.yaml configuration.

    console
    $ helm upgrade chatwoot chatwoot/chatwoot -f values.yaml
    

    When succesful, your output should look like the one below:

    Release "chatwoot" has been upgraded. Happy Helming!
    NAME: chatwoot
    LAST DEPLOYED: Mon Oct 16 16:25:12 2023
    NAMESPACE: default
    STATUS: deployed
    REVISION: 2
    NOTES:
    Thank you for installing chatwoot.
    
        Your release is named chatwoot.
    
        To learn more about the release, try:
    
          $ helm status chatwoot
          $ helm get all chatwoot
    
        NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        You can watch the status by running
        'kubectl get svc -w chatwoot'
    
        export SERVICE_IP=$(kubectl get svc --namespace default chatwoot -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
        echo http://$SERVICE_IP:3000
  9. Verify that all pods are running.

    console
    $ kubectl get pods
    

    Output:

    NAME                                            READY   STATUS    RESTARTS   AGE
    pod/cert-manager-55657857dd-lp9dh               1/1     Running   0          6m1s
    pod/cert-manager-cainjector-7b5b5d4786-8wqnb    1/1     Running   0          6m1s
    pod/cert-manager-webhook-55fb5c9c88-d5wlq       1/1     Running   0          6m1s
    pod/chatwoot-web-666b5bdb69-vp5bd               1/1     Running   0          16m
    pod/chatwoot-worker-ffccccd4-4j8l4              1/1     Running   0          16m
    pod/chatwoot-worker-ffccccd4-n6272              1/1     Running   0          16m
    pod/ingress-nginx-controller-84bd4cb7ff-h8ght   1/1     Running   0          18m

Test: Access your Chatwoot Application

  1. Using a web browser such as Firefox, access your Chatwoot domain name.

    https://chatwoot.example.com
  2. Verify that the Chatwoot onboarding page displays in your browser.

    Chatwoot onboarding page

  3. Verify that your domain name uses a valid SSL certificate.

    Chatwoot valid cluster SSL certificate

  4. Fill in the Name, Company Name, Email and Password fields with your details. Then, click Finish Setup to save the new administrator details.

    The Chatwoot onboarding page

  5. Login to Chatwoot using your administrator email and password to access the application dashboard.

    Chatwoot application dashboard

Conclusion

You have deployed a Chatwoot instance to a Vultr Kubernetes Engine (VKE) cluster using Helm. In addition, you integrated a Vultr Managed Database for PostgreSQL, Vultr Object Storage and a Vultr Managed Database for Caching to extend the Chatwoot production environment functionalities. For more information about Chatwoot, visit the official documentation.

More Information