How to Deploy Next.js on Linux

Published:
October 6, 2026

Next.js helps developers build fast, scalable, and interactive web applications with features that improve performance, SEO, and the overall user experience. It supports efficient development and flexible deployment across different hosting environments, including Linux servers.

This tutorial explains how to deploy a Next.js application on Ubuntu using three methods: PM2 with Nginx, Docker with Docker Compose, and systemd.

How to deploy Next.js on Linux - a tutorial.

Prerequisites

Step 1: Install Node.js

Next.js requires Node.js to build and run the application. Install Node.js 24 from the NodeSource repository to use a current Node.js release and make the runtime available system-wide. A system-wide installation also lets services such as systemd access the Node.js executable without extra environment configuration. Follow the steps below:

1. Update the package index:

sudo apt update

2. Install the packages required to download the NodeSource setup script and work with the application:

sudo apt install -y curl git

3. Add the NodeSource repository for Node.js 24:

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -

4. Install Node.js and npm:

sudo apt install -y nodejs

5. Verify the installed versions:

node -v
npm -v
Checking Node and NPM program versions.

6. Verify the installation paths:

which node
which npm
Checking Node and NPM installation paths on Ubuntu.

The commands should return the paths to the installed Node.js and npm executables.

Step 2: Create and Build the Next.js Application

After installing Node.js, create a Next.js application that serves as the deployment target for all three methods. Building the application before deployment verifies that the project and its dependencies work correctly in a production environment. Follow the steps below:

1. Create a new application:

npx create-next-app@latest nextjs-demo

When prompted, type y and press Enter to confirm the installation, and press Enter again when prompted to use the recommended Next.js configuration.

You can also choose to customize settings to configure the application to your needs.

Build Next.js app.

2. Change to the application directory:

cd ~/nextjs-demo

3. Create an optimized production build:

npm run build
Create Next.js optimized production build.

4. Start the application in production mode:

npm start
Starting the Next.js app.

5. Verify that the application responds on port 3000:

curl http://localhost:3000

The command returns the HTML generated by the Next.js application. You can also check if it works by visiting http://localhost:3000 in your web browser:

Checking if the Next.js app is running.

Stop the application with Ctrl+C before continuing.

Option 1: Deploy Next.js with PM2 and Nginx

PM2 runs the Next.js application as a managed background process, while Nginx acts as a reverse proxy for incoming HTTP requests. This setup provides process management and a dedicated web server that can handle client requests before forwarding them to the Next.js application.

Follow the steps below to deploy Next.js using PM2 and Nginx:

Step 1: Install PM2

PM2 manages the Next.js process independently from the terminal session and can restart the application when necessary. Installing it globally makes the pm2 command available system-wide.

Install PM2 with:

sudo npm install -g pm2
Installing pm2 on Ubuntu.

Verify the installation:

pm2 --version

Step 2: Build and start the application with PM2

PM2 should run the production version of the Next.js application rather than the development server. Create a production build and then use PM2 to manage the npm start process.

Create the production build:

npm run build

Start the application with PM2:

pm2 start npm --name nextjs-app -- start

Check the PM2 process status:

pm2 status
Checking pm2 status on Ubuntu.

Verify that the application responds on its local port:

curl http://localhost:3000

If it works, the output returns the HTML generated by Next.js.

Save the current PM2 process list so PM2 can restore the application after a system reboot:

pm2 save

Step 3: Install and configure Nginx

Nginx provides a reverse proxy in front of the Next.js application. Instead of exposing the application directly on port 3000, Nginx receives HTTP requests on port 80 and forwards them to the Next.js process.

Follow the steps below:

1. Install Nginx:

sudo apt install -y nginx

2. Check the service status:

sudo systemctl status nginx
Checking Nginx service status.

3. Create a dedicated Nginx configuration for the application:

sudo nano /etc/nginx/sites-available/nextjs

Add the following configuration:

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://127.0.0.1:3000;

        proxy_http_version 1.1;

        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;
    }
}

Save and exit the file.

4. Enable the configuration:

sudo ln -s /etc/nginx/sites-available/nextjs /etc/nginx/sites-enabled/nextjs

5. Remove the default Nginx site:

sudo rm /etc/nginx/sites-enabled/default

6. Test the configuration before applying the changes:

sudo nginx -t
Testing the Nginx configuration.

7. Restart Nginx to apply the changes:

sudo systemctl restart nginx

Step 4: Verify the PM2 and Nginx Deployment

The final verification confirms that Nginx can receive requests and forward them to the Next.js application managed by PM2. A successful response from port 80 confirms that the reverse proxy is working.

Send a request through Nginx:

curl -I http://localhost

A successful deployment returns an HTTP 200 OK response:

Verifying Nginx and pm2 deployment.

Option 2: Deploy Next.js with Docker and Docker Compose

