How to make backend accessible only from Frontend in Docker

Viewed 42

For my frontend, I have an angular application which consumes data from a node.js backend through an http call: http//server:3000.

With my current setup and config or a different setup if needed, how can restrict the backend from being accessible only to the frontend and inaccessible via any channel i.e it shouldn't be reachable by any Postman request or via browser etc but only reachable within the frontend app.

Dockerfile for the Frontend:

FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Dockerfile for the server:

FROM  node:lts-alpine
WORKDIR /server
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]

Docker-compose.yml:

services:

server:
  container_name: server
  image: server
  build:
    context: ./server
    dockerfile: Dockerfile
  volumes: 
    - ./server:/app
  expose:
    - '3000:3000'

client:
  container_name: commerce
  image: commerce
  build: 
    context: ./
    dockerfile: Dockerfile
  volumes: 
    - ./commerce:/app
  ports:
    - 8080:80
  depends_on:
    - server

I'm wholly unfamiliar with networking in docker so detailed suggestions would be much appreciated. Thanks in advance.

1 Answers

You can isolate the communication between server and client by using docker bridge network. According Docker Documentation: a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network.

I.e. Only services defined in docker-compose.yaml can reach backend server if they use defined backend bridge network, e.g. your client. Note! Server port is not mapped and exposed to be reached. You can reach your client from e.g. browser on 8080 as we map and expose it with ports: -8080:80 in docker-compose.yaml for client service.

Note! It only works if the requests are processed and sent from frontend container and not from browser.

version: '3.9'

services:

  server:
    container_name: server
    image: server
    build:
      context: ./server
      dockerfile: Dockerfile
    volumes: 
      - ./server:/app
    networks:
      - backend
  
  client:
    container_name: commerce
    image: commerce
    build: 
      context: ./
      dockerfile: Dockerfile
    volumes: 
      - ./commerce:/app
    ports:
      - 8080:80
    networks:
      - backend
    depends_on:
      - server
    
networks:
  backend:
    driver: bridge

You can reach backend server from client container with its service name, i.e. server. E.g.:

  1. Verify that you can not reach server from host e.g. in browser entering localhost:80
  2. Start both container with above docker-compose.yaml in detached mode.
docker-compose up -d
  1. Start a bash instance in client container.
docker exec -ti <image-name-or-id> bash
  1. Verify you can reach server with its service name and internal port number (i.e. within network bridge)
curl server:80
Related