# Deploy with Docker (/community/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. This guide will walk you through the steps to run all services in single virtual machine using docker compose. This guide uses latest docker images. If you are looking to self host 0.24.x version, checkout [0.24.x docs](https://v0.x-docs.novu.co/self-hosting-novu/deploy-with-docker)

## Prerequisites

You need the following installed in your system:

* [Docker](https://docs.docker.com/engine/install/) and [docker-compose](https://docs.docker.com/compose/install/)
* `curl` and `openssl` (pre-installed on most systems)

## Quick Start

Run the setup script to download the required files, generate secure secrets, and start Novu:

```bash
curl -fsSL https://raw.githubusercontent.com/novuhq/novu/next/docker/community/setup.sh | bash
```

To install into a specific directory, set `NOVU_DIR`:

```bash
curl -fsSL https://raw.githubusercontent.com/novuhq/novu/next/docker/community/setup.sh | NOVU_DIR=~/novu bash
```

The script will:

1. Download `docker-compose.yml` and `.env.example` into the target directory (defaults to `./novu`)
2. Generate cryptographically random values for `JWT_SECRET`, `STORE_ENCRYPTION_KEY`, and `NOVU_SECRET_KEY`
3. Create a `.env` file with the generated secrets
4. Start all Novu services via `docker compose up -d`

Once complete, visit [http://localhost:4000](http://localhost:4000/) to start using Novu.

<Callout type="info">
  If you already have a `.env` file in the target directory, the script will only fill in any missing secret values without overwriting existing configuration.
</Callout>

### Configure Environment

#### VPS Deployment

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

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

Start Novu on your VPS:

```bash
docker compose up -d
```

Access your dashboard at [http://vps-ip-address:4000](http://vps-ip-address:4000/).

## Securing Your Setup

If you used the setup script, secure random secrets were generated automatically for `JWT_SECRET`, `STORE_ENCRYPTION_KEY`, and `NOVU_SECRET_KEY`. If you cloned the repository manually, update the `.env` file with your own secrets before going to production.

### 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:
  * To run in local machine: `http://localhost`
  * To run in VPS: 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 the Inbox Component

This section explains how to integrate the Novu Inbox component into your application when using a self-hosted Novu deployment.

### Install the required packages

```bash
npm install @novu/react react-router-dom
```

### Create the Inbox component

Create a component file (e.g., `notification-center.tsx`) in your project:

```tsx
import React from 'react';
import { Inbox } from '@novu/react';
import { useNavigate } from 'react-router';
 
export function NotificationCenter() {
  const navigate = useNavigate();
 
  return (
    <Inbox
      applicationIdentifier="YOUR_APPLICATION_IDENTIFIER"
      subscriber="YOUR_SUBSCRIBER_ID"
      backendUrl="http://<your-docker-host>:3000" // Docker host address where Novu API is running
      socketUrl="http://<your-docker-host>:3002" // Docker host address where Novu socket is running
      routerPush={(path: string) => navigate(path)}
    />
  );
}
```

### Configure the environment URLs

Adjust the `backendUrl` and `socketUrl` based on your deployment:

### Testing the connection

Once your application is running, you should see the bell icon in your navbar. Clicking it will open the notification inbox UI.

To test notifications, create and trigger a workflow from your self-hosted Novu dashboard, selecting In-App as the channel.

For more information on customizing the Inbox component, refer to the [Inbox documentation](/inbox/overview).

## Initializing the Node SDK

When using a self-hosted Novu deployment with your backend services, you need to configure the Node SDK to connect to your Docker-hosted Novu instance.

### Install the package

```bash
npm install @novu/api
```

### Initialize the SDK

Configure the SDK with your self-hosted backend URL:

```typescript
import { Novu } from '@novu/api';

const novu = new Novu({
  secretKey: "<YOUR_SECRET_KEY_HERE>", // Your Novu API key from the dashboard
  serverURL: "http://<your-docker-host>:3000", // URL of your self-hosted Novu API instance
});
```

### Configure for different environments

Adjust the `backendUrl` based on your deployment:

### Triggering events

Once initialized, you can trigger notification events:

```typescript
await novu.trigger({ 
  workflowId: 'workflowId', 
  to: {
    subscriberId: 'subscriberId',
  },
  payload: {
    // Your custom payload data
    name: 'John Doe',
    orderId: 'ORDER_ID_123',
  },
});
```

For more information on using the Node SDK, refer to the [Server-Side SDKs documentation](/sdks/overview).

### Setting Up local studio and bridge application

#### Setting Up the bridge application

The bridge application is application where workflow definition are written using `@novu/framework`. Here's how to set it up:

```bash
# Initialize the bridge application
npx novu@latest init \
  --secret-key=<secret_key> \
  --api-url=http://localhost:3000

# Install dependencies
npm install

# Start the bridge application
npm run dev
```

Nextjs based bridge application having one test workflow written using `@novu/framework` will be running on `http://localhost:4000`, Go to [http://localhost:4000/api/novu](http://localhost:4000/api/novu) to see status.

#### Setting Up Novu Studio

[Novu Local Studio](/framework/studio) is a development environment that allows you to test and manage your workflows. The setup varies based on your deployment:

1. Running in local machine

if novu is run using above docker compose command in local machine, use below commmand

```bash
npx novu@latest dev -d http://localhost:4000 -p <bridge_application_port>
```

Following actions will occur:

* Novu local studio will be started on default port 2002,
* Novu will generate a tunnel url that will forward the request to bridge application running on `<bridge_application_port>`
* Studio will use `http://localhost:4000` as dashboard url

**Using bridge application url as bridge url**

To use bridge application url as bridge url, use below command:

```bash
npx novu@latest dev -d http://localhost:4000 -p <bridge_application_port> -t http://host.docker.internal:<bridge_application_port>

# example:
npx novu@latest dev -d http://localhost:4000 -p 4000 -t http://host.docker.internal:4000
```

<Callout type="info">
  In Windows OS, there are some additional steps:

  * stop the running docker compose process using `ctrl + c`
  * update the `docker-compose.yml` file and add below config with each service (api, dashboard, worker and ws)

  ```bash
  extra_hosts:
      - "host.docker.internal:host-gateway"
  ```

  * start the docker compose process again using `docker compose up`
  * now you can use `host.docker.internal` as bridge url hostname inplace of `localhost`
</Callout>

2. Running in VPS

```bash
# update the bridge .env file with below variables
NOVU_API_URL=http://<vps-ip-address>:3000

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

Check all [available flags](/framework/studio#novu-cli-flags) with `npx novu dev` command

### Synchronizing Workflows

1. For local deployment:

```bash
npx novu@latest sync \
  --bridge-url <tunnel-url>/api/novu \
  --api-url http://localhost:3000 \
  --secret-key <secret_key>
```

2. For VPS deployment:

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

### 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`.

```tsx
import { Novu } from '@novu/api';  

const novu = new Novu({
  secretKey: '<YOUR_SECRET_KEY_HERE>',
  serverURL: '<REPLACE_WITH_SELF_HOSTED_BACKEND_URL>',
});

await novu.trigger({
  workflowId: 'workflowId',
  to: {
    subscriberId: 'subscriberId',
  },
  payload: {},
});
```

### 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, Dashboard, 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 DASHBOARD\_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 DASHBOARD\_CONTEXT\_PATH to Dashboard.

This would produce the following urls: - API: company.com/novu/api - WIDGET: company.com/novu/widget - WS: company.com/novu/ws - DASHBOARD: company.com/novu/dashboard

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

<Callout type="info">
  These env variables should be present on all services novu provides due to tight coupling.
</Callout>

## FAQs

### Local Tunnel and Self-Hosted Deployments

Novu uses a local tunnel as bridge url. It can be used as bridge url with local studio and for testing purpose in development environment. It should not be used in production environment. It is recommended to use deployed application url as bridge url

#### 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. Checkout `Using bridge application url as bridge url` section to learn more.

#### 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:

```bash
npx novu@latest dev -d http://my-self-hosted-novu-domain.com:my-port
```
