All posts
Deploying Next.js with Nginx — reverse proxy, SSL and gzip configuration
  • Next.js
  • Nginx
  • Deployment
  • SSL
  • Node.js

Deploying Next.js with Nginx

A comprehensive guide to deploying your Next.js application on a server running Nginx, covering reverse proxy setup, gzip compression, static caching, and SSL configuration.

3 min read

This guide covers deploying a Next.js application on a server running Nginx. Two modes are covered: a standard Node.js deployment with full SSR support, and a static export deployment where Nginx serves flat HTML files directly.

Standard Deployment with Node.js

1. Build your Next.js app

Build locally before transferring to the server:

# Navigate to your project directory
cd your-next-app

# Install dependencies if you haven't already
npm install

# Build the app
npm run build

# This creates a .next directory with the built app

2. Transfer files to your server

# Example using SCP (run from your local machine)
scp -r .next package.json package-lock.json public next.config.js username@your-server-ip:/path/to/your/app

3. Install dependencies on your server

SSH into your server and install production dependencies:

cd /path/to/your/app
npm install --production

4. Set up Nginx as a reverse proxy

Install Nginx if you haven’t already:

sudo apt update
sudo apt install nginx

Create a new Nginx configuration file for your site:

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

Add this configuration (adjust domain names and paths as needed):

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    # Enable gzip compression
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_proxied any;
    gzip_vary on;
    gzip_types
        application/javascript
        application/json
        application/x-javascript
        application/xml
        image/svg+xml
        text/css
        text/javascript
        text/plain
        text/xml;

    location / {
        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_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;
        proxy_cache_bypass $http_upgrade;
    }

    # Long-term caching for static assets
    location /_next/static/ {
        proxy_pass http://localhost:3000/_next/static/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location /public/ {
        proxy_pass http://localhost:3000/public/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
}

Enable the site, test the configuration, and restart Nginx:

sudo ln -s /etc/nginx/sites-available/nextjs /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

5. Run your Next.js server with PM2

PM2 manages the Node.js process and restarts it on server reboot. For a full PM2 reference covering ecosystem config files, cluster mode, and log rotation, see the PM2 Node.js Process Management Guide.

# Install PM2 globally
sudo npm install -g pm2

# Start your Next.js app
cd /path/to/your/app
pm2 start npm --name "next-app" -- start

# Persist across reboots
pm2 startup
pm2 save

6. Set up SSL with Certbot

Install Certbot and obtain a Let’s Encrypt certificate. For a complete SSL guide covering HSTS, auto-renewal, and troubleshooting, see Set Up HTTPS with Let’s Encrypt on Nginx and Apache.

# Install Certbot
sudo apt install certbot python3-certbot-nginx

# Obtain and install certificates
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Verify auto-renewal is configured
sudo systemctl status certbot.timer

Certbot will automatically modify your Nginx configuration to handle SSL.


Static Export Deployment

Use this approach when you don’t need SSR, API routes, or middleware.

1. Configure your app for static export

Add the output setting to your next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
}

module.exports = nextConfig

2. Build your app

npm run build

This creates an out directory with static files ready to serve.

3. Install Nginx

sudo apt update
sudo apt install nginx

4. Transfer the built files to your server

# From your local machine
scp -r ./out/* username@your-server-ip:/var/www/yourdomain.com/html/

Create the directory and set permissions on the server first:

sudo mkdir -p /var/www/yourdomain.com/html
sudo chown -R $USER:$USER /var/www/yourdomain.com/html
sudo chmod -R 755 /var/www/yourdomain.com

5. Configure the Nginx server block

sudo nano /etc/nginx/sites-available/yourdomain.com
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com/html;
    index index.html;

    # Enable gzip compression
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_proxied any;
    gzip_vary on;
    gzip_types
        application/javascript
        application/json
        application/x-javascript
        application/xml
        image/svg+xml
        text/css
        text/javascript
        text/plain
        text/xml;

    # Long-term caching for static assets
    location /_next/static/ {
        expires 365d;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location / {
        try_files $uri $uri.html $uri/ =404;
    }

    # Custom 404 page
    error_page 404 /404.html;
}

6. Enable the site and restart Nginx

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

7. Set up SSL

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Important Notes

  • Your server must have Node.js installed. Check the official Next.js docs for the minimum Node.js version required by your release — each major version may raise the minimum.
  • Static export does not support SSR, API routes, server actions, or middleware.
  • Configure proper file permissions so Nginx can read your static files.
  • Always use HTTPS in production and set up logging and monitoring for production deployments.

Frequently Asked Questions

Is Nginx better than Apache for Next.js?

Nginx is often preferred for Next.js deployments due to its efficient handling of static assets, lower memory footprint, and better performance under high load. It excels at serving static content and acting as a reverse proxy. If you prefer Apache, see the Deploying Next.js with Apache2 guide for an equivalent setup.

How do I handle client-side routing with static export?

Add a location block in your Nginx config to redirect requests to the appropriate HTML file, since Next.js client-side routing expects the server to serve the main index.html for all routes.

How do I manage environment variables?

For SSR deployments, set environment variables directly on your server. For static exports, variables consumed client-side must be prefixed with NEXT_PUBLIC_ and available at build time — they get embedded into the JavaScript bundles.

How do I update the deployment after code changes?

For standard deployments: pull the latest code, rebuild, and restart the PM2 process. For static exports: rebuild locally, copy the new out directory to your server — no Nginx restart needed.