Angular应用域名访问返回404,Docker容器内运行正常(Traefik环境)
问题
我是一名新手,正在用Docker、Traefik和GitHub Actions搭建Java+Angular Web应用的持续部署流水线,已经在Debian 12的VPS上部署成功,用Portainer管理,Traefik搭配Let's Encrypt处理HTTPS。
通过Cloudflare购买了域名,Traefik能正常做HTTP到HTTPS的重定向,服务器可通过HTTPS访问,但部署Angular应用到域名后,访问https://exemple.com始终返回404,虽然容器内用curl http://localhost:80能拿到正确的HTML内容,说明应用本身运行正常。
配置信息
1. Traefik栈配置
services: traefik: image: traefik:v2.5 command: - "--api.insecure=true" - "--api.dashboard=true" - "--providers.docker=true" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.dnschallenge=true" - "--certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare" - "--certificatesresolvers.myresolver.acme.email=myemail@example.com" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" - "8080:8080" environment: - CF_API_EMAIL=myemail@example.com - CF_API_KEY=${CLOUDFLARE_TOKEN} volumes: - "traefik-certificates:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock" networks: - web restart: always networks: web: external: true volumes: traefik-certificates:
2. Angular应用栈配置
services: front: image: mydockerimage:latest container_name: angular-front restart: unless-stopped networks: - web labels: - "traefik.enable=true" - "traefik.http.routers.angular.rule=Host(`exemple.com`)" - "traefik.http.routers.angular.entrypoints=web" - "traefik.http.services.angular.loadbalancer.server.port=80" watchtower: container_name: watchtower image: containrrr/watchtower environment: - WATCHTOWER_CLEANUP=true volumes: - /var/run/docker.sock:/var/run/docker.sock command: --interval 60 angular-front networks: web: external: true
3. Cloudflare配置
- DNS:
- A记录:指向VPS IP(开启Cloudflare代理)
- AAAA记录:指向域名IPv6地址(开启Cloudflare代理)
- CNAME记录:www子域名指向根域名(开启Cloudflare代理)
- SSL/TLS:Full(非严格模式)
测试结果
- 容器内执行
curl http://localhost:80返回正确HTML,应用运行正常 - 访问
https://exemple.com持续返回404错误
问题原因与解决方案
核心原因1:Traefik未配置HTTPS入口的路由规则
你的Angular应用只配置了web(80端口)的Traefik路由,但Traefik会自动把HTTP请求重定向到HTTPS(443端口,对应websecure入口),而websecure入口没有匹配exemple.com的路由规则,所以HTTPS访问时找不到对应的服务,返回404。
核心原因2:Angular单页应用的SPA路由 fallback 未配置(可选但关键)
Angular是单页应用,所有路由都由前端处理,服务器需要把所有非静态资源的请求都转发到index.html,否则刷新页面或直接访问子路由也会404(即使根路径能访问后,这个问题也会出现)。
解决方案步骤
步骤1:修改Angular应用的Traefik标签,添加HTTPS路由
更新Angular服务的labels部分,同时配置web和websecure入口,并且为HTTPS路由配置证书解析器:
labels: - "traefik.enable=true" # HTTP路由,负责重定向到HTTPS - "traefik.http.routers.angular-http.rule=Host(`exemple.com`)" - "traefik.http.routers.angular-http.entrypoints=web" - "traefik.http.routers.angular-http.middlewares=redirect-to-https" # HTTPS路由,实际处理请求 - "traefik.http.routers.angular-https.rule=Host(`exemple.com`)" - "traefik.http.routers.angular-https.entrypoints=websecure" - "traefik.http.routers.angular-https.tls.certresolver=myresolver" # 绑定服务 - "traefik.http.services.angular.loadbalancer.server.port=80" # 添加重定向中间件 - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
说明:把原来的
angular路由拆分为angular-http(负责重定向)和angular-https(实际处理HTTPS请求),确保HTTPS入口有对应的路由规则。
步骤2:配置Angular容器的SPA fallback(解决后续路由404)
如果你的Angular镜像用的是Nginx作为基础镜像,需要修改Nginx配置,添加SPA fallback规则:
- 在Angular项目根目录创建
nginx.conf文件:
server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # 静态资源直接返回 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } # 所有其他请求转发到index.html,让Angular处理路由 location / { try_files $uri $uri/ /index.html; } }
- 修改Angular的Dockerfile,把这个配置文件复制到Nginx的配置目录:
# 构建阶段省略... FROM nginx:alpine COPY --from=builder /app/dist/your-angular-project /usr/share/nginx/html # 复制自定义Nginx配置 COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
- 重新构建并推送镜像到你的仓库,让Watchtower拉取更新。
步骤3:验证配置
- 在Portainer中重新部署Angular应用栈
- 等待容器更新完成后,访问
https://exemple.com,应该能正常加载Angular应用 - 测试刷新页面或访问子路由(比如
https://exemple.com/dashboard),确认不会返回404
内容的提问来源于stack exchange,提问作者Etienne Pogoda

