Expose Your Local Dockerized Node Server to the Web with Ngrok
Run your node server locally with Docker & Ngrok while enabling to communicate with 3rd party services and other devices
Tuesday, Dec 15, 2020
The problem
Let's say you're working on your local development server and encounter the need to test your environment from a different machine other than the one your working on which... is also on a different network.
Or that your local server is dependent on a 3rd party service and that API needs a longer time to process and send results back to your server via a callback interface.
The list can go on.
Trying to expose your local server running on http://localhost:${PORT}
to the public internet can be a pain.
Local tunneling services such as ngrok allow you to expose your local server to the public internet in a secure fashion.
The Solution ~ What we will build
We'll be using:
- Docker to containerize our server environment.
- In the docker config, install ngrok and the dependencies for our node server.
- Then we'll be using the ngrok npm package to create a connection in the application and get the forwarded DNS address to be accessible to the web.
- We can then pass that address/url to the other API's and recieve the results back on our local machine.
Project Setup (If starting from scratch)
Create project Directory
cd or re-open vscode new directory as project root
Create package.json
Install Dependencies
Install Development Dependencies
Docker Setup
Create in the project root
Dockerfile
Brief DockerFile rundown,
- We start from a node image of
12.18.1
- Install ngrok within the container
- Create our working directory and install our npm modules (as if setting up our project from scratch)
- Set our environment variables we can access in the node runtime via
process.env.*
- Expose the docker container to be accessible via Port
8080
. - Finally start the node server
Create in the project root
.dockerignore
The .dockerIgnore behaves as a .gitignore. Since we install our npm modules each time we build our Docker image, we want to ignore the existing modules from our image. Which will greatly reduce the size of the image as well.
Create our application server
index.js
Basic boilerplate node/express server, if the process.env.LOCAL
environment variable is set, we require ngrok helper module mentioned below and use the ngrok service to expose the application to the web and assign a dynamic DNS record.
Helper function to expose our server
exposeServer.js
This is a helper async function that requires the ngrok
npm package that gives us a javascript based API to interact with ngrok's services. We give it a port, and it will assign a DNS that any computer on any network can access. This will only work if the ngrok executable is installed on the machine (Installed as part of our Docker Image)
Update package.json Scripts
package.json
*Since we opted to not use docker-compose
, building and starting the docker image/container can get tiring to type in manually. Just run npm run docker
, which will remove the old image, build the new updated image and finally run the container.
Test access to the Dockerized Node Server
Go ahead and run npm run docker
After the image is built and the container has started, should see the following logged to the console.
Go to your browser on another device and navigate to https://*.ngrok.io
and should receive back a response of Hello World!
Work with a 3rd Party API Callback
Since your node application has access to this ngrok address in the application layer, it can pass this information to an API/Service.
This scenario is usually necessary for requests that take a long time to process, and requires setting a callback endpoint of where to send the results back to.
Unfortunately, not aware of any public API's out there that have a callback interface to send results back to but here's a bit of pseudo-code.
Conclusion
This is just one way to run your environment locally if this was a barrier to do so previously. You do not need to use docker with ngrok, but if you're familiar with docker it's an added convenience. Hopefully, this helps you as it has helped me. Cheers!