What I’d like to do is have 2 Angular apps on the same domain, but serve different files for different paths. For example, browsing to “app1/” will show different content than that on the “app1/test” path. Note: these are default Angular apps, they’re not doing anything special. The only thing I’ve changed the landing page to say “app1” or “app2” to verify that paths hit the correct container.
Additionally, I want anything on the app1/test path to resolve to the same host. So paths like “app1/test” and “app1/test/page1” will lead to the same container. I can get to app1/ with no issues, but I can’t seem to figure out how to route to app1/test correctly. I can browse to it, but it serves the content of app1/ instead of what it’s supposed to. I’ve verified that all of the files I’m creating are inside the container as well, they’re just not being accessed.
Finally, the URL information needs to be in a state that allows nginx to route to the correct container and also allow the angular apps to handle its own virtual routing, without these two interfering with one another.
Here are my config files:
docker-compose.yml
services:
traefik:
image: "traefik:v2.4"
container_name: "traefik"
command:
- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
app1:
build:
context: ./app1
ports:
- "8081:80"
labels:
- "traefik.enable=true"
- "traefik.http.routers.app1.entrypoints=web"
- "traefik.http.routers.app1.rule=Host(`localhost`)"
- "traefik.http.routers.app1.middlewares=app1-stripprefix"
- "traefik.http.routers.app1.middlewares=app1-autodetect"
- "traefik.http.middlewares.app1-stripprefix.stripprefix.prefixes=/"
- "traefik.http.middlewares.app1-autodetect.contenttype.autodetect=false"
- "traefik.port=80"
app2:
build:
context: ./app2
ports:
- "8082:80"
labels:
- "traefik.enable=true"
- "traefik.http.routers.app2.entrypoints=web"
- "traefik.http.routers.app2.rule=Host(`localhost`) && PathPrefix(`/test{regex:$$|/.*}`)"
- "traefik.http.routers.app2.middlewares=app2-stripprefix"
- "traefik.http.routers.app2.middlewares=app2-autodetect"
- "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/test"
- "traefik.http.middlewares.app2-autodetect.contenttype.autodetect=false"
- "traefik.port=80"
Dockerfile for both Angular apps
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /app/package.json
RUN npm install
RUN npm install -g @angular/[email protected]
# add app
COPY . /app
# generate build
RUN ng build --output-path=dist
# base image
FROM nginx:1.16.0-alpine
# copy artifact build from the 'build environment'
COPY --from=build /app/dist /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
# expose port 80
EXPOSE 80
# run nginx
CMD ["nginx", "-g", "daemon off;"]
nginx.conf for app1
include /etc/nginx/mime.types;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
nginx.conf for app2
include mime.types;
include /etc/nginx/mime.types;
server {
listen 80;
server_name localhost;
location /test {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
2
Answers
I solved my problem. There were a few edits I made along the road, but the final key to the puzzle was a "try_files" line in my nginx.conf files. Read about it here: https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
Here are the updated files:
docker-compose.yml
Dockerfile (for app1)
Dockerfile for app2
nginx.conf for app1
nginx.conf for app2
You should serve from subdomains which are more easily manageable, there is a general accepted pattern sandbox|dev|test|staging.example.com, example.com being production.
You’d be able to route properly in the whole stack (reverse proxy, web server, angular), drop cookies, manage separate identities etc.
Unfortunatelly what you are experiencing happens because the lack of negation in traefik’s routing rules but also in regular expression used to describe the routing. Basically the 1st router is taking over, Host(‘localhost) in a greedy way.
What you can do is follow Traefik’s docs and try to set a priority:
see section Set priorities — using the File Provider at
https://doc.traefik.io/traefik/routing/routers/#priority