Deploy Next.js App to Ubuntu with Apache2

A step-by-step guide for deploying a Next.js application on an Ubuntu server with Apache2 as a reverse proxy, including setting up HTTPS with Let's Encrypt and updating deployment processes.
Deploying a Next.js App on Ubuntu with Apache2 Reverse Proxy
Deploying a modern web application such as Next.js on an Ubuntu server is a practical way to control your environment directly. This guide will walk you through the process of using Apache2 as a reverse proxy to serve your Next.js app, ensuring that it is accessible over HTTPS with Let's Encrypt.
Prerequisites
Before starting the deployment process, ensure you have:
- An Ubuntu server
- Node.js LTS installed
- A domain name pointing to your server's IP address
Building the Next.js App for Production
npm run buildBuilding your Next.js app with npm run build packages up all the static files needed for production, optimizing images and assets to ensure a performant delivery.
Testing the Production Build
npm startStart the development server to test the Next.js app on localhost. This step is crucial to verify that the app builds correctly and runs without issues.
Keeping the App Running with PM2
PM2 helps in keeping your app alive, ensuring it automatically restarts if it crashes or is restarted by a system reboot.
Install PM2
apt-get install pm2Install PM2 using the package manager.
Starting the App with PM2
pm2 start app-nameStart your Next.js app with PM2, which will keep it running in the background.
Saving PM2 Processes
pm2 saveSave the current state of your app in PM2 for a quicker startup on the next boot.
Starting on Reboot
Edit the PM2 startup script to ensure your app starts automatically when the server boots up.
sudo pm2 startup -p [app_process_id]Enabling Apache2 Reverse Proxy Modules
Enable the necessary Apache2 modules:
a2enmod proxy
a2enmod proxy_http
a2enmod headers
a2enmod rewriteThese modules are required to act as a reverse proxy, forwarding requests to the Node.js app.
Writing Apache2 Virtual Host Configuration
Create and edit a virtual host file for your domain:
sudo nano /etc/apache2/sites-available/example.com.confInclude the following configuration in the virtual host file:
<VirtualHost *:80>
ServerName example.com
ServerAdmin webmaster@example.com
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} !=0 [S]
RewriteCond %{HTTP:CONNECTION} !=close [S]
RewriteCond %{HTTP:PROXY} !^$
RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [P,QSA,R=1]
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
</VirtualHost>This configuration directs HTTP traffic to your Node.js app running on port 3000 and forwards it through the proxy.
Setting Up WebSocket and Headers
To ensure WebSocket connections and proper headers, include these directives:
Alias /websocket /var/www/html/websocket
<Directory /var/www/html/websocket>
Require all granted
</Directory>
Header set X-Next-Js-Host "example.com"Enabling HTTPS with Let's Encrypt
sudo certbot --apache -v 22Run Certbot to obtain and install a free SSL certificate from Let's Encrypt. Certbot will set up an Apache virtual host configuration for SSL and reload Apache to apply the changes.
Updating Deployments
To deploy updates to your Next.js app:
rsync -avz ./static/ /var/www/html/Or for production deployments:
npm run buildThen restart the app using PM2:
sudo systemctl restart apache2Or for PM2:
pm2 restart app-nameTroubleshooting Common Problems
- 502 Bad Gateway: Ensure the correct port is being forwarded to your Node.js app and that Apache2 is configured properly to pass requests to it.
- Wrong Port: Check the port in your Apache2 configuration and make sure it matches the port your Node.js app is running on.
- Permission Errors: Verify file and directory permissions, especially for the websocket directory.
- App Not Surviving a Reboot: Ensure the PM2 process is set to start on reboot and that the PM2 process list is not empty.
Apache2 Configuration for Nginx
For Nginx, create a similar configuration in your server block with the appropriate proxy_pass directive and headers.
location / {
proxy_pass http://localhost:3000/;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-S 1;
proxy_set_header X-Forward-To $http_x_forwarded_for;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-For IP:port;
proxy_set end_tags;
}Remember to replace IP:port with the actual server IP and port where your Next.js app is running.
This deployment tutorial provides a comprehensive guide to deploying a Next.js app on an Ubuntu server with Apache2 as a reverse proxy, complete with HTTPS setup using Let's Encrypt. By following these steps, you can ensure a secure and performant deployment of your web application.

Written by Robin te Hofstee
Technology enthusiast with a deep love for programming. Sharing practical guides on React, Next.js, Linux and self-hosting.
Related Posts
Next.js App Router Deep Dive
A practical deep dive into the Next.js App Router: layouts, dynamic routes, Server and Client Components, data fetching, caching, Server Actions, route handlers, and the pitfalls to avoid.
Reverse Proxying Multiple Self-Hosted Apps with One Nginx Instance
Learn how to use a single Nginx instance to reverse proxy multiple self-hosted applications, manage subdomains, and secure them with HTTPS.
How to Secure SSH on Linux/Ubuntu
A complete step-by-step guide to hardening SSH on Linux/Ubuntu for improved security and reduced attack surface.


