This is a small tutorial on setting up auto deployment of NodeJS apps so that your app is deployed automatically on your VPS when you push. This tutorial will use webhook.
Logging in to your VPS, pulling the changes and restarting your app every time you change something can sometimes be annoying. This method will help you automate that process. All you need to do is just push.
In this tutorial, I will use NodeJS v12 on a fresh Ubuntu 20.04 VPS and a very simple "Hello World" express app. But most of the things should work for you.
First of all, we will convert our node app to a "service". Our service will be very basic but you can add more stuff to it if you need them. This is what we will have for our use case:
[Unit]
Description=Express Hello World
[Service]
Type=simple
WorkingDirectory=/home/user/express-helloworld
ExecStart=/usr/bin/yarn start
Restart=always
First of all, in the Unit
group, we specify what our service is. You can put whatever you want in here.
Then in the Service
group, we define the service type as simple
. (Should be fine in most cases)
And then we specify our WorkingDirectory
. This is where the commmands will be executed from. Most of the time, it's your project's root folder.
Then we have ExecStart
that defines which command will be executed when this service starts. As I have a start
script added in my package.json
file, I simply set it to run yarn start
. And I set it to take yarn
from /usr/bin/yarn
. If you want to use node
directly and your main script is called app.js
, then you can set ExecStart
to /usr/bin/node app.js
and it should work fine.
Finally, setting the Restart
option to always
tells the system to restart this service if it crashes.
You can read more about this option here
If you've never written a service file before, you might be confused and/or wondering what you should do with the above.
The above text is a "service file" that defines the properties of a service. What you need to do is create a file in the /etc/systemd/system
folder of your VPS and put the content in there. You can call it whatever but the extension needs to be .service
. I will call mine express-hello-world.service
. So the file path is /etc/systemd/system/express-hello-world.service
.
After you're done with that, you need to execute the following command to make your service available:
sudo systemctl daemon-reload
Now to verify that your service has been created and is working properly, you can try the following command:
sudo service express-hello-world start # to start the service
sudo service express-hello-world status # to check the status of the service
If it says running
then it's all good.
If you already have an SSH key, you can skip this step.
To generate a SSH key, you can use the ssh-keygen
command.
It is going to ask you some questions. I usually accept the default values, they are fine in most cases as far as I know.
This will generate a new SSH key and save it inside the .ssh
folder of your user folder.
Then you will need to get the public key and add it to your GitHub account. To get the public key, you can use the following commmand:
cat ~/.ssh/id_rsa.pub
This command will print your SSH public key. Go ahead and follow the next step to add this key to your GitHub account.
If you already use SSH with GitHub, you can skip this step. Otherwise you can follow this guide to set it up.
We're almost there! Just a few more steps.
Installing webhook on Ubuntu is really easy. All you need to do is
sudo apt install webhook
Next, we need to write a script that webhook will run when something is pushed to our GitHub Repository.
A basic script would look like this:
#!/bin/bash
cd /home/user/express-helloworld # we go inside our project folder
git pull # we pull the latest changes
yarn # we install the dependencies
service express-hello-world restart # we restart our app's service
# if you need to run some more comands before restarting your app, you can put them
# before the restart command
Make sure you make the script executable by running chmod +x script.sh
.
I usually put this script in my /home/user
folder and call it update-PROJECT.sh
.
So in this case, I'll call it update-express-hello-world.sh
so the full path is /home/user/update-express-hello-world
.
Then we need to configure webhook. We need to give a config file to webhook. that defines what it will do when a request is sent on a specific path.
Below is a simple webhook config:
[
{
"id": "update-express-hello-world",
"execute-command": "/home/user/update-express-hello-world.sh",
"command-working-directory": "/home/user/"
}
]
Now, assuming webhook is running on port 9000 and your VPS has the IP Address 101.22.33.44
, if a HTTP request is sent to http://101.22.33.44:9000/hooks/update-express-hello-world
, webhook will go to the command-working-directory
of the update-express-hello-world
hook, which is /home/user/
and then run the /home/user/update-express-hello-world.sh
script which will pull the changes, install the dependencies and restart our app.
Save the webhook config file as /etc/webhook.conf
and then restart webhook with the following command:
sudo service webhook restart
Again, you can check the status of the webhook service as mentioned at the bottom of this section
Finally, we reached the last step, whew!
What we need to do in this step is very simply visiting our repository on GitHub and go to the Settings
tab.
Then we need to click the Webhooks
section which you can find on the left.
After that, we need to click on the Add webhook
button.
GitHub might ask for your password at this step, enter the password to proceed.
The Payload URL is basically http://VPS_IP:WEBHOOK_PORT/hooks/HOOK_ID
where VPS_IP
is the IP address/domain name of your VPS, WEBHOOK_PORT
is the port webhook
is running on (9000
by default) and HOOK_ID
is the id of your hook that you set in the webhook config file in this step
You can leave the other fields as they are and click on Add webhook
.
Now you can test the webhook. Simply commit and push to your repository and it should be updated on your VPS.
If you have any questions, feel free to comment here, I'll try my best to reply. Thanks and happy coding!