Here you are — you spent days and nights trying to create your website which is awesome and solves the problems of the future. But now, you need to figure out how to deploy it. While you can use services like Heroku to deploy applications, in this example we will see a basic way of dockerizing your application and using nginx.

Packaging the Application

While running locally on our machines, we always need a dev server which can hot reload and serve the transpiled code. This is true whether it is React JSX files being transpiled to JS or Angular TypeScript files which are compiled to JS.

But when deploying to the server, we do not need any transpilation as it no longer requires any changes and all the final code is ready to be shipped. In this case, we simply need to generate our distribution-ready static files and something that can serve these static files. In our case the something is nginx. You can learn more about nginx here.

One might then wonder, where does Docker fit in? What do we mean by dockerizing our application? In very few words, we are using Docker to avoid having to install and reinstall nginx (or any other system level dependencies) on every server we deploy our application. Learn more about Docker here.

For this article, we will be using this demo application which makes a simple HTTP request and logs the response to the console. First let us go ahead and create the distribution files for the project. Since this is an Angular project, we will use the CLI commands to build the project.

npm run build

Based on the type of project, you will see a dist / build folder which in our case will take the following structure:

Creating Dockerfile

Now that the application is packaged, we will create a simple Dockerfile which will copy over the contents of the dist folder to the html folder of nginx which was downloaded as a part of our image.

In the above Dockerfile we are just specifying that our base image is nginx which is available here and then we are replacing the default nginx html page with our content. There are other things which we can add here so that nginx can proxy our requests to our custom backend which we will discuss in last section.

Build Image

To build the image i.e. the packaged code on top on nginx, we can do it using the following command:

docker build --rm -f Dockerfile -t httpclient:latest .

We are explicitly specifying the Dockerfile which we want it to use (it will pick the file with this filename by default anyway, you can rename it if you want to) and then we are specifying the image name httpclient:latest and the last . specifies that we want to build everything in this project.

Once we run the command we would see the response as below:

To verify that the image is created, we can check by running the command docker images and we see the outcome as below:

Run Image

Now that we have the image ready, we are going to run it using a simple command

docker run --rm -d -p 9999:80 httpclient:latest

We are running the docker image that we just created and we are specifying the port mapping with the -p parameter. We know that nginx exposes port number 80, we want to map it to the port 9999 on our machine. So when our browser tries to access port 9999 the request would be forwarded to the port 80 that is running within our image.

To test the application, open http://localhost:9999 on your browser and you would see the application running as expected.

Proxy Backend APIs

In the sample application we are pointing to a 3rd party server to get the data which allows cross origin requests. But that is not recommended for production backend applications and if you are running your UI and backend separately then you would want to proxy the requests as well. To set up the proxy, nginx provides a config file which can hold the necessary configuration for us and forward the requests as defined. A simple example of this file would look as follows:

We are simply forwarding the requests starting with /api/ to the backend server and everything else such as the UI page requests back to the index page since the routing is handled by SPAs themselves.

To tell nginx to pick our nginx configuration instead of the default, we just modify our Dockerfile to pick our configuration file instead.

The next time we build the image, the nginx config would get copied over to the image. Everything else like the way images are built and run remain the same as explained above.

Conclusion

Now that the application is running as expected, next step would be to use some cloud service such as AWS, Azure, or Google Cloud to save your image on an image repository, spin up a server and run your image on it.

Full code sample is available here.