How to deploy a Next.js project on Ubuntu with NGINX

How to deploy a Next.js project on Ubuntu with NGINX, explained in simple steps.

15 min read

views

In this article, you will learn how to deploy your Next.js application on an Ubuntu VPS with NGINX. We will also cover how to install Node.js and how to set up a firewall.

Requirements

It's important that you have the following requirements before you start:

  • Your Next.js project
  • Your domain
  • VPS with Ubuntu 20.04
  • Minimal experience in the terminal

Prepare VPS for deployment

Before we can start deploying our Next.js project, we must first install some dependencies on our VPS. This includes updating the VPS, installing Node.js and NGINX and setting up the firewall.

Updating the VPS

Firstly, let's update the VPS to make sure we have the latest packages installed. We can do this by running the following command:

sudo apt update && sudo apt upgrade -y
bash

Installing Node.js

Secondly, we must install Node.js, which is required to run our Next.js project. We will be using v18 for this guide. There are several methods of installing Node.js, and we will be installing from Nodesource since I find it the easiest method.

To install Node.js, we must first download and run the Nodesource setup script:

curl -sL https://deb.nodesource.com/setup_18.x | sudo bash
bash

This will also automatically install npm for us, which is the package manager for Node.js. To verify that Node.js and npm are installed, we can run the following command:

node -v # 18.x.x
npm -v # 9.x.x
bash

NGINX

NGINX is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache.

NGINX will allow us to serve our Next.js project on our domain. For now, we will only install NGINX, and we will configure it later.

To install NGINX, we can run the following command:

sudo apt install nginx -y
bash

Firewall

We must set up a firewall to only allow certain ports on our VPS, in this guide we will use the built-in ufw command. This will prevent unwanted access to our VPS. We will only allow the following ports:

  • SSH: 22
  • HTTP: 80
  • HTTPS: 443
sudo ufw allow ssh # 22
sudo ufw allow "Nginx Full" # 80 and 443
bash

To verify this worked, you can run the following command:

sudo ufw status
bash

Firewall disabled or not installed?

Learn more how to install and enable ufw 👉

To install ufw, run the following command:

sudo apt install ufw -y
bash

To enable ufw, run the following command:

sudo ufw enable
bash

Next.js project setup

Now that we have our VPS ready to rock and roll, we will have to install our Next.js project on the VPS. We will be using git to clone our project from GitHub onto our VPS.

To clone our Next.js project, we can run the following command:

# replace this URL with your repo
git clone https://github.com/casperiv0/nextjs-ts-eslint-template.git
bash

Don't have git installed?

If you don't have git installed on the VPS, learn how to install it 👉
sudo apt install git -y
bash

Once the project is cloned, we must change the directory to the project folder:

cd nextjs-ts-eslint-template
bash

Now we can install the dependencies:

# Replace this with your package manager of choice
npm install
bash

Once all the dependencies are installed, we can build our Next.js application so it is ready to be deployed:

npm run build
bash

Now we can start the project in the background using pm2. This will start the project on port 3000 in the background. You can view any logs by running pm2 logs.

# `run start` is the start command that will be executed.
pm2 start npm --name my-project -- run start
bash
If you don't have pm2 installed yet, see the following command 👉
sudo npm install --global pm2
sh

Learn more about pm2 here.

NGINX Configuration

Now that we have our Next.js project running, we can configure NGINX to serve our project.

NGINX proxy setup

Start by opening the following file with a text-editor: /etc/nginx/sites-available/default. I will use nano for this.

nano /etc/nginx/sites-available/default
bash

You might already see some configurations, you can safely remove this.

We can now start editing this file and add our own server block.

/etc/nginx/sites-available/default
server {
  # the name of your domain, www is optional.
  server_name my-domain.com www.my-domain.com;
 
  location / {
    # this must stay localhost. The port must be the same as your Next.js project
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
 
  # simple headers
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
  add_header X-XSS-Protection          "1; mode=block" always;
  add_header X-Frame-Options DENY always;
 
  # this will serve the project on port 80
  listen 80;
}
nginx

Once done editing, save and exit the editor and verify the config file with the following command:

nginx -t
bash

You may have noticed that we are serving the project on port 80. This is fine for now, since we haven't installed our certificates yet. If you do not need a secure site, you can skip to #final-deployment-steps! Otherwise, continue reading on how to install certificates with Certbot.

Installing certificates with Certbot

Certbot can be installed in many ways and on many machines with different configurations, therefore please follow Certbot's installation guide.

After following Certbot's instructions, you should verify if it changed the NGINX config, open the config file and see changes made.

nano /etc/nginx/sites-available/default
bash

Now you should see that the server block will serve the project on port 443 (HTTPS)!

Final Deployment steps

As our last step, we must restart NGINX with this simple command:

sudo systemctl reload nginx
bash

Now verify that all is running, head over to your domain and see the project in action 🎉!

The end

That's it! You've successfully set up NGINX on Ubuntu and deployed a Next.js project to it