Self hosting novu

Deploy with Docker

Learn how to deploy Novu with Docker

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

Before you begin

You need the following installed in your system:

In above loom video local/deployment directory is used. Now it has been moved to docker/community. Follow below mentioned steps.

Quick Start

Get the code

Clone the Novu repo and enter the docker directory:

# Get the code
git clone --depth 1 https://github.com/novuhq/novu
 
# Go to the docker community folder
cd novu/docker/community
 
# Copy the example env file
cp .env.example .env

Configure Environment

Local Development

For local development, you can use the default configuration. Start Novu with:

docker-compose -f docker-compose.yml up

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

VPS Deployment

When deploying to a VPS, update your .env file with your server's information:

# Replace <vps-ip-address> with your VPS IP address
HOST_NAME=http://<vps-ip-address>

Start Novu on your VPS:

docker-compose -f docker-compose.yml up

Access your dashboard at http://vps-ip-address:4200.

Securing your setup

While we provide 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:
    • For local development: http://localhost
    • For VPS deployment: Your server's IP address (e.g., http://<vps-ip-address>) or domain name
  • 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.

Setting Up Novu Studio and Bridge

Setting Up Novu Studio

Novu Studio is a development environment that allows you to test and manage your notifications. The setup varies based on your deployment:

For Local Development
npx novu@latest dev
For VPS Deployment
# Start Novu Studio with your VPS dashboard URL and bridge application URL
npx novu@latest dev -d http://<vps-ip-address>:4200 -o http://<novu-bridge-ip>:4000

Setting Up the Novu Bridge

The Novu Bridge is used to connect your application with Novu. Here's how to set it up:

# Initialize the bridge
npx novu@latest init \
  --secret-key=<secret> \
  --api-url=http://<vps-ip-address>:3000
 
# Start the bridge
npm run dev

Synchronizing Workflows

For VPS deployment:

npx novu@latest sync \
  --bridge-url http://<novu-bridge-ip>:3000/api/novu \
  --api-url http://<vps-ip-address>:3000 \
  --secret-key <secret>

VPS Security Considerations

When deploying to a VPS, consider these additional security measures:

  1. Use a firewall to restrict access to only necessary ports
  2. Set up SSL/TLS certificates for HTTPS access
  3. Regularly update your Docker images and host system
  4. Use strong, unique secrets in your .env file
  5. Consider using a reverse proxy like Nginx for additional security layers

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.

Reverse-Proxy / Load Balancers

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.

FAQs

Local Tunnel and Self-Hosted Deployments

Novu uses a local tunnel to connect to Local Studio during development. Local tunnel support is not included as part of the Novu Docker images. This is typically unnecessary for many users, depending on how their environment is structured.

When is Local Tunnel Not Required?

If the customer's application and the self-hosted Novu deployment are within the same network, there is no need for a local tunnel. In this case, the application can communicate directly with Novu through the internal network.

When is Local Tunnel Required?

If the application and Novu deployment reside on different networks, you can still interact with your self-hosted Novu instance using the Novu CLI. The CLI allows you to specify the Dashboard URL and Bridge Endpoint Origin to enable communication across networks via the Novu Cloud Local Tunnel.

For example, you can use the following command:

npx novu@latest dev -d http://my-self-hosted-novu-domain.com:my-port -o http://my-app-running-novu-domain.com