Overview
Deploying a Next.js application properly is more than just starting the app with npm run start. In a real server environment, the application should run as a managed process, and Nginx should sit in front of it as a reverse proxy.
This setup allows Nginx to receive browser traffic on port 80 or 443 and forward requests internally to the Next.js app running on a local port such as 3000.
The goal is simple: users access the website using a normal domain name, while the application remains safely managed behind Nginx.
1. Prepare the server
Before deploying the application, confirm that the server has Node.js, npm, Git, Nginx, and PM2 installed.
Use a normal application user where possible, and avoid running the application directly as root.
Use this command to check the important tools:
node -v
npm -v
git --version
nginx -v
pm2 -vIf one of these tools is missing, install it before continuing.
2. Build the Next.js application
After pulling the latest code from Git, install dependencies and build the application.
cd /srv/example-app
npm install
npm run buildA successful build confirms that the application can compile correctly before it is started in production mode.
If the build fails, do not continue to Nginx configuration yet. Fix the application issue first.
3. Start the app with PM2
PM2 keeps the application running in the background and can restart it if the process crashes.
pm2 start npm --name example-app -- start
pm2 save
pm2 statusAfter starting the app, test it locally from the server:
curl -I http://127.0.0.1:3000You should see a successful HTTP response. If the local test does not work, Nginx will not fix the problem.
4. Configure Nginx reverse proxy
Create an Nginx server block for the application domain.
server {
listen 80;
server_name example.com www.example.com;
client_max_body_size 10M;
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;
}
}The proxy_pass line is the most important part. It tells Nginx to forward public web traffic to the local Next.js process.
5. Test and reload Nginx
Always test the Nginx configuration before reloading the service.
sudo nginx -t
sudo systemctl reload nginxThen test the website from the server:
curl -I http://example.com6. Common mistakes to avoid
A common mistake is configuring Nginx before confirming that the application works locally.
Another common issue is using the wrong port in proxy_pass. If PM2 runs the app on port 3000, then Nginx must point to 127.0.0.1:3000.
Also check that the domain DNS points to the correct server IP address. If DNS points somewhere else, the Nginx configuration on this server will not be used.
7. Final checklist
Before considering the deployment complete, confirm the following:
The app builds successfully
PM2 shows the app as online
The local curl test works
Nginx configuration test passes
The domain resolves to the correct server
The website opens in the browser
Upload limits are configured if the app accepts filesTip
Do not expose the application port directly to the internet unless there is a clear reason. In most deployments, users should access the app through Nginx, while the app itself listens locally.
Conclusion
A clean Next.js deployment should be predictable and easy to maintain. PM2 manages the application process, while Nginx handles public web traffic, reverse proxying, and upload limits.
This structure makes the deployment easier to troubleshoot because each layer has a clear responsibility.
Testing images
Add one image after the Overview section and one image after the Nginx reverse proxy section. This will confirm that:
Images upload correctly
Images appear inside the editor
Images render on the public article page
Public image sizing looks good