A complete and straightforward guide to Node.js, Nginx, Git Deploy, and PM2 on Ubuntu.
Do you still need Terraform after this?

Search for a command to run...
Do you still need Terraform after this?

No comments yet. Be the first to comment.
Here we will go through the process of contract upgrades. I assume you are already familiar with proxy patterns in Ethereum. No matter which libraries or frameworks you use, every upgrade ends with the same critical action: executing the method that ...

This article isn’t about cryptocurrency or decentralized finance. Instead, we’ll explore public EVM blockchains and how they can be used in your next project, depending on your specific needs and goals. I’ll delve into the pros, cons, and practical e...

* to write in the local and forked development network In the previous article, we looked into how the EVM storage is arranged and how we can access all the contract's data relatively easily when the contract is validated or we have the source code. ...

One of the greatest features of Web3 is the Open Data Principle. The Data doesn't belong just to companies, governments, groups, and individuals - it belongs to all of them and you at once. Anyone can create a twig (the contract) in global storage (t...

A multi-signature account as middleware between you and the dApps

Okay, I must admit that Terraform is not obsolete after this tutorial, neither Kubernetes, Azure Pipelines, Ansible, Pulumi nor Docker. I just want to show how you can deploy your first Node.js stack in seconds via SSH by having just a fresh or any existing Ubuntu server. For middle projects, this should be enough.
In the first part, we'll go through the commands required to install and configure things, then you'll get a script to automate this, to be able to perform all these steps with a single command.
Nginx
Certbot
PM2
Local Git
Node.jsn module helps to manage the nodejs versionsapt update
apt install nginx nodejs npm certbot -y
npm install -g n
# update nodejs to the latest
n stable
node -v
npm -v
npm i pm2 -g
# start pm2 on OS start
pm2 startup
# the server directory
mkdir -p /var/www/foo
# the git repository, we will push to
git init --bare /var/www/foo.git
Then we have to create the post-receive hook - the script, which will be executed each time we push the changes to the git server. In the script we will a) copy the code to the server directory b) handle git submodules c) run build scripts d) restart the nodejs process:
cat <<EOT >> /var/www/foo.git/hooks/post-receive
#!/bin/sh
git --work-tree=/var/www/foo --git-dir=/var/www/foo.git checkout -f
cd /var/www/foo
# optionally, restore submodules
git --git-dir=/var/www/foo.git --work-tree=. submodule init
git --git-dir=/var/www/foo.git --work-tree=. submodule update
npm i
npm run build
# this will also restart foo, if already running
pm2 start foo
EOT
# allow to execute
chmod +x /var/www/foo.git/hooks/post-receive
This one we will split into two steps:
# to remove any default websites
rm /etc/nginx/sites-available/default
# copy-paste simple server for the letsencrypt challange
cat <<EOT >> /etc/nginx/sites-available/default
server {
listen 80;
server_name foo.bar;
root /var/www/foo;
}
EOT
# start a new server
service nginx restart
# will generate the certificates
certbot certonly --webroot -w /var/www/foo -d foo.bar --email team@foo.bar --agree-tos --no-eff-email
# now create the final server
rm /etc/nginx/sites-available/default
cat <<EOT >> /etc/nginx/sites-available/default
server {
listen 80;
listen 443 ssl;
server_name foo.bar;
ssl_certificate /etc/letsencrypt/live/foo.bar/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/foo.bar/privkey.pem;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
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_cache_bypass $http_upgrade;
}
}
EOT
service nginx restart
ecosystem.config.js file to configure the pm2module.exports = {
"apps": [
{
"name": "foo",
"script": "index.js",
"args": [
"--SERVER", "--port 3000",
],
"node_args": [
"--max-old-space-size=12000"
],
"timestamp": "MM-DD HH:mm Z",
"instances": "max",
"exec_mode": "cluster",
"env": {}
}
]
};
git init
git remote add prod root@SERVER_IP_DOMAIN:/var/www/foo.git/
You can extend and install any other software you need, which is beneficial by using plain SSH access directly to your Ubuntu instance - there are dozens of other tutorials and configurations.
The commands above are simple copy-paste-enter commands, which means you can submit them one by one, but I'm using ssh2 module to submit commands over the ssh client.
I've also published the ssh2 wrapper class to make the client easier to use - sshly
import { Ssh } from 'sshly'
const script = `
apt update
---
apt install nodejs npm certbot -y
---
npm install -g n
---
n stable
---
npm i pm2 -g
---
pm2 startup
---
mkdir -p /var/www/foo
---
git init --bare /var/www/foo.git
---
cat <<EOT >> /var/www/foo.git/hooks/post-receive
#!/bin/sh
git --work-tree=/var/www/foo --git-dir=/var/www/foo.git checkout -f
cd /var/www/foo
git --git-dir=/var/www/foo.git --work-tree=. submodule init
git --git-dir=/var/www/foo.git --work-tree=. submodule update
npm i
npm run build
pm2 start foo
EOT
---
chmod +x /var/www/foo.git/hooks/post-receive
---
rm /etc/nginx/sites-available/default
---
cat <<EOT >> /etc/nginx/sites-available/default
server {
listen 80;
server_name foo.bar;
location ^~ /.well-known/acme-challenge/ {
root /var/www/foo
allow all;
default_type "text/plain";
}
}
EOT
---
service nginx restart
---
certbot certonly --webroot -w /var/www/foo -d foo.bar --email team@foo.bar --agree-tos --no-eff-email
---
rm /etc/nginx/sites-available/default
---
cat <<EOT >> /etc/nginx/sites-available/default
server {
listen 80;
listen 443 ssl;
server_name foo.bar;
ssl_certificate /etc/letsencrypt/live/foo.bar/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/foo.bar/privkey.pem;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
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_cache_bypass $http_upgrade;
}
}
EOT
---
service nginx restart
`
const client = new Ssh({
host: 'IP',
privateKeyPath: 'path/to/file'
});
const commands = script
.split('---')
.filter(x => x.trim().replace(/\r/g, ''))
.filter(Boolean);
for (let command of commands) {
await client.exec(command);
}
Push your code to the repository
git add -A
git commit -am "init"
git push -u prod master
You can create your own setup, using apache2 for example, or separate roles. After all, these are plain *nix commands with Node.js scripting, and it is a huge advantage over using some additional deployment tools or platforms.
Adjust and save the server creation script as a template, so that later you can deploy Node.js servers with ease.
Happy deploying.