Docker packages the Next.js application and its dependencies into an isolated container, while Docker Compose defines and manages the container configuration. This approach provides a consistent runtime environment and makes the application easier to move between systems.

Step 1: Verify the Docker Installation

Docker and Docker Compose must be available before you can containerize the Next.js application. Verify both installations before creating the container configuration.

Check the Docker version:

docker --version

Check the Docker Compose version:

docker compose version

Follow our guide to install Docker if it isn't available on your system.

Step 2: Create the Docker configuration

The Dockerfile defines how Docker builds the Next.js application image, including the Node.js runtime, dependencies, and production build. A .dockerignore file prevents unnecessary project files from being copied into the image. Follow the steps below to create the Docker configuration:

1. Change to the application directory:

cd ~/nextjs-demo

2. Create the Dockerfile:

nano Dockerfile

3. Add the following:

FROM node:24-alpine

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]

4. Create the .dockerignore file:

nano .dockerignore

5. Add:

node_modules
.next
.git
.gitignore
Dockerfile
compose.yaml
npm-debug.log

Save the file and exit.

Step 3: Configure Docker Compose

Docker Compose defines how to build and run the Next.js container. The configuration maps host port 3000 to container port 3000 and restarts the container automatically unless you stop it explicitly.

Follow the steps below:

1. Create the Compose file:

nano compose.yaml

2. Paste the following lines:

services:
  nextjs:
    build: .
    container_name: nextjs-app
    ports:
      - "3000:3000"
    restart: unless-stopped

Step 4: Build and Start the Next.js Container

Build the Docker image and start the container in detached mode. Docker Compose uses the Dockerfile to create the image and then starts the Next.js application inside the container.

docker compose up -d --build

Check the service status with:

docker compose ps
Checking the Next.js container status.

Step 5: Verify Docker deployment

Verify that the containerized Next.js application responds on port 3000. Checking the listening port also confirms that Docker correctly publishes the application port on the host.

Send a request to the application:

curl -I http://localhost:3000

A successful deployment returns an HTTP 200 OK response.

Option 3: Deploy Next.js Using systemd

systemd can run the Next.js application as a native Linux service without requiring a separate process manager or container runtime. Creating a dedicated service user and application directory also provides a controlled environment for running the application.

Follow the steps below to deploy Next.js with systemd.

Step 1: Create a Dedicated System User

Running the application under a dedicated system user limits the permissions available to the Next.js process and avoids running the application as root.

Create the nextjs system user and group:

sudo adduser --system --group nextjs

Verify the user:

id nextjs
Verifying Next.js user.

The output shows that the nextjs user has UID 112, belongs to group nextjs with GID 115, and has no additional group memberships.

Step 2: Prepare the Application Directory

The application needs a dedicated location outside the user's home directory so systemd can manage it as a system service. Copy the application files to /var/www/nextjs and assign ownership to the dedicated service user.

1. First, create the application directory:

sudo mkdir -p /var/www/nextjs

2. Copy the Next.js application files to the directory we created in the previous step:

sudo cp -r . /var/www/nextjs/

3. Assign ownership to the nextjs user:

sudo chown -R nextjs:nextjs /var/www/nextjs

Step 3: Create the systemd Service

The systemd service definition specifies which user runs the application, where the application is located, which command starts it, and how systemd handles the process. The service uses the production environment and port 3000 defined for the Next.js application.

Create the service file:

sudo nano /etc/systemd/system/nextjs.service

Paste the following lines into the file:

[Unit]
Description=Next.js Application
After=network.target

[Service]
Type=simple
User=nextjs
Group=nextjs
WorkingDirectory=/var/www/nextjs
ExecStart=/usr/bin/npm start
Restart=on-failure
Environment=NODE_ENV=production
Environment=PORT=3000

[Install]
WantedBy=multi-user.target

Save the file and exit the editor.

Step 4: Enable and Start the Next.js Service

After creating a new systemd service, reload the systemd configuration so it recognizes the service definition. Enable the service to start automatically during system boot, then start it immediately.

Reload systemd with:

sudo systemctl daemon-reload

Enable the service:

sudo systemctl enable nextjs

Start the service:

sudo systemctl start nextjs

Check the service status:

sudo systemctl status nextjs
Checking the Next.js service status.

A successful service shows active (running) in the status output.

Step 5: Verify the systemd deployment

Verify that the systemd-managed application responds on port 3000. This confirms that systemd successfully started the Next.js production server and that the application is accepting connections.

Send a request to the application:

curl -I http://localhost:3000

A successful deployment returns an HTTP 200 OK response.

Conclusion

This tutorial demonstrated three ways to deploy a Next.js application on a Linux server: PM2 with Nginx, Docker with Docker Compose, and systemd. Each method offers a different approach to process management and deployment, so you can choose a setup that fits your server environment and operational needs.

Next, see how to PrettyPrint a JSON File with Python.

Was this article helpful?
YesNo