• Skip to main content
  • Skip to primary sidebar
  • Skip to footer

Alex Aitken

Technical and Engineering Leadership, Coaching, and Mentorship

Getting Docker, React, .NET Core, Postgres, and Nginx Playing Nice

August 14, 2024 By Alex Leave a Comment

I wanted to write a short article on how to get all four components working so you don’t need to install a bunch of libraries on your machine. The reason I’m doing this is so that I can work on my frontend, backend, and SQL independently. The Nginx acts as a reverse proxy for my services.

When I was using my Google Foo to find the solution, it seemed like there was no single place where the answer lay. There were explanations for all sorts of different scenarios but not like mine. As well, I also did some updates over time (and switched technology i.e. NodeJS to ViteJS) which broke things (like ports and mappings).

One of my requirements was that the front end also recompile every change so I don’t need to restart the Docker engine. I also want to do this for the back end, but I haven’t invested the time yet. The other requirement that I had was that I wanted separate repositories for frontend, backend, and proxy. There is no practical reason behind this other than my wanting some clean system design.

ViteJS + React

Firstly, this is a really simple setup. We first just take NodeJS from Docker, change the working directory, copy the package.json, install the packages, and then copy everything, exposing the public port from ViteJS and finally running our dev server.

FROM node:18-alpine

WORKDIR /app

COPY package.json .

RUN yarn install

COPY . .

EXPOSE 3000

CMD [ "yarn", "dev" ]

What you may notice is that this won’t mount the local drive. So if you run this docker, you’ll need to restart to compile any changes. The fun comes when we use our docker-compose script.

.NET Core

Again, we have a simple script that’s pretty much derived from the examples online. First, we build using the build environment and then we run using the runtime environment. In this scenario, the port we want to expose is port 8080 (depending on your .NET config/version). Most likely, because we are publishing our app, it will be the default.

# Learn about building .NET container images:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build

WORKDIR /source

# copy everything
COPY . .
RUN dotnet restore --use-current-runtime

# copy everything else and build app
RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
EXPOSE 8080
WORKDIR /app
COPY --from=build /app .
RUN ls -al
ENTRYPOINT ["dotnet", "Your.Library.dll"]

Again, you can run this locally. It should have your .NET Core app up and running with no problems. But will they be playing nice? And how to make it like a production setup whereby you want to have the same address but a different path. That’s where the nginx comes in.

Nginx

For nginx docker, you don’t need to do much. Just copy over the config file.

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

How does that config file look?

server {
    listen 80;
    server_name localhost;

    location /api/ {
        proxy_pass http://api:8080/;
    }
    
    location / {
        proxy_pass http://app:3000;
    }
}

Again, you can run this locally but it won’t do anything yet. That’s where we need our magic docker-compose file.

version: '1.0'
services:
  api:
    build: 
      context: ../Path/to/.net/app/.
      dockerfile: Dockerfile
    ports: 
      - 3001:8080
  app:
    build: 
      context: ../Path/to/react/app/.
      dockerfile: Dockerfile
    ports: 
      - 3000:3000
    volumes:
      - ../path/to/react/app:/app
      - /app/node_modules/
  proxy:
    build: 
      context: .
      dockerfile: Dockerfile
    ports: 
      - 8080:80
    depends_on:
      - app
      - api
  db:
    image: postgres:15.7
    restart: unless-stopped
    volumes:
      - ~/apps/postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
    ports:
      - '5432:5432'

Ok, so let’s look at what’s going on in here as it’s a little complex. Firstly, with docker-compose, we can see there are several services. The first service is what I’ve called the API, or the .NET Core app. According to our nginx.conf, this is mapped to /api/ and port 8080. What I found out was that you need to use the internal ports when accessing the Docker network from a service within. The external ports can be used by your browser or headless rest client to access.

 api:
    build: 
      context: ../Path/to/.net/app/.
      dockerfile: Dockerfile
    ports: 
      - 3001:8080

Digging deeper into the API, we can see the port I expose is 3001 (as per my diagram) and it’s mapped to port 8080 (the default .NET Core port that’s listening). For how to build the Docker image, we’ve given some context like where the path is and what the docker file is (in case you have different production/dev docker files).

app:
    build: 
      context: ../Path/to/react/app/.
      dockerfile: Dockerfile
    ports: 
      - 3000:3000
    volumes:
      - ../path/to/react/app:/app
      - /app/node_modules/

Next is the app, or the React + ViteJS application. Again, we give it some context of how to build it and where the docker file is. We also give it a port, this time I’ve just mapped it to the same port (3000). The only difference here is the volumes. These allow you to mount local directories/paths to directories/paths inside of the docker instance. In this case, we have mounted our local path to the old app path. But we are not loading the node_modules again. This allows for ViteJS and/or any other framework to do the hot reloading on changes.

proxy:
    build: 
      context: .
      dockerfile: Dockerfile
    ports: 
      - 8080:80
    depends_on:
      - app
      - api

Here you can see the standard context on how to build the docker file for this service. You can see we expose port 8080 as our public port for the reverse proxy. Lastly, I’ve added depends_on as these are the two services that this reverse proxy needs to run.

I’m not going to go into Postgres as that’s pretty much the default setup with some username/password combo you should not use for production.

And that’s it. All you need to do is run docker compose up --build and it will do the heavy lifting for you. No need to install additional .NET libraries or JS libraries if you are just developing on one side of the project.

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook

Like this:

Like Loading...

Related

Filed Under: Coding

Alex

Reader Interactions

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

About the author

Alex is an AVP of Engineering currently working at Bukalapak. He is a leader in full-stack technologies. Read More…

Pages

  • Speaking Experience
  • About

Social Profiles

  • LinkedIn
  • Medium
  • ADPList

Recent Posts

  • Interviewing as an Engineering Leader
  • Managing Low Performers
  • Getting Docker, React, .NET Core, Postgres, and Nginx Playing Nice
  • What Makes a Good Software Engineering Manager?
  • “Am I There Yet?” Said an Engineer

Archives

  • January 2025
  • August 2024
  • July 2024
  • October 2023
  • August 2023
  • October 2020
  • May 2020
  • February 2020
  • June 2019
  • March 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • January 2018

Categories

  • Coding
  • Essay
  • Leadership
  • Management
  • Roundtable
  • Strategy

Footer

Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy

Copyright © 2025

 

Loading Comments...
 

    %d