Some time ago I wrote the post How I deploy my NextJS Projects with Nginx and Cloudflare Tunnel. But since than I've changed the way I host my sites. I've removed Cloudflare Tunnel from my tech stack and decided to manage things by myself by switching to a PM2 + Nginx + Certbot based setup. But sometimes I just like to embrace the traditions like using Systemd instead of PM2.
So in this post I'm going to show you how I deploy my NextJS projects on Linux using nothing but Systemd and Nginx web server. Let's start!
Setting up user and Systemd
So first things first we need a different user without root access for running our website. And for that I'm gonna create a webd user (Stands for web-daemon) with /web
as it's home folder.
sudo useradd -m -d /web webD
This command above creates our user and it's home directory /web
for us. Now when you go to root folder you can see a new folder named web.
Now we need to change the owner group of that folder as our current user and give it right permissions. To do that we can simply use the commands below.
sudo chown -R webD:bt /web
sudo chmod -R ug+rwx /web
At that point you should be able to read, write and execute from that folder with no problem. You can verify that by running a simple touch command inside that folder.
Now we need to move our website source to this folder and create our Systemd service for it.
Before continuing I needed to verify that NodeJS has no issues with our permissions, so I moved an old version of this website and tested it out by running command below.
sudo -u webD npm run dev
And of course it worked perfectly fine. But in case of error, you can run the chmod command above and try again.
Now we need to create a file with the name of our project under /etc/systemd/system
folder.
sudo vim /etc/systemd/system/web-project.service
And fill the file with the content like below. Don't forget to tune it for your project!
[Unit]
Description=Projects Name
After=network.target
[Service]
WorkingDirectory=/web/project
User=webD
Environment="NODE_ENV=production"
ExecStart=/usr/bin/npm run start
[Install]
WantedBy=multi-user.target
At that point you should make sure that your npm binary is located at /usr/bin
by using the command below otherwise it'll fail to run.
which npm
After that run the command below to enable our service.
sudo systemctl enable --now web-project
Now our NextJS website should be up and running in our local network. You can confirm that by using the command below and visiting the website from it's local address.
sudo systemctl status web-project
# Example output from tbnmc's website
● Caesium.service - TBNMC Website
Loaded: loaded (/etc/systemd/system/Caesium.service; enabled;
Active: active (running) since Sun 2024-05-19 16:30:16 UTC; 3min 19s ago
Main PID: 3665 (npm run start)
Tasks: 24 (limit: 2197)
Memory: 164.3M
CPU: 3.361s
CGroup: /system.slice/Caesium.service
├─3665 "npm run start"
├─3676 sh -c "next start -p 8090"
└─3677 next-router-worker
May 19 16:30:16 cork-server2 systemd[1]: Started TBNMC Website. May 19 16:30:17 cork-server2 npm[3665]: > Caesium@1.2.0 start May 19 16:30:17 cork-server2 npm[3665]: > next start -p 8090
May 19 16:30:17 cork-server2 npm[3677]: ▲ Next.js 13.5.6 May 19 16:30:17 cork-server2 npm[3677]: - Local: http://localhost:8090
May 19 16:30:17 cork-server2 npm[3677]: ✓ Ready in 311ms
And this means our service is up and running perfectly fine! Now we can configure Nginx as reverse proxy and Certbot for TLS certificates.
Setting up Nginx and Certbot
Configuring Nginx as a reverse proxy and using Certbot with it is actually pretty easy. We just need to add a server config file that listens connections on port 80 and proxies that to our website which runs in background as a systemd service.
But before going any further we need to install those packages.
For dnf :
sudo dnf install nginx certbot python3-certbot-nginx
For apt :
sudo apt install nginx certbot python3-certbot-nginx
after that simply go to your Nginx config directory and create a new config file with your projects name.
(/etc/nginx/conf.d
for RHEL based, /etc/nginx/sites-enabled
for Debian based)
Now create file using command below and fill it's contents like the example below that command.
sudo vim web-project.conf
server {
listen 80;
server_name example.com;
location / {
add_header Access-Control-Max-Age "3600" always;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options deny;
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
You need to change the server_name
with your domain and the port 3000 with the current port your server runs on in proxy_pass
section.
After that restart the Nginx and after that (assuming that you've done with DNS settings) when you visit your website under your domain, everything should work.
Now only thing we need to do is getting our TLS certs for secure Https connections. For that we're gonna use Certbot that we installed earlier. Believe me it's easy as running a single command.
To get your tls certs for your website use the command below and follow it's instructions.
sudo certbot --nginx -d example.com
After that restart Nginx, you should be able to visit your website using Https.
sudo systemctl restart nginx
And we're done!
This is a way I use for servers that only hosts 1 or 2 websites, for more complex setups like load balancing, multi-threading and other stuff I still use PM2. But I believe it's an overkill for hosting a simple static blog site like I have with TbnMC so this is an alternative way to follow.
So that's it for this post. If you got any problems with your setup you can always send an e-mail or leave me a comment on Mastodon, I'll be happy to help you. As always, thanks for reading!
Reply via E-Mail
Thank You!
19.05.2024 - 51/100