I'm trying to Dockerize a classic NodeJS (Express, TS) Angular application using nginx, but I struggle binding correctly my api throught nginx.
In fact, it seems that nginx target my localhost:80...
...while I want it to target my localhost:3000
.
When I manually ping that url while adding :3000
after localhost
, it works.
I'm trying to keep my code simple. Here are my different files.
Back Dockerfile :
FROM node:15.14-alpine AS build
RUN mkdir -p /build/tmp
WORKDIR /build/tmp
COPY . .
RUN npm ci
CMD ["npm", "run", "start"]
Front Dockerfile :
### STAGE 1: Build ###
FROM node:15.14-alpine AS build
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
### STAGE 2: Run ###
FROM nginx:1.17.1-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /usr/src/app/dist/front /usr/share/nginx/html
dockercompose.yml :
version: '3.4'
services:
mymusicads-front:
container_name: mymusicads-front
build:
context: ./front
dockerfile: Dockerfile
ports:
- 80:80
restart: on-failure
depends_on:
- mymusicads-api
networks:
- front-back
mymusicads-api:
container_name: mymusicads-api
build:
context: ./api
dockerfile: Dockerfile
ports:
- 3000:3000
networks:
- front-back
networks:
front-back:
driver: bridge
nginx.conf :
events{}
http {
include /etc/nginx/mime.types;
upstream api {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name front;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
server {
listen 80;
server_name api;
location /api/ {
proxy_pass http://localhost:3000/;
proxy_redirect off;
}
}
}
Thanks !
EDIT :
By checking the error, we can see we're obtaining my Angular index.html file as a response, instead of the JSON object my API should return, which may signify an proxying error. Seems like nginx is missing the location /api/
instruction, or maybe the whole server
one.
CodePudding user response:
When you use multiple server
blocks in your configuration, nginx chooses the server block to process your request by the HTTP Host
header value. If it won't match any of the specified server names (or if the Host
header is absent at all), the default server block will be used. You can specify the default server block explicitly using default_server
flag for the listen
directive. If you don't specify it explicitly, the very first server block listening on the specific port will be used. See the How nginx processes a request official documentation page or this answer for even more details.
Try this configuration instead:
events {}
http {
include /etc/nginx/mime.types;
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://mymusicads-api:3000/;
proxy_redirect off;
}
}
}
You don't need to expose the node.js port 3000 to the outer world, it is only mymusicads-front
container that should have an access to that port. According to What is the difference between docker-compose ports vs expose SO thread your dockercompose.yml
file should be something like
version: '3.4'
services:
mymusicads-front:
container_name: mymusicads-front
build:
context: ./front
dockerfile: Dockerfile
ports:
- 80:80
restart: on-failure
depends_on:
- mymusicads-api
networks:
- front-back
mymusicads-api:
container_name: mymusicads-api
build:
context: ./api
dockerfile: Dockerfile
expose:
- 3000
networks:
- front-back
networks:
front-back:
driver: bridge