Why?
You have a Node.js project in your local machine but you don't know how to deploy it to your remote server or you use old fashioned way by copying the contents from your computer to the remote server using FTP?
Well, you can automate this process and make your life easier using PM2 *insert hooray gif here*
What?
PM2 is a Process Manager for Node.js. It's like Task Manager in Windows and Activity Monitor in macOS.
You can -including but not limited to- manage your application, scale, start and stop. But the most important feature we want is deploying.
In this post, we will learn how to deploy our application to our remote server and run/build it with a single console command.
How?
Step 1: Create a Project
First, we obviously need a project.
We create a folder and cd into it.
mkdir pm2-deploy; cd pm2-deploy
Then we initialize the folder as a node project.
npm init -y
We can then go ahead and install express
to serve static files in node environment.
npm i express
And we need to create a JS file to write our code that will serve the folder public
which we also need to create.
I have created index.js
in the root directory. You can rename it whatever you want but don't forget that you need to change the main
field in the package.json
file also.
We also need an HTML file to be served in that public folder.
Your file structure now looks like this:
Here's my index.js
express is serving a static folder named public
and its contents in port 3000; Nothing fancy here.
In index.html
we do nothing special.
Now we can use
npm start
We should see the console.log output which is PM2 Project is now live @ localhost:3000
.
We can check if that's working by going to that port. Go to localhost:3000
in the browser, If you see YAY!
that's great.
Step 2: Install PM2 globally
We need to install PM2 npm package globally. We can install it by using
npm i -g pm2
Now onto Step 3!
Step 3: Initialize git
We cannot have a CI/CD without a version control system, right? So we need to push our project to a git service. I will use Github for that.
When you create a git repo you will see the necessary instructions on how to push an existing project.
But here are the necessary commands, just in case:
git init
git remote add origin git@github.com:<your_github_username>/<your_repository_name>.git
git add .
git commit -m "Initial Commit"
git branch -M main
git push -u origin main
Note: I strongly recommend using SSH Connection instead of using HTTPS for Github. Your life will get better and securerer :)
Step 4: Configuring the remote machine
In this step, I won't go into the details of how to create/reserve a virtual remote machine but keep in mind that I am using Ubuntu on an EC2 (AWS) machine.
First, we need to connect to the remote machine using SSH
ssh -i path_to_key_file remote_username@remote_ip
I assume you have already done nvm, npm installations, if not you can go ahead and check the nvm repo here: https://github.com/nvm-sh/nvm#installing-and-updating
One important thing to do here. We need to move the lines that were added by nvm to our .bashrc file to the top. Your system may be using .bash_profile or something else. Just pay attention to the output of the nvm installation.
These are the lines we need to move. Open your favorite editor and move them to the top of the file.
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
After saving and exiting the file we can install PM2 here too as we did in Step 2.
i -g pm2
After the installation
startup
will give you a simple instruction on how to make PM2 start automatically every time your remote system reboots. I strongly recommend doing that.
Now that we installed PM2, we need to create an SSH key and add it to Github.
In the remote machine, you can go ahead and type
ssh-keygen -t ed25519 -C "<your_github_email>"
Further reading on how to create ssh key https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
The keygen will ask you the name of the key. If you want to change it (I strongly advise you not to do that) you need to give the full path here.
You may just hit Enter when asking for password.
After creating the key we need to copy the contents of the public key.
cat /home/ubuntu/.ssh/id_ed25519.pub
Go ahead and copy the text you see starting with ssh-
and ending with your e-mail (included).
Then go to https://github.com/settings/keys while logged in to Github then click New SSH Key
button. You can give a title and paste the copied text into the key field.
We now have given authorization to our remote machine to connect to our Github. But we need to connect to Github just once to mark the connection trusted in our remote machine. To do that we can clone the repository into the remote machine.
git clone git@github.com:T410/pm2-deploy.git
Of course, it will be your username and your repo name.
The console will ask you if you want to continue connecting. Type yes
end hit Enter.
Note: We cloned the repo into the user folder. /home/ubuntu for me. Now the full project path is
/home/ubuntu/pm2-deploy
. We will use this path to update theecosystem.config.js
file in the next step.
And now we are good to close the remote connection to the server.
Step 5: Configuring the ecosystem.config.js file
Now that we have a remote server up&running and have already pushed the project into our repository, we need to properly configure the ecosystem.config.js
file to tell PM2 where our project is, what to do with that, and where to push that.
The file will look like this:
Notice there are 2 sections we are exporting:
- apps
- deploy
The name
field in the apps
section is the name of our project which will be shown in PM2 process list.
The script
field is the script that PM2 will run when we deploy the project to the remote server. In this case, it will be the same as the main
field in the package.json
file.
The rest of the fields are pretty self-explanatory.
-
user
is the username that you use to connect to the remote server using SSH -
host
is the IP of the remote server -
path
where do you want your project to be deployed in your remote server? Remember we already cloned the repo into our remote server. We can go ahead and write that path here -
repo
is the repository URL in a format likegit:github.com:/user/repo.git
-
ref
is the reference branch. Which branch we want the remote server to pull -
key
is the LOCAL PATH of the key that we use to connect our machine using SSH -
"post-deploy"
takes commands which will be run at the remote machine after pulling the repo from Github
Step 6: Deploying
We have configured our machine and PM2. We can now deploy our project to the remote machine.
Before deploying we need to commit and push the changes we have made. After that, for the first run, we need to tell PM2 that it needs to setup the project.
pm2 deploy ecosystem.config.js production setup
With this command PM2 connects to the remote, clones the repo from Github. We can now deploy the project.
pm2 deploy ecosystem.config.js production
Now you are asking yourself: Now what?
Well, we didn't set up a server like nginx but we can test if the project is working or not with curl
. Of course, we need to connect to the remote machine before doing that.
curl http://localhost:3000
If you see the index.html output on the screen that's great news! You have done it!
And also you can list the apps PM2 running with this command
pm2 ls
Conclusion
We made great progress here. We learned how to deploy our project with just one command.
Here's the sample Repo:
Description
This is a sample project that demonstrates how to configure ecosystem.config.js
file for PM2 made for this tutorial
https://dev.to/t410/how-to-ci-cd-using-pm2-for-your-node-js-project-404f
I know I didn't tell you how to install nginx and serve the port we are using for our project but I will definitely do that in the near future and update here.
If you have any issues with anything, feel free to tell me what's wrong on the comments section.
Top comments (2)
This is really interesting, thanks!! I like to play with a very small VM I have in Vulture, and I wanted something really lightweight for CD.
However there's something I don't understand. It seems it is assumed that the ecosystem file will be in your local computer. In my case, I have the ecosystem file in the VM itself along with my apps. Do I still need to configure the ssh key for it to deploy in itself? Or is there some alternate configuration to tell it to deploy locally instead of in a remote server?
Thank you for your interest. Well, the ecosystem file contains the necessary information along with instructions for the machine that the app will run on. So if you want your VM to run the app with PM2, and no CD you can of course use ecosystem file without SSH configurations.
If you want to deploy the app and then run it on a remote VM without connecting to that VM from your local and physical machine then you can configure SSH information and PM2 will automate the connection, pulling from git, npm installing, running the app steps.
So you are letting PM2 do the deploying and running footwork. To deploy, PM2 needs an SSH key to connect to the remote machine. That SSH configuration part is essential for CD operations.
I hope this clarifies your question.