Friendly URLs for your local apps with Docker and Nginx

Daniel Stoyanoff
3 min readAug 26, 2020

TL; DR;
This story is about going from localhost:8080 to app.local/.

Introduction

Perhaps you, like me, were having some issues to remember which app is on which port, remembering not to run app on a specific port as it’s already taken or just because you are annoyed by the auto-complete in the browser, based on history. For App A, the URL structure will be different than App B, which is annoying.

End Result

After some digging in relation to a new project, I’ve managed to setup the following infrastructure:

All those items are running inside docker containers, using docker-compose.

I am using Windows 10 as a host OS, but most of the things should be the same for other OSs.

Step by Step

Assuming you have docker installed and a basic knowledge on how to use it.

Step 1: Docker network
As a first step, we need to setup a local network for our docker containers. My requirement here was that I can setup the proxy ones and use it will multiple projects. I have named by network local and it is using bridge mode, so all projects, as well as the proxy, will be able to use the same network so they can discover each other. In order to do that, the following command should be executed.

$ docker network create -d bridge local

Step 2: Create the nginx-proxy container
For the next step, we will create a docker-compose file that will setup the proxy container. It’s important to reference the same network that we’ve created in Step 1. Everything rest is as-is from the nginx-proxy documentation.

We can start the container. Since it has a “hot-reload’ functionality, any container that we stop/start in future will automagically be updated in the nginx configuration.

$ docker-compose up -d

Step 3: Create the specific project’s docker-compose. Now that we have the nginx container running, we will setup an example project, again using docker-compose. As an example, we will run 3 containers — wordpress with MariaDB and react app with create-react-app. We will create a custom Dockerfile to run the react app and use ready images for the rest. The React Dockerfile is based on this tutorial — https://mherman.org/blog/dockerizing-a-react-app/

MariaDB will not be accessible from outside world, so nothing special should be done with it’s configuration. As for the rest, there are 3 important steps:

  • The port that the app runs on should be exposed (not necessarily mapped to a host port)
  • The same port should be added as an environment variable VIRTUAL_PORT as for some containers the port expose is not sufficient (this was the case with wordpress, while on the React app it worked even without it)
  • The VIRTUAL_HOST environment variable should be set to the Url that you want to use for that app.

In my case, since it’s the same project (and same docker-compose), I have decided to use the following pattern — {app}.{project}.local

We can then start this compose file

$ docker-compose up -d

Step 4: Hosts file
Unfortunately, the magic is not a full magic. We will need to map all Urls in hosts file to resolve using nginx.
The location of hosts file:

# Windows
C:\Windows\System32\drivers\etc\hosts # you need to edit as admin
# Linux
/etc/hosts # edit as admin
# Mac OS
/private/etc/hosts

We need to add 2 entries in our case (since we have 2 public services):

127.0.0.1 app.proj.local
127.0.0.1 wordpress.proj.local

Since our nginx works on port 80 of our host machine, we just resolve the Urls to localhost.

Step 5: Test
Now that we have finished all steps, just go to your browser and access the urls:

Conclusion

As you can see, the effort is not that big, but creates a serious difference in the developer experience. Once you go to your second project, just create it’s compose file and add the Urls to hosts file and voila!

--

--

Daniel Stoyanoff

Passionate about technology and architecture. #dotnet #react #typescript #grpc #microservices