Ansible playbook to setup a NGINX Reverse Proxy and a NodeJS server

Hello everyone! I have been busy with work and studies so couldn’t write a blog for a while. In this blog we will look at how we can set up a basic NGINX Reverse Proxy and a NodeJS server using an ansible playbook. Please note that this is just a demo. In reality, the Reverse Proxy would normally be sitting in the DMZ. The NodeJS(or any other webserver) sits on an internal network. So the requests will have to go through the Reverse Proxy server in to the webserver.

However, in this setup we’re setting up both in the same server for demonstration purposes. You can download/clone the playbook from here: https://github.com/ihsanizwer/BasicNodeNginxPlaybook.git. Instructions on how to set it up to work on your environment is here: https://github.com/ihsanizwer/BasicNodeNginxPlaybook/blob/main/README.md. Follow the steps there and you should be able to run the playbook with ease. If you need to know a bit more about my ReactJS based Covid19 Dashboard and you want to set it up locally(manually), you can expand the ‘running it locally’ section in my previous blog here: Deploying and hosting node.js applications on Heroku – Take On Devops

Directory structure:

A sample initial output of successful playbook execution:

Some of the changes observed in the managed node after the playbook execution.

The ReactApp accessible from outside of the managed node after the execution of the playbook

Let’s go over some interesting things in this playbook.

  1. Yarn and Forever – Yarn is a package manager that is better than npm in many ways. Generally speaking speed and security is better in Yarn. Forever – I didn’t need to use this. But apparently, when you do a npm start or yarn start from within an ansible script, the script starts to hang at that point and doesn’t seem to complete. Forever fixes this problem and that is why we use it here.
  2. Jinja template based config – Here I have used a Jinja template for the NGINX custom configuration file. We are leaving the default configuration as is and copying over our template to the NGINX configuration directory. At the same time the values in the template file takes shape based on the variables we have defined. Though I haven’t used ansible facts, they too can be used in Jinja templates. You can compare the difference seen in the above screenshot of the custom config file with that of what’s in github.
  3. Run as many times as you want – As you may already know, Ansible is a Desired state language that is also idempotent. Let’s say you messed up some configuration in this NodeJS webserver/ reverse proxy server after the script was initially run. To fix this, simply run the playbook again. This will apply changes where necessary.
  1. Why so many variables? You may be wondering why there are so many variables for such a small playbook. That is because it may be used in the future. So that we can repurpose them. Suppose we write a large script, then we only need to change few places when we need to make a change and the change will reflect in multiple areas. It makes the script highly configurable.
  2. No DNS setup No problem – If you peak in to the inventory file you will notice ansible-host in there. This gives a human readable name for an IP if DNS is not setup. Or if DNS is setup but you want to call those hosts with different names. We can do this with DNS as well. But if don’t have access to make such changes, with very little effort, we can make them in the inventory file. Let me draw your attention towards the webservers group in the inventory file. You can add as many hosts as you want. All the hosts in that group will be managed this way. May need to consider using fork and serial if the number of hosts increase.
  3. Handlers – I have written handlers so that we can restart the NGINX service if the playbook changes anything related to NGINX.
  4. Credentials? Aside from the above, you’d see that there is another variable file under the group_vars directory. I have put the remote host credentials here. It is a good idea to encrypt this using ansible-vault to avoid any security issues.