Introduction
In this tutorial we will deploy a Next.js application on a Hetzner Managed Server for production. We will set up PM2 and a reverse proxy configuration.
Prerequisites
- SSH access
hos-nodejs
is already installed (send support request via konsoleH)- Process release for
PM2*
,next-server*
andsh
(send support request via konsoleH)
Step 1 - Set Node.js version
Depending on which Node.js version your application requires, execute one of the following commands:
# for v18
echo 18 > ~/.nodeversion
# for v20
echo 20 > ~/.nodeversion
# for v22
echo 22 > ~/.nodeversion
Use v22 if you create a new application.
You can check the currently used version via node -v
.
Step 2 - Install PM2
Adjust $PATH
variable
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Install PM2 via
npm install -g pm2
and check if PM2 is installed
pm2 --version
This should give you the version number.
Step 3 - Create Next.js application
Change into your home directory and create a new Next.js application via the following command:
cd "$HOME"
npx create-next-app@latest
cd example-app/ # Replace example-app with the name of your app
Alternatively, you can upload your existing application via FTP, SFTP or clone it from your Git repository.
Step 4 - Build your Next.js application
Adjust your next.config.ts
and make sure output
option is set to standalone
:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: 'standalone',
};
export default nextConfig;
Now create a production build via
npm run build
Step 5 - Copy static files into the document root
To serve the static files directly via Apache, we have to copy the files into a directory Apache can access.
In this example, the document root of the domain is set directly to the public_html
directory via konsoleH.
Run the commands below inside the directory of your app.
Replace holu
with the actual username of your current user.
cp -r public/* /usr/www/users/holu
mkdir /usr/www/users/holu/_next
cp -r .next/static/ /usr/www/users/holu/_next
This step has to be repeated every time you rebuild your application via npm run build
. You might want to delete old files before.
Step 6 - Start Next.js via PM2
Start your application in cluster mode:
pm2 start --name example-app -i max .next/standalone/server.js
pm2 save
To check if your application is running, run pm2 status
. The output should look like this:
$ pm2 status
┌────┬────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ example-app │ default │ 0.1.0 │ cluster │ 78638 │ 85s │ 0 │ online │ 0% │ 97.1mb │ holu │ disabled │
│ 1 │ example-app │ default │ 0.1.0 │ cluster │ 78645 │ 85s │ 0 │ online │ 0% │ 96.9mb │ holu │ disabled │
│ 2 │ example-app │ default │ 0.1.0 │ cluster │ 78652 │ 85s │ 0 │ online │ 0% │ 94.3mb │ holu │ disabled │
│ 3 │ example-app │ default │ 0.1.0 │ cluster │ 78659 │ 85s │ 0 │ online │ 0% │ 94.9mb │ holu │ disabled │
│ 4 │ example-app │ default │ 0.1.0 │ cluster │ 78670 │ 85s │ 0 │ online │ 0% │ 95.0mb │ holu │ disabled │
│ 5 │ example-app │ default │ 0.1.0 │ cluster │ 78681 │ 85s │ 0 │ online │ 0% │ 95.0mb │ holu │ disabled │
│ 6 │ example-app │ default │ 0.1.0 │ cluster │ 78692 │ 85s │ 0 │ online │ 0% │ 95.2mb │ holu │ disabled │
│ 7 │ example-app │ default │ 0.1.0 │ cluster │ 78703 │ 85s │ 0 │ online │ 0% │ 95.0mb │ holu │ disabled │
└────┴────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
Step 7 - Create .htaccess
Add the following .htaccess
file to your document root (e.g. public_html
):
DirectoryIndex disabled
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/?$
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*)$ http://localhost:3000/$1 [P,L]
If your application is using a different port, you have to replace 3000
with your port.
Step 8 - Create a @reboot cronjob
To automatically start PM2 and your application after a server restart, create the following cronjob via the Cronjob-Manager in konsoleH:
@reboot "$HOME/.local/bin/pm2" resurrect
Step 9 - Test
Open your domain in the browser and you should see your Next.js application.
Conclusion
You now have a production ready deployment of your Next.js application on your Managed Server.