Deploy Next.js to Hetzner VPS with PM2 & Nginx
A complete, hands-on guide to deploying a production-ready Next.js application on Hetzner Cloud. Covers server provisioning, Node.js setup, PM2 process management, Nginx reverse proxy, free SSL, and automated deployments via GitHub webhooks.
Why Hetzner for Next.js?
Hetzner is the best-value VPS provider for hosting Next.js apps in 2026. Their CX22 plan gives you 2 vCPU, 4 GB RAM, and 20 TB bandwidth for just €4.15/mo ($4.51) — that's 200x more bandwidth than Vercel's free tier at a fraction of the cost of Vercel Pro.
Hetzner server tiers for Next.js
Here are the three Hetzner plans we recommend for Next.js deployments. The CX22 handles most projects. Pick CX32 if you run multiple apps, or CAX11 (ARM) if you want the absolute cheapest option.
| Plan | Arch | Price | CPU | RAM | SSD | Bandwidth |
|---|---|---|---|---|---|---|
| CX22 | x86 | €4.15 | 2 vCPU | 4 GB | 40 GB | 20 TB |
| CX32 | x86 | €7.00 | 4 vCPU | 8 GB | 80 GB | 20 TB |
| CAX11 | ARM | €3.79 | 2 vCPU | 4 GB | 40 GB | 20 TB |
Tip: The CAX11 ARM server is €3.79/mo and runs Next.js perfectly. Node.js has excellent ARM support. Just make sure your npm dependencies don't require x86-only native binaries.
Prerequisites
1Create a Hetzner Cloud server
Log in to Hetzner Cloud Console and click Create Server. Configure the following:
Click Create & Buy Now. Your server will be ready in about 10 seconds. Copy the IP address — you'll need it next.
2Initial server setup
SSH into your new Hetzner server and run the initial hardening steps:
# Connect to your server
ssh root@YOUR_SERVER_IP
# Update packages
apt update && apt upgrade -y
# Set up UFW firewall
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# (Optional) Create a non-root user
adduser deploy
usermod -aG sudo deploy
cp -r ~/.ssh /home/deploy/
chown -R deploy:deploy /home/deploy/.sshYour server is now secured with a firewall that only allows SSH, HTTP, and HTTPS traffic. All other ports are blocked by default.
3Install Node.js, PM2, and Nginx
Install the runtime and tools your Next.js app needs:
# Install Node.js 20 LTS via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
apt install -y nodejs
# Verify installation
node -v # v20.x.x
npm -v # 10.x.x
# Install PM2 globally
npm install -g pm2
# Install Nginx
apt install -y nginx
systemctl enable nginx
systemctl start nginxVisit http://YOUR_SERVER_IP in your browser — you should see the default Nginx welcome page. That confirms Nginx is running and ports 80/443 are open.
4Deploy your Next.js app
Clone your repository and start the app with PM2:
# Create app directory
mkdir -p /var/www && cd /var/www
# Clone your repo
git clone https://github.com/YOUR_USER/YOUR_REPO.git myapp
cd myapp
# Install dependencies
npm ci
# Build the Next.js app
npm run build
# Start with PM2
pm2 start npm --name "myapp" -- start
pm2 save
pm2 startupThe pm2 startup command generates a systemd service so PM2 (and your app) restarts automatically if the server reboots. Run the command it outputs to complete the setup.
Using a PM2 ecosystem file gives you more control. Create ecosystem.config.js in your project root:
module.exports = {
apps: [
{
name: "myapp",
script: "node_modules/.bin/next",
args: "start",
cwd: "/var/www/myapp",
instances: "max",
exec_mode: "cluster",
env: {
NODE_ENV: "production",
PORT: 3000,
},
},
],
};Then start with pm2 start ecosystem.config.js. Cluster mode spawns one process per CPU core, maximizing throughput on the CX22's 2 vCPUs.
5Configure Nginx reverse proxy
Create an Nginx server block that forwards HTTP traffic to your Next.js app running on port 3000:
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://127.0.0.1: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;
}
# Cache static assets
location /_next/static/ {
proxy_pass http://127.0.0.1:3000;
expires 365d;
access_log off;
add_header Cache-Control "public, immutable";
}
}Enable the site and reload Nginx:
# Enable the site
ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
# Remove the default site
rm /etc/nginx/sites-enabled/default
# Test and reload
nginx -t
systemctl reload nginxYour Next.js app is now accessible at http://yourdomain.com. The Nginx config also caches Next.js static assets with a one-year expiry for optimal performance.
6SSL with Let's Encrypt
Install Certbot and obtain a free SSL certificate:
# Install Certbot
apt install -y certbot python3-certbot-nginx
# Obtain and auto-configure SSL
certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Verify auto-renewal
certbot renew --dry-runCertbot automatically modifies your Nginx config to redirect HTTP to HTTPS and adds the SSL certificate paths. Certificates auto-renew every 90 days via a systemd timer — zero maintenance required.
7Set up GitHub webhook for auto-deploy
Create a simple deploy script on your server so every git push to main triggers a fresh build:
#!/bin/bash
# /var/www/deploy.sh
cd /var/www/myapp
git pull origin main
npm ci
npm run build
pm2 restart myappYou can trigger this script with a lightweight webhook listener like webhook (adnanh/webhook) or a simple Express endpoint. For detailed instructions, see our GitHub webhooks auto-deploy guide.
Or: skip all 7 steps with DeployWise
DeployWise automates everything above. Connect your GitHub repo and your Hetzner server — DeployWise installs Node.js, configures PM2, sets up Nginx, provisions SSL, and deploys your app. Push to GitHub, and it auto-deploys.
No SSH commands. No config files. No forgetting to restart PM2 after a deploy. Every step in this guide is automated by DeployWise.
Hetzner vs other VPS providers
A quick comparison of the entry-level plan suitable for Next.js from each provider:
| Provider | Price | CPU | RAM | Bandwidth | Verdict |
|---|---|---|---|---|---|
| Hetzner CX22 | $4.51 | 2 vCPU | 4 GB | 20 TB | Best value |
| DigitalOcean | $6 | 1 vCPU | 2 GB | 2 TB | Best docs |
| Vultr | $6 | 1 vCPU | 2 GB | 2 TB | Most locations |
| Linode | $5 | 1 vCPU | 1 GB | 1 TB | Reliable |
| Vercel Pro | $20 | Serverless | N/A | 1 TB | Easiest, priciest |
For most indie developers and small teams, Hetzner's CX22 delivers 4x the RAM, 10x the bandwidth, and half the price of DigitalOcean's entry plan. The only downside is no Asia-Pacific datacenters — if your users are primarily in Asia, consider Vultr or DigitalOcean instead.
Ready to deploy to Hetzner?
Sign in with GitHub, add your Hetzner server, and have your Next.js app live in under 2 minutes — for free.
Open DeployWise Dashboard