如何使用Nginx与Traefik为同域容器化Angular应用配置多路径静态服务?
同域名多Angular容器Traefik部署修正方案
部署要求
- 同一域名下按URL路径分流到对应容器
- 根路径
/的所有请求路由到app1容器 /test及所有子路径(如/test、/test/page1)全部路由到app2容器- 分流规则不干扰Angular自身的前端路由逻辑
现有配置核心问题
- Traefik路由匹配优先级混乱:app1的路由规则仅绑定域名,未限定路径范围,会拦截所有请求,优先级高于app2的
/test路径规则,导致请求全部被导向app1 - app1中间件配置错误:
stripprefix配置为剥离/前缀,属于无效规则 - app2容器内部Nginx配置不匹配:Traefik会剥离
/test前缀再转发请求到容器,容器内收到的路径不带/test标识,但原Nginx配置将/test作为匹配条件,无法命中静态文件 - 缺少前端路由兜底规则:刷新Angular内部的二级路由路径时会返回404
- 未配置Angular部署前缀:Angular默认从站点根路径加载静态资源,部署到
/test子路径时会出现静态资源加载失败
修正后的完整配置
Angular构建参数调整
- app1部署在站点根路径,无需额外调整构建参数
- app2部署在
/test子路径,构建时必须指定base-href参数,保证静态资源加载路径正确:ng build --output-path=dist --base-href=/test/
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" # 排除/test开头的路径,避免拦截app2的请求 - "traefik.http.routers.app1.rule=Host(`localhost`) && !PathPrefix(`/test`)" - "traefik.http.routers.app1.entrypoints=web" - "traefik.http.routers.app1.middlewares=app1-autodetect" - "traefik.http.middlewares.app1-autodetect.contenttype.autodetect=false" # 设置较低优先级,保证/test路由优先匹配 - "traefik.http.routers.app1.priority=10" - "traefik.port=80" app2: build: context: ./app2 # 传入构建参数,指定Angular的base-href args: BASE_HREF: /test/ ports: - "8082:80" labels: - "traefik.enable=true" # 匹配/test及所有子路径 - "traefik.http.routers.app2.rule=Host(`localhost`) && PathPrefix(`/test`)" - "traefik.http.routers.app2.entrypoints=web" - "traefik.http.routers.app2.middlewares=app2-stripprefix" - "traefik.http.routers.app2.middlewares=app2-autodetect" # 转发请求到容器前,剥离/test前缀 - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/test" - "traefik.http.middlewares.app2-autodetect.contenttype.autodetect=false" # 设置较高优先级,保证/test路径优先被命中 - "traefik.http.routers.app2.priority=100" - "traefik.port=80"
关键调整说明:
- 移除app1原有的错误stripprefix中间件
- 显式设置路由优先级,避免泛匹配规则拦截精准路径请求
- 简化app2的路径匹配规则,删除冗余正则表达式
Nginx配置
两个应用的Nginx配置均需补充前端路由兜底规则,避免刷新二级路径404
app1的nginx.conf
include /etc/nginx/mime.types; server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html index.htm; # 兜底所有前端路由请求,找不到文件时返回根目录的index.html location / { try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
app2的nginx.conf
include /etc/nginx/mime.types; server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html index.htm; # 容器收到的请求已被Traefik剥离/test前缀,直接匹配根目录文件即可 location / { try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
关键调整说明:
- 删除app2原配置中
location /test的匹配规则,适配Traefik的前缀剥离逻辑 - 增加
try_files规则,支持Angular前端路由的正常运行
通用Dockerfile配置
# 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/cli@11.0.7 # add app COPY . /app # 接收构建参数,指定Angular的base-href ARG BASE_HREF=/ RUN ng build --output-path=dist --base-href=${BASE_HREF} # 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;"]
验证逻辑
- 访问
http://localhost/,返回app1的页面内容 - 访问
http://localhost/test,返回app2的页面内容 - 访问
http://localhost/test/page1,仍路由到app2容器,app2内部前端路由可正常跳转、刷新 - 访问
http://localhost/page1,路由到app1容器,app1内部前端路由可正常跳转、刷新
内容的提问来源于stack exchange,提问作者Kagen Fontenot
相关产品推荐
相关产品推荐

