Cannot communicate backend and frontend on Docker

Viewed 50

I have two projects I have to dockerize, I suspect there is a problem between nginx port-forwarding, I am newbie on this subject and the Dockefiles are the following:

// Dockerfile NodeJS (Backend)

FROM alpine as node-build
RUN apk add --update nodejs npm
WORKDIR /app
COPY . .
RUN npm install

CMD [ "node", "server.js" ]

// Dockerfile Angular (Frontend)

FROM node:16-alpine as frontend
WORKDIR /app
COPY . .
RUN npm install
RUN npm run frontend

FROM nginx:alpine
COPY --from=frontend /app/dist/frontend /usr/share/nginx/html

// Docker compose

version: '2.0'
services:
  backend:
    build:
      context: './backend'
    ports:
    - "3000:3000"
  frontend:
    build:
      context: './frontend'
    ports:
    - "4200:80"

//Proxy on frontend (/frontend/proxy.config.json)

{
  "/enviroment/*":{
    "target": "http://localhost:3000",
    "secure": false,
    "loglevel": "debug"
  }
}

How can I make them communicate between?

1 Answers

Inside the Docker environment named "frontend", localhost refers to the container named "frontend", not to the Docker host (your server / local computer). It's on a separated network from its host. Segregating containers from each other and the host is a big part of containerization.

You could have Angular pass the request to your server / local computer, by connecting to its 'gateway IP address', but there is a better way: have Angular's proxy talk to the backend server. It's on the same network.

Docker Compose makes this easy by making every service available to containers in the same docker-compose.yml under a hostname, named identical to the service name:

{
  "/enviroment/*":{
    "target": "http://backend:3000",
    "secure": false,
    "loglevel": "debug"
  }
}

Likewise, you could go into the container named "backend" and ping the hostname frontend.

You do not need to forward ports to do this, just like how you don't need to port forward within your home LAN. If you wanted to, you could remove the "3000:3000" mapping and Angular would still be able to communicate to backend:3000 (but of course, then you wouldn't be able to do access localhost:3000 from your own computer, which is not on the network Docker-compose has set up).


Having said that, your Dockerfile doesn't start the proxy process and the proxyconfig.json file isn't used at all.

You have a couple of options:

  1. Run the development proxy in production (bad idea).
  2. Run the backend on a domain (api.example.com) and the frontend on another (example.com) and change your app to load API requests from https://api.example.com. Easy to do although you need to worry about CORS.
  3. You're using nginx to serve your static assets. It can also, just like the development server, proxy requests. In this case to your API.

If all requests to your API start with /api you could just do this:

location / {
  # Any URL that isn't found falls back to the index page.
  # That way if you browse to example.com/about-us,
  # the index.html page is loaded, not a 404.
  try_files $uri $uri/ /index.html;
}
location /api {
  # A request like /api/users is forwarded to the backend.
  proxy_pass http://backend:3000;
}

# If you don't want the backend to receive "/api/users" but
# "/users" then this should work:
# location /api/ { proxy_pass http://backend:3000/; }
# (Note the two new trailing slashes.)

You might need to add more settings, such as a client_max_body_size if you have uploads. That's all specific to your app and out of scope for this single answer. The documentation on Angular deployment has a lot of information, not all of it relevant to your use-case, but it's worth a skim.

Related