How to (actually) configure CORS for preflight requests?

I've been at this for five days now ... can I have a configuration that just works?

My setup is a FastAPI + Traefik + Docker setup - a super simple setup that you can run on your own machine like so: https://github.com/mshajarrazip/fastapi-traefik-docker-cors. It doesn't even have TLS/SSL configured.

The issue is not with FastAPI - the CORSMiddleware module is working fine there. I got no CORS errors when making API calls without traefik as the proxy.

This is my docker-compose.yml file (am I doing something wrong with the labels?):

version: '3.8'

services:
  reverse-proxy:
    image: traefik:v2.9
    ports:
      - ${API_PORT}:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/etc/traefik/traefik.yml

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    expose:
      - 88
    labels: # new
      - "traefik.enable=true"
      - "traefik.http.routers.to_api.rule=Host(`basic.api`)"
      - "traefik.http.routers.to_api.middlewares=cors"
      - "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"
      - "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
      - "traefik.http.middlewares.cors.headers.accesscontrolmaxage=300"
      - "traefik.http.middlewares.cors.headers.addvaryheader=true"

I have a simple fetch call from an html file like this:

<html>
    <Button id="btnAddData" onclick="AddData();"> Add Data </Button>
</html>

<script>
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Host", "basic.api");

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  redirect: 'follow'
};

function AddData(){
  console.log("click");

  fetch("http://172.16.239.132:81/add", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
}
</script>

I got this error on the browser when I run the app behind a traefik proxy:

index.html:1 Access to fetch at 'http://172.16.239.132:81/add' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Curl and Postman works just fine:

curl -X 'POST' http://172.16.239.132:81/add -H 'Host: basic.api'

I am at my wit's end. I think this should be simple but maybe I'm bad at reading documentations but I can't find the solution anywhere :frowning: I was excited about using traefik in my company but this has become a major major major hurdle.

I'm convinced that this is not a FastAPI problem, so regardless of the framework used, the issue is at the traefik service itself. How did you guys make your setup work? Please share a super simple configuration that just works (for any origin, any methods) here. Thank you so much :frowning:

Only a browser is restricting according to CORS, curl does not care. Use curl -v and check your browser's developer tools' network tab for headers sent from Traefik.

And some info from stackoverflow:

Origin null is the local file system, so that suggests that you're loading the HTML page that does the load call via a file:/// URL (e.g., just double-clicking it in a local file browser or similar).

Most browsers apply the Same Origin Policy to local files by disallowing even loading files from the same directory as the document. (It used to be that Firefox allowed the same directory and subdirectories, but not any longer.

Basically, using ajax with local resources doesn't work.

1 Like

Hi bluepuma77! Thank you for the reply!

So I ended up putting my file on a server, but the fetch call still didn't went through.

And somehow as I was tweaking my rules, which was originally this:

- "traefik.http.routers.to_nac.rule=Host(`basic.api`) && PathPrefix(`/nac/`)"

And I changed it to this:

- "traefik.http.routers.to_nac.rule=Host(`nac.ml.api`) || PathPrefix(`/nac/`)"

It finally went through! D: I think I missed something about using || and && in the rules? Or is this a bug ...

Anyhow, if your services already applies CORS middleware, probably should do nothing on traefik side. Perhaps the problem is not a failing middleware, but something with how the rules are set up.