I'm trying to setup a Angular/NestJS project that uses docker. It's all working except if I reload the Angular frontend (admin) on any url other than /
it gives me a 404. I believe I need the try_files $uri $uri/ /index.html =404;
in location /
part of the default.config
file, but I can't figure out how to get it to work with proxy_pass
. Anyone get this to work or know the secret?
Folder Structure
my-project/ -> root
my-project/admin/ -> Angular Project
my-project/api/ -> NestJS API Project
my-project/default.config
upstream api {
server api:3000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
# Frontend
location / {
# root /usr/share/nginx/html;
# index index.html index.htm;
# try_files $uri $uri/ /index.html =404;
proxy_pass http://admin;
}
# Backend
location /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://api;
}
# You may need this to prevent return 404 recursion.
location = /404.html {
internal;
}
}
my-project/docker-compose.yml
version: "3.8"
services:
api:
container_name: api
build:
context: ./api
target: development
volumes:
- ./api:/usr/src/app
- /usr/src/app/node_modules
ports:
- ${SERVER_PORT}:${SERVER_PORT}
- 9229:9229
command: npm run start:prod
env_file:
- .env
networks:
- webnet
depends_on:
- redis
- postgres
admin:
container_name: admin
build:
context: ./admin
# target: development
# ports:
# - 80:80
networks:
- webnet
nginx-proxy:
depends_on:
- admin
- api
image: nginx:alpine
volumes:
- $PWD/default.conf:/etc/nginx/conf.d/default.conf
networks:
webnet:
ports:
- 80:80
redis:
container_name: redis
image: redis:6
restart: always
ports:
- 6379:6379
volumes:
- redisdata:/data
networks:
- webnet
postgres:
container_name: postgres
image: postgis/postgis
networks:
- webnet
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
PG_DATA: /var/lib/postgresql/data
ports:
- 5432:5432
volumes:
- pgdata:/var/lib/postgresql/data
networks:
webnet:
volumes:
pgdata:
redisdata:
my-project/admin/Dockerfile
# Stage 1: Compile and Build angular codebase
# Use official node image as the base image
FROM node:latest as build
# Set the working directory
WORKDIR /usr/local/app
# Add the source code to app
COPY ./ /usr/local/app/
# Install all the dependencies
RUN npm install
# Generate the build of the application
RUN npm run build
# Stage 2: Serve app with nginx server
# Use official nginx image as the base image
FROM nginx:latest
# Copy the build output to replace the default nginx contents.
COPY --from=build /usr/local/app/dist/my-project /usr/share/nginx/html
# Expose port 80
EXPOSE 80
my-project/api/Dockerfile
FROM node:12.13-alpine As development
WORKDIR /usr/src/app
COPY package*.json ./
RUN apk add --update python3 make g && rm -rf /var/cache/apk/*
RUN npm install
COPY . .
RUN npm run build
FROM node:12.13-alpine as production
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --only=production
COPY . .
COPY --from=development /usr/src/app/dist ./dist
CMD ["node", "dist/main"]
CodePudding user response:
The try_files
directive needs to be set in the Angular apps Nginx Docker component. The first Nginx instance does not have access to the Angular containers' filesystem, which it needs to check whether a file exists or not.
Create a Nginx configuration file, admin/nginx-config.conf
:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html =404;
}
}
Copy the file into your admin app container:
# Stage 2: Serve app with nginx server
# Use official nginx image as the base image
FROM nginx:latest
# Set custom Nginx configuration
COPY ./nginx-config.conf /etc/nginx/conf.d/default.conf
# Copy the build output to replace the default nginx contents.
COPY --from=build /usr/local/app/dist/my-project /usr/share/nginx/html
# Expose port 80
EXPOSE 80
You might have to change the ./nginx-config.conf
filename and path to match the one you created in your project.