ingress-nginx doesn’t support CORS with multiple origins, this has been an issue for quite a while. If you just have one domain, you can use a simple two-line annotation to allow cors rules for this domain.

However, if you’ve got multiple domains (let’s say localhost for development and your own domain) and maybe even socket.io for websockets, try this in your ingress annotations block:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_origin ~* "http.?:\/\/(.*\.)?(localhost:8080|example\.com).*$") {
        add_header "Access-Control-Allow-Origin" "$http_origin" always;
        add_header "Access-Control-Allow-Methods" "GET, PUT, POST, OPTIONS" always;
        add_header "Access-Control-Allow-Headers" "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" always;
        add_header "Access-Control-Expose-Headers" "Content-Length,Content-Range" always;
      }
      if ($uri ~* "/socket.io/") {
        add_header "Access-Control-Allow-Origin" "" always;
      }

The snippet above checks if the origin request contains either the origin http(s)://localhost:8080 or http(s)://example.com. If it matches it’ll add the requested origin as a cors header, if there’s no match, no headers will be added.

The second if block is required for socket.io. If the url matches /socket.io/ it’ll just drop the cors header response from the socket.io client and sticks to the one defined earlier. Otherwise nginx would add a header, socket.io would add another header and we would get a response with two Access-Control-Allow-Origin headers. You don’t want that.