Docker compose is the easiest way to get started with self-hosted Novu.

Before you begin

You need the following installed in your system:

Quick Start

Get the code

Clone the Novu repo and enter the docker directory locally:

# Get the code
git clone --depth 1 https://github.com/novuhq/novu

# Go to the docker folder
cd novu/docker

# Copy the example env file
cp .env.example ./local/deployment/.env

# Start Novu
docker-compose -f ./local/deployment/docker-compose.yml up

Now visit http://localhost:4200 to start using Novu.

Securing your setup

While we provide you with some example secrets for getting started, you should NEVER deploy your Novu setup using the defaults provided.

Update the .env file with your own secrets.

Required Variables:

  • JWT_SECRET: Used by the API to generate JWT keys.
  • STORE_ENCRYPTION_KEY: Used to encrypt/decrypt the provider credentials. It must be 32 characters long.
  • HOST_NAME: Host name of your installation. This will be the base URL of your installation. For example, if you are deploying to server with ip 35.154.137.80, then you should set this to http://35.154.137.80.

REDIS_CACHE_SERVICE_HOST and REDIS_HOST can have same value for small deployments. For larger deployments, it is recommended to use separate Redis instances for caching and queue management.

Configuration

To keep the setup simple, we made some choices that may not be optimal for production:

  • the database is in the same machine as the servers
  • the storage uses localstack instead of S3

We strongly recommend that you decouple your database before deploying.

Triggering events with custom installation

When self-hosting Novu, in order to trigger an event you must first create a new Novu object and configure it with the proper backendUrl.

import { Novu } from '@novu/node';

const config = {
  backendUrl: '<REPLACE_WITH_BACKEND_URL>',
};

const novu = new Novu('<API_KEY>', config);

await novu.trigger('<WORKFLOW_TRIGGER_IDENTIFIER>', {
  to: {
    subscriberId: '<SUBSCRIBER_ID>',
  },
  payload: {},
});

Pointing IFrame embed to custom installation

When using the IFrame embed to attach the notification center rather than the React component, you need to specify the backendUrl and the socketUrl when initializing the iframe.

<script>
  novu.init(
    '<REPLACE_APPLICATION_ID>',
    {
      unseenBadgeSelector: '#unseen-badge',
      bellSelector: '#notification-bell',
      backendUrl: 'https://api.example.com',
      socketUrl: 'https://ws.example.com',
    },
    {}
  );
</script>

Using React Component with custom installation

See Use your own backend and socket URL.

Caching

We are introducing the first stage of caching in our system to improve performance and efficiency. Caching is turned off by default, but can easily be activated by setting the following environment variables:

  • REDIS_CACHE_SERVICE_HOST
  • REDIS_CACHE_SERVICE_PORT

Currently, we are caching data in the most heavily loaded areas of the system: the widget requests such as feed and unseen count, as well as common DAL requests during the execution of trigger event flow. These are the most heavily used areas of our system, and we hope that by implementing caching in these areas, we can improve performance in the near future.

If you require guidance on setting up a production-scale configuration, official IaaS recommendations, please don’t hesitate to contact our team. They can provide assistance regarding enterprise edition licenses or cloud-prem deployment to meet your specific needs.

NGINX based reverse proxy

This method uses nginxproxy/nginx-proxy and nginxproxy/acme-companion docker image to provide a reverse proxy. SSL certificates are managed using Let’s Encrypt. Fresh certificates will be stored after 90 days for each service.

Steps to configure:-

1

Create EC2 instance

Create a new EC2 instance in preferred AWS region having minimum configuration as below

  • Instance type - t2.medium
  • Storage - 32GB
  • Number of vCPUs - 2

Above configuration is minimum requirement. You can choose higher configuration based on your requirement.

2

Security Group Rules

Add the following rules to the security group of the EC2 instance

  • Inbound rules
    • Type - HTTP, Protocol - TCP, Port Range - 80, Source - Anywhere
    • Type - HTTPS, Protocol - TCP, Port Range - 443, Source - Anywhere
    • (Optional) - Type - SSH, Protocol - TCP, Port Range - 22, Source - Your IP
  • Outbound rules
    • Type - All traffic, Protocol - All, Port Range - All, Destination - Anywhere
3

Public IPv4

Copy the public IPv4 address of the EC2 instance. If using elastic ip, copy the elastic ip.

4

Update DNS Records

In above step, incoming request is allowed only on port 80 and 443. Update the DNS records of the domain to point to the public IPv4 address of the EC2 instance:

  • Go to the DNS provider’s website.
  • Go to DNS settings of domain.
  • Add an A record with the name as novu and value as the above copied IPv4 address.
  • Add an A record with the name as api.novu and value as the above copied IPv4 address.
  • Add an A record with the name as ws.novu and value as the above copied IPv4 address.
  • Add an A record with the name as embed.novu and value as the above copied IPv4 address.
  • Add an A record with the name as widget.novu and value as the above copied IPv4 address.
5

Clone Novu repository

# Get the code
git clone --depth 1 https://github.com/novuhq/novu

# Go to the nginx-based folder
cd novu/docker/local/deployment/nginx-based/

# Copy the example env file
cp .env.example .env
6

Update the environment variables

Update the following environment variables in the .env file:

  • LETSENCRYPT_EMAIL - Email address to register with Let’s Encrypt to remind you about certificate expiry.
  • JWT_SECRET - Used as a secret to verify the JWT token signature
  • STORE_ENCRYPTION_KEY - used to encrypt/decrypt the provider credentials. It must be 32 characters long

Above environment variables are mandatory. Update other environment variables as per your configuration and requirements.

7

Start the docker compose

Make sure current directory is novu/docker/local/deployment/nginx-based/ and run below command:

docker compose up

To run in background

docker compose up -d
8

Access Novu web dashboard

Open the browser and access the Novu web dashboard using the domain name. For example, https://novu.domain.com. Replace domain.com with your domain name.

Reverse-Proxy / Load Balancers

This method is deprecated and will be removed in future versions of Novu. Please use the above method (NGINX based reverse proxy).

To implement a reverse-proxy or load balancer in front of Novu, you need to set the GLOBAL_CONTEXT_PATH for the base path of the application. This is the path that the application will be served from after the domain. For example:

  • company.com/novu This is used to set the base path for the application, and is used to set the base path for the API, web, and websocket connections.

The following environment variables are used to set the context path for each public service that Novu provides: API_CONTEXT_PATH WIDGET_CONTEXT_PATH WS_CONTEXT_PATH WEB_CONTEXT_PATH

These allow you to set the context path for each service independently or dependently of the GLOBAL_CONTEXT_PATH.

For example, if I was using a reverse proxy to serve Novu from company.com/novu, I would set the GLOBAL_CONTEXT_PATH to novu, and then set the API_CONTEXT_PATH to api, the WIDGET_CONTEXT_PATH to widget, the WS_CONTEXT_PATH to ws, and the WEB_CONTEXT_PATH to web.

This would produce the following urls:

  • API: company.com/novu/api
  • WIDGET: company.com/novu/widget
  • WS: company.com/novu/ws
  • WEB: company.com/novu/web

However the Service context path can be used entirely independently of the GLOBAL_CONTEXT_PATH.

For example, if I wanted to expose the api as novu-api, I would set the API_CONTEXT_PATH to novu-api without setting the GLOBAL_CONTEXT_PATH. This would producte the following url:

  • API: company.com/novu-api
These env variables should be present on all services novu provides due to tight coupling.