Deploying Novu on a Virtual Machine


Any good product these days must have some way to send notifications to users across different channels. As an engineer, building and managing the infrastructure required can be a time-consuming endeavour, especially if we have complex scenarios and multiple notification channels. In this article, we will be looking at how to deploy Novu, an open-source notification system, on a virtual machine.
Let's get started!
Getting Started
This article is the second part of a short series on deploying Novu, an open-source notification system. The first part of the article can be read here.
This article builds on the first one, so it is necessary to read that first.
When deploying to a VM using just the VM's IP address, the official guide is sufficient.
However, if we need our setup to use domain names or subdomains, we need to make some changes to our .env
files in our Docker folder.
This article focuses on using Nginx as a proxy server on a Linux virtual machine. To properly set up our Novu application, we must also make some changes to our Nginx configuration.
Let's assume that we want to deploy our Novu applications to the following URLs:
Novu Application: http://notifications.example.com
Novu Websocket URL: http://notifications-ws.example.com
We use a different URL for the WebSocket service because the WebSocket URL has to be configured to a root path.
Configuring Nginx to Serve Our Applications
We need different Nginx configurations for the various parts of the app.
One thing to note is to make sure that the root path points to the web app.
Since we can only have one root path per configuration, we need a different configuration that will have a root path that points to the WebSocket service.
Let's create a configuration for our Nginx server in the /etc/nginx/sites-enabled
folder:
> cd /etc/nginx/sites-enabled
# create a new file
> sudo touch novu
# open the file for editing
> sudo vim novu
Next, we edit the content of the config file to proxy for both the Novu app and the API:
server {
server_name notifications.example.com;
access_log /var/log/nginx/access.log;
client_max_body_size 40M;
location / {
proxy_pass http://localhost:4200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*) /$1 break;
}
}
Here we configure our Nginx to proxy all requests to http://notifications.example.com to the container running on http://localhost:4200, which is the Novu application dashboard.
We also configure http://notifications.example.com/api to proxy to http://localhost:3000, which is the Novu API server. The last line rewrite ^/api/(.*) /$1 break;
ensures we strip away the /api/
before forwarding it to localhost:3000.
Since our WebSocket service will be on a different path, let's create a new Nginx config for the WebSocket service:
# create a new file
> sudo touch novu-ws
# open the file for editing
> sudo vim novu-ws
We then add the Nginx config for WebSocket to novu-ws:
server {
server_name notifications-ws.example.com;
access_log /var/log/nginx/access.log;
client_max_body_size 40M;
location / {
proxy_pass http://localhost:3002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Here, we proxy all traffic to http://notifications-ws.example.com to the WebSocket service running on http://localhost:3002. The request is upgraded to a WebSocket request, and a timeout is also set.
Configuring the Novu Application
Once we have Nginx configured, we must configure our Novu application to reference the new URLs.
Let's edit the content of our .env
file in the folder containing our Novu Docker compose file:
> cd novu/docker/community
# open the file for editing
> sudo vim .env
Since we have absolute paths for the Novu Dashboard, API, and WebSocket, we need to update our .env
file to reference these new locations.
First, let's add the absolute URLs as variables:
## code committed for brevity
# Host
HOST_NAME=https://notifications.example.com
API_HOST_NAME=https://notifications.example.com/api
WS_HOST_NAME=https://notifications-ws.example.com
Next, we change the values for API_ROOT_URL
and REACT_APP_WS_URL
:
# Root URL
REACT_APP_WS_URL=$WS_HOST_NAME
# code committed for brevity
API_ROOT_URL=$API_HOST_NAME
We then rebuild our Docker containers and restart nginx:
> sudo docker compose down
# start container
> sudo docker compose up -d
# restart Nginx
> sudo systemctl restart nginx
The Novu dashboard should be available on http://notifications.example.com.
The API URL and Websocket should be available on http://notifications.example.com/api and http://notifications-ws.example.com, respectively.
We can secure our application by configuring SSL for our application using this LetsEcrypt guide.
Conclusion
In the second part of our series, we focus on configuring our Novu application when hosting it on a virtual machine.
Subscribe to my newsletter
Read articles from Bayo A directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Bayo A
Bayo A
Software engineer with a passion for learning and trying out new tech.