POST Nginx Rewrite CORS and lost POST body

This problem is driving me demented, and any help would be appreciated I am refactoring a local development area from jwilder/nginx-proxy to Traefik. The architecture involves several docker containers:

  • Traefik
  • Nginx
  • Node (VueJS)
  • PHP
  • ...

The Nginx setup has a rewrite block, and then processes the rewritten request in PHP:

server {
    ....
    add_header 'Access-Control-Allow-Origin' "*";
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUSH, PUT';
    add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since';

    location / {
        if ($request_method = 'OPTIONS') {
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'application/text charset=UTF-8';
            add_header 'Access-Control-Max-Age' 1728000;
            return 204;
        }
    }

    location ~ ^/(?!(index.php)) {
        rewrite ^/(.*)$ /index.php?request=$1 last;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_index index.php;
        fastcgi_pass php:9000;
    }
    ....
}

The pre-flight from the VueJS works fine (POST request), but then the final request has an empty body, so the code that processes the request cannot proceed.

This was working fine with the old reverse proxy and in production environments, so the nginx config should be fine. Has anyone had issues with Traefik and lost POST body, is there perhaps some config I need to put into Traefik, or rewrite the call in a different way in Nginx?

In a Traefik forum it probably makes more sense to post your Traefik static and dynamic config when seeking help :slight_smile:

Agreed, I just didn't want to overload the initial question with too much data. Here it is:

Docker excerpt:

version: '3.7'

services:

  # Node container
  admin:
    container_name: "${APP_NAME}-admin"
    build:
      context: .
      dockerfile: "config/docker/Dockerfile-node"
    labels:
      - traefik.enable=true
      - traefik.docker.network=apiopenstudio_docker_dev_default
      - traefik.http.routers.admin.rule=Host(`${ADMIN_SUBDOMAIN}.${DOMAIN}`)
      - traefik.http.routers.admin.tls=true
      - traefik.http.services.admin.loadbalancer.server.port=8081
      - traefik.webservice.admin.entryPoints=http,https,ws,wss
#      - traefik.http.middlewares.cors.headers.customResponseHeaders.Access-Control-Allow-Origin=*
#      - traefik.http.middlewares.cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,DELETE,PUSH,POST
#      - traefik.http.routers.admin.middlewares=cors

    ports:
      - "8081:8081"
    volumes:
      - ${ADMIN_CODEBASE}:/app:rw
    networks:
      - default

  # NGINX API server.
  api:
    image: nginx:stable
    container_name: "${APP_NAME}-api"
    ports:
      - "8082:80"
    volumes:
      - ./config/nginx/api.conf:/etc/nginx/conf.d/default.conf:ro
      - ${API_CODEBASE}:/var/www/html:rw
    depends_on:
      - php
      - db
    labels:
      - traefik.enable=true
      - traefik.docker.network=apiopenstudio_docker_dev_default
      - traefik.http.routers.api.rule=Host(`${API_SUBDOMAIN}.${DOMAIN}`)
      - traefik.http.routers.api.tls=true
#      - traefik.http.middlewares.cors.headers.customResponseHeaders.Access-Control-Allow-Origin=*
#      - traefik.http.middlewares.cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,DELETE,PUSH,POST
#      - traefik.http.routers.api.middlewares=cors
    networks:
      - default

  # Reverse Proxy.
  traefik:
    image: "traefik:${TRAEFIK_VERSION}"
    container_name: "${APP_NAME}-traefik"
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker=true
      - --providers.file.directory=/etc/traefik/dynamic_conf
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/proxy/static.yml:/etc/traefik/traefik.yml:ro
      - ./config/proxy/dynamic.yml:/etc/traefik/dynamic.yml:ro
      - ./config/certs/_wildcard.apiopenstudio.local+3.pem:/etc/certs/apiopenstudio.local.pem:ro
      - ./config/certs/_wildcard.apiopenstudio.local+3-key.pem:/etc/certs/apiopenstudio.local-key.pem:ro
      - ./logs/traefik:/var/log:rw
    networks:
      - default

static.yml

global:
  sendAnonymousUsage: false

api:
  dashboard: true
  insecure: true

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    watch: true
    exposedByDefault: false

  file:
    filename: /etc/traefik/dynamic.yml
    watch: true

log:
  level: DEBUG
  filePath: "/var/log/error.log"

accessLog:
  filePath: "/var/log/access.log"

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"

dynamic.yml

http:
  routers:
    traefik:
      rule: "Host(`traefik.apiopenstudio.local`)"
      service: "api@internal"
      tls:
        domains:
          - main: "apiopenstudio.local"
            sans:
              - "*.apiopenstudio.local"

tls:
  certificates:
    - certFile: "/etc/certs/apiopenstudio.local.pem"
      keyFile: "/etc/certs/apiopenstudio.local-key.pem"

You can’t mix Traefik command and static traefik.yml file, which contained static config like entrypoints. Decide for one.

See simple Traefik example.