How to Setup Proxy Server for ReactJS and Node on Heroku With Docker

This article will walk you step by step on how to setup a proxy on Heroku using Docker and Nginx. I will also show how to setup a simple frontend with create-react-app and a Nodejs server. All dockerized and running on Heroku.

As a heads up free Heroku apps take a while to start once they have fallen asleep, but this is happens only for free options. If you know a better free alternative, let me know!

Our final setup will look like this:

Image for post
Image for post

For this setup we will use two Heroku apps. One for backend and one for frontend.

React-Create-App

First, let’s make a React frontend that makes a simple request to the backend. Start by running create-react-app with the following command:

npx create-react-app my-react-frontend

This will create a new folder, with all the necessary boilerplate for a React project. Change into the folder created by create-react-app:

cd my-react-frontend

Then install all the dependencies with:

npm install

And start the development server with:

npm start

Now you should be running a React application on localhost:3000. If everything looks ok, let’s add a button to make a request.

Image for post
Image for post
Should look like this

Open up the file my-react-frontend/src/app.js and replace the contents with this:

When clicked the button will make a request to path “api/hello-world” and to whatever domain the frontend is running on. The “api/” part of the request is important.

Then you should have something like this:

Image for post
Image for post

If you press the button now, you will be flooded with a wall of text. Create-react-apps development server seems to respond with contents of the index.html file for some reason. It’s fine for now, so let’s move on to configuring our Nginx server.

Setup Nginx Configuration File

Next we will create the Nginx configuration file that will serve our React build and proxy its requests to our backend. For now, create this configuration file in the folder created by react-create-app.

Create a file named “default.conf.template”. Open the created file in your code editor. Then add:

server {
# Listen to port defined by Heroku
listen $PORT default_server;
}

The server block tells Nginx that we want to start a new server. The listen declaration tells Nginx on which port we want it to run on. $PORT variable will be defined later in a Dockerfile.

Then add the location property into the server block of code:

server {
# Listen to port defined by Heroku
listen $PORT default_server;

# Serve static files for requests made to /
location / {
root /usr/src/app/build;
}
}

This means that any requests made to “/” of our frontend server will be served static files from /usr/src/app/build within the Docker container.

Add another location declaration to the configuration, that will redirect traffic from our frontend servers /api path to “https://my-react-backend.herokuapp.com/;

server {

# Listen to port defined by Heroku
listen $PORT default_server;

# Serve static files for requests made to /
location / {
root /usr/src/app/build;
}

# Redirect requests made to /api
location /api {
proxy_pass https://my-react-backend.herokuapp.com/;
}
}

This is what our final configuration file should look like. Next lets dockerize it.

Dockerize Frontend

In order to deploy to Heroku we need to dockerize our frontend.There are definitely other ways, that might even be better and faster, but this is how I do it.

in root React project folder, create a Dockerfile. Note the capital first letter. Open it and add the following code:

First get default Nginx image from Docker hub by adding these lines to the Dockerfile you just created:

# Get Nginx image from Docker hub
FROM nginx

Then we want to copy our Nginx server configuration file into our docker image. We will create this configuration file soon:

COPY default.conf.template /etc/nginx/conf.d/default.conf.template

Then we need to add this monstrosity to make sure that our proxy server is running on the correct port on Heroku, and that the $PORT variable is defined. Kudos to RJoonas for this:

CMD /bin/bash -c “envsubst ‘\$PORT’ < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf” && nginx -g ‘daemon off;’

The above code will setup Nginx for our frontend app. Next we need to configure docker to build our React app.

Setup node by adding the following lines of code:

# Update available packages in Debian
RUN apt-get update
# Install curl cmd line tool
RUN apt-get install curl -y
# Fetch latest node v10.x from nodesource
RUN curl -sL https://deb.nodesource.com/setup_10.x -o nodesource_setup.sh
# Run setup script
RUN bash nodesource_setup.sh
# install nodejs and npm
RUN apt install nodejs -y

Then copy all of the React files into the Docker image and build your frontend inside Docker.

# Copy everything
COPY . .
# Do a clean install based on package-lock file
RUN npm ci
# Build frontend
RUN npm run build
# Expose port picked by Heroku. Otherwise we couldn't connect to the server running inside a docker container
EXPOSE $PORT

Now we are done with the Dockerfile! You can see what the final Dockerfile should look like here: https://github.com/Waltari10/proxy-tutorial-frontend/blob/master/Dockerfile

Before we build this, let’s tell docker to ignore the node_modules folder. We don’t want it copied, since we are installing node_modules inside the image. Create a “.dockerignore” file, and add the following contents:

**/node_modules

Congratulations! You now have dockerized the frontend! Now let’s make it run on Heroku.

Deploy Frontend to Heroku

If you haven’t already create a free account on Heroku. Then create a single free Heroku app. In this example the app has the name of “my-react-frontend”, but you will have to use something else, as Heroku app names have to be unique.

Select the Container Registry deployment method.

You will need Docker installed, so go ahead and install it. Then you will also need to install Heroku CLI.

Once you have Docker and Heroku CLI installed, run the following command to Login into Heroku:

heroku login

Then sign into the Container registry:

heroku container:login

Then the following command will build and push the image to Heroku. This will not make it available yet. This will take a while, especially on the first run, since nothing is cached yet.

heroku container:push web --app my-react-frontend

Finally we can release the app and see if it works!

heroku container:release web --app my-react-frontend

Press the “Open app” in the upper right corner in your browser in Heroku apps dashboard, and it should open the app. Free Heroku apps take a while to wake-up from sleep. Eventually you should see the familiar app!

Image for post
Image for post

There! Now you are done with the frontend side. Let’s move on to backend. It’s actually much simpler.

Setup Node Backend on Heroku

Now lets make a backend for the frontend to communicate with.

Make a new folder outside of your React project and move into it:

mkdir my-node-backend
cd my-node-backend

Initialise a new npm project with defaults:

npm init -y

Create a server.js file into your new folder and add the following code into the server.js file:

This creates a bare-bones server that responds with “Hello world!” to any requests made to “/hello-world” path. We aren’t using any node_modules for this.

In the package.json file add the start command to the scripts section. This will run the server.

"scripts": {
"start": "node server.js"
},

At this point you can try to run the server, by executing the following command:

npm run start

Open up browser at address: http://localhost:3001/hello-world

You should be greeted with: “Hello world!”.

Dockerize Node

Finally we want to dockerize our Node server to run it on Heroku. Do it by creating a file called “Dockerfile” and add the following content:

# Choose default image for dockerfile
FROM node:10
# Define the directory to which files will be copied to in the docker image
WORKDIR /usr/src/app
# Copy everything in current folder to /usr/src/app in Docker image
COPY . .
# Expose port picked by Heroku. Otherwise we couldn’t connect to the server running inside a docker container
EXPOSE $PORT
# npm run start
CMD [ “npm”, “run”, “start” ]

Deploy Node to Heroku

Create a new app on Heroku. In this example the app has the name of “my-node-backend”.

Then deploy to Heroku, by running the now familiar commands:

heroku loginheroku container:loginheroku container:push web --app my-node-backendheroku container:release web --app my-node-backend

Now if you go to address herokuapp.my-node-backend.com/hello-world

You should be greeted with “Hello world!” again.

If you do, congratulations! You now have successfully deployed a Nodejs backend to Heroku! If not, don’t worry! Shoot me a comment below, and I will help you debug!

We are now one block away from making the backend and frontend work together : )

Moment of Truth

Now open up your Frontend on Heroku and. Keep in mind that you might have to wait for the frontend to wake up before the site loads. When you press the “Say hello!” button the backend will start to wake up, so the request might take 10–20 seconds to complete. Patience is key!

If everything lines up perfectly, clicking the button should eventually add a big happy “Hello world!” under the button. This is a response from the backend server, through the proxy.

Image for post
Image for post
There are probably faster ways to print out Hello world.

Boom! The frontend and the backend now successfully communicate with each other. Now we can make a request between separate frontend and backend services, and not get blocked by CORS Policy.

Thank you for reading! Let me know if you have any questions. I am happy to help with anything, and try to improve this article : )

If you missed something here are the code repositories:

Also here are my running demo apps on Heroku

Sources/Read more:

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store