Host Next.js 14 Application on Ubuntu VPS
When it comes to deploying modern web applications, Next.js has established itself as one of the top frameworks for developers. With its server-side rendering, static site generation, and hybrid capabilities, it offers a robust solution for building scalable web applications. This guide will walk you through the process of hosting a Next.js 14 application on an Ubuntu 22 VPS, ensuring your app runs smoothly and efficiently.
Whether you're a seasoned developer or just starting with Next.js, this tutorial will provide you with a step-by-step approach to deploying your application on a VPS. We'll cover everything from setting up your server environment to configuring Nginx for reverse proxying, ensuring that your application is both secure and performant.
Overview: What We Will Cover
In this guide, we will cover the following 9 steps:
- Connecting to Your Ubuntu VPS
- Updating and Installing Essential Dependencies
- Installing Node.js Using NVM
- Setting Up PM2 for Process Management
- Deploying Your Next.js Application
- Running Your Application with PM2
- Configuring Nginx as a Reverse Proxy
- Securing Your Site with SSL (Optional)
- Final Configuration and UFW Setup
Now, let's dive into each step in detail.
Step 1: Connect to Your Ubuntu VPS
The first step in deploying your Next.js application is to connect to your Ubuntu VPS. If you haven't already, you should have access to your VPS through SSH. Open your terminal and enter the following command:
ssh username@vps_ip
Replace username
with your VPS username and vps_ip
with your VPS's IP address. Once connected, you'll be working directly on your VPS, where we'll set up the environment needed to host your Next.js application.
Step 2: Update and Install Essential Dependencies
Before we dive into setting up Node.js and other tools, it's essential to update your system's package list and upgrade any outdated packages. This ensures your environment is up-to-date and reduces the risk of conflicts during the installation process.
Run the following commands:
sudo apt update && sudo apt upgrade -y
sudo apt install nginx curl
These commands will update your package list, upgrade existing packages, and install Nginx and Curl, two critical components for our setup.
Note: Although Ubuntu 22 typically comes with Curl pre-installed, we are installing it manually to avoid potential issues. If you’re using a different version of Ubuntu, this step ensures you have the latest version of Curl.
Step 3: Installing Node.js Using NVM
Node.js is the runtime environment required for running Next.js applications. While you can install Node.js directly using apt-get
, I recommend using NVM (Node Version Manager). NVM allows you to manage multiple versions of Node.js, making it easier to switch between versions or upgrade in the future.
To install NVM, run the following command:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
After installation, load NVM into your shell session:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
To verify the installation, check the NVM version
nvm -v
You should see the installed NVM version as below:

Now, you can install Node.js using NVM:
nvm install --lts
This command installs the latest Long-Term Support (LTS) version of Node.js, ensuring that you have a stable and supported version for your application. After installation, verify Node.js and NPM (Node Package Manager) versions:
node -v
npm -v
You should see the installed Node and NPM version as below:

Step 4: Setting Up PM2 for Process Management
Next.js applications are typically run using the npm start
command, but this isn't ideal for production. Instead, we'll use PM2, a process manager that keeps your application running even after you close your SSH session. PM2 also offers additional features like load balancing and monitoring, making it a powerful tool for managing Node.js applications.
Install PM2 globally using NPM:
npm install -g pm2
With PM2 installed, you're now ready to run your Next.js application in a more production-friendly manner.
Step 5: Deploying Your Next.js Application
Now that our environment is set up, it's time to deploy your Next.js application. First, create a directory where your application will reside:
sudo mkdir -p /var/www/myapp
Navigate to this directory and install your Next.js app dependencies:
cd /var/www/myapp
npm install
npm run build
This will install all the necessary packages and build your Next.js application for production. The build command compiles your application into an optimized bundle that can be served to users.
In my case, I directly install nextjs here. Let's go


Step 6: Running Your Application with PM2
Instead of using the traditional npm start
command, we'll leverage PM2 to manage our Next.js process. This ensures that your application remains running, even after server restarts or SSH disconnections.
Start your Next.js application using PM2:
pm2 start npm --name "nextjs-app" -- start
if you need to launch Next.js with pm2 on a different port then run the command below:
pm2 start npm --name "nextjs-app" -- start -- --port=3001
Now you can verify that your application is running by checking the PM2 process list:
pm2 list
You should see a list of pm2 that containing your nextjs-app to be running:

To ensure that PM2 restarts your application after a server reboot, run the following commands:
pm2 startup systemd
pm2 save
These commands configure PM2 to start your application automatically on system boot.
Step 7: Configuring Nginx as a Reverse Proxy
Nginx is a powerful web server that can act as a reverse proxy for your Next.js application. This means that Nginx will handle incoming HTTP requests and forward them to your Next.js server, which is running on port 3000 by default.
First, create a new Nginx configuration file:
sudo nano /etc/nginx/sites-available/your-domain
Replace your-domain.com
with your actual domain name. If you don't have a domain name, you can use your server's IP address.
Paste the following configuration into the file:
server {
listen 80;
server_name domainname.com www.domainname.com; # Replace with your domain or IP
gzip on;
gzip_proxied any;
gzip_types application/javascript application/x-javascript text/css text/javascript;
gzip_comp_level 5;
gzip_buffers 16 8k;
gzip_min_length 256;
location /_next/static/ {
alias /var/www/myapp/.next/static/;
expires 365d;
access_log off;
}
location / {
proxy_pass http://localhost:3000; # Ensure this matches your Next.js port
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;
}
}
This configuration tells Nginx to listen on port 80 (HTTP) and forward all requests to your Next.js application running on port 3000. The gzip
settings optimize the compression of static assets, improving load times for your users.
Save and close the file. Then, enable this configuration and restart Nginx:
sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/your-domain.com
sudo nginx -t
sudo systemctl restart nginx
The nginx -t
command tests your configuration for syntax errors, and if everything looks good, Nginx will restart with your new settings.
Step 8: Securing Your Site with SSL (Optional but Recommended)
Securing your site with SSL is crucial for protecting user data and improving SEO. Let's Encrypt provides free SSL certificates, and we can use Certbot to automate the installation process.
First, install Certbot and the Nginx plugin:
sudo apt install certbot python3-certbot-nginx
Next, obtain and install your SSL certificate:
sudo certbot --nginx -d your-domain.com
Replace your-domain.com
with your actual domain name. Certbot will automatically configure Nginx to use SSL, and your site will now be accessible via HTTPS.
Step 9: Final Configuration and UFW Setup
To further secure your server, it's essential to configure UFW (Uncomplicated Firewall). We'll allow traffic on ports 80 (HTTP) and 443 (HTTPS), as well as SSH for remote access:
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
Finally, restart Nginx to apply all changes:
sudo systemctl restart nginx
sudo systemctl status nginx
This will ensure that your Nginx server is running with the latest configuration and that your Next.js application is accessible via your domain or IP address.
Ensuring Proper Nginx Access (Optional but Helpful)
In some cases, even after correctly configuring Nginx, you might encounter issues where your domain doesn't seem to work as expected. This can be due to permission problems with your application's static files. While this step isn't mandatory, it can resolve certain issues that arise after Nginx configuration.
To give Nginx the proper access to your Next.js static files, you can adjust the permissions of the directories containing these files. Run the following commands:
sudo chmod -R 755 /var/www/myapp/.next/static/
sudo chmod -R 755 /var/www/myapp/public/static/
These commands ensure that Nginx has the necessary read and execute permissions to serve your static files properly. While this step is often overlooked in many tutorials, it can be crucial in troubleshooting issues related to file access and permissions.
Finally
In my case I don't have any domain yet so I go with my VPS ip_address and after all the setup, I am finally able to see Nextjs default landing page:

Conclusion
Congratulations! You have successfully deployed a Next.js 14 application on an Ubuntu 22 VPS. By following this guide, you've set up a robust environment that includes Nginx for reverse proxying, PM2 for process management, and SSL for security. This setup is scalable, secure, and production-ready, allowing you to focus on developing your application while ensuring it runs smoothly for your users.
Remember, maintaining your server is just as important as setting it up. Regularly update your packages, monitor your server's performance, and renew your SSL certificates to keep your application running securely and efficiently. With this foundation, you're well on your way to delivering a high-performance Next.js application to the world.