CORS (405) Failing - Caddy Reverse Proxy

1. The problem I’m having:

Caddy is acting as a reverse-proxy, and is working fine with direct calls from Python or Postman, but whenever the api is called from a web application on different domain, the pre-flight is getting a 405 with the following data

**General :**
Request URL:
https://dataapi.example.com/api/v1
Request Method:
OPTIONS
Status Code:
405 Method Not Allowed
Remote Address:
104.21.52.199:443
Referrer Policy:
strict-origin-when-cross-origin

**Response Headers**
Access-Control-Allow-Credentials:
true
Access-Control-Allow-Headers:
Authorization, Content-Type, x_api_key, x_hash, x_data, x_timestamp
Access-Control-Allow-Methods:
GET
Access-Control-Allow-Origin:
https://example.in
Access-Control-Expose-Headers:
Authorization, Content-Type, x_api_key, x_hash, x_data, x_timestamp
Allow:
GET, HEAD
Alt-Svc:
h3=":443"; ma=86400
Cf-Cache-Status:
DYNAMIC
Cf-Ray:
820b0e1f5963bc03-FRA
Content-Length:
18
Content-Type:
text/plain; charset=utf-8
Date:
Sat, 04 Nov 2023 07:13:34 GMT
Expect-Ct:
max-age=86400, enforce
Nel:
{"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Priority:
u=1,i
Referrer-Policy:
same-origin
Report-To:
{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=zIDEmJujxcZPjKhOo%2Fp36XdyigPGAZIBxOtPdIkOfR3OSawpUSMQGnE29zAGClWK9iZX7Cy4FYCU0wgAn6x1373epur9KUDZAIZUuAso2Kbe1cLmhVfNwY6%2F%2FxZ9RhngxkWsa%2FeRyjKkiyA%3D"}],"group":"cf-nel","max_age":604800}
Server:
cloudflare
Strict-Transport-Security:
max-age=15552000; includeSubDomains; preload
X-Content-Type-Options:
nosniff
X-Frame-Options:
SAMEORIGIN
X-Xss-Protection:
1; mode=block

**Request Headers**
:authority:
dataapi.example.com
:method:
OPTIONS
:path:
/api/v1
:scheme:
https
Accept:
*/*
Accept-Encoding:
gzip, deflate, br
Accept-Language:
en-US,en;q=0.9
Access-Control-Request-Headers:
x_api_key,x_data,x_hash,x_timestamp
Access-Control-Request-Method:
GET
Cache-Control:
no-cache
Origin:
https://example.in
Pragma:
no-cache
Referer:
https://example.in/
Sec-Fetch-Dest:
empty
Sec-Fetch-Mode:
cors
Sec-Fetch-Site:
cross-site
User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0

with a console log error of

Access to XMLHttpRequest at 'https://dataapi.example.com/api/v1' from origin 'https://example.in' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

2. Error messages and/or full log output:

There's no error message on journalctl

3. Caddy version:

v2.7.5 h1:HoysvZkLcN2xJExEepaFHK92Qgs7xAiCFydN5x5Hs6Q=

4. How I installed and ran Caddy:

i installed is using “dnf install ‘dnf-command(copr)’
dnf copr enable @caddy/caddy
dnf install caddy”

a. System environment:

CentOS 8 , amd64, systemd>

b. Command:

c. Service/unit/compose file:

d. My complete Caddy config:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "dataapi.example.com"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "subroute",
                          "routes": [
                            {
                              "handle": [
                                {
                                  "handler": "headers",
                                  "response": {
                                    "set": {
                                      "Access-Control-Allow-Origin": [
                                        "https://example.in"
                                      ]
                                    }
                                  }
                                }
                              ],
                              "match": [
                                {
                                  "header": {
                                    "Origin": [
                                      "https://example.in"
                                    ]
                                  }
                                }
                              ]
                            },
                            {
                              "handle": [
                                {
                                  "handler": "headers",
                                  "response": {
                                    "set": {
                                      "Access-Control-Allow-Methods": [
                                        "GET"
                                      ]
                                    }
                                  }
                                }
                              ],
                              "match": [
                                {
                                  "header": {
                                    "Origin": [
                                      "https://example.in"
                                    ]
                                  }
                                }
                              ]
                            },
                            {
                              "handle": [
                                {
                                  "handler": "headers",
                                  "response": {
                                    "set": {
                                      "Access-Control-Allow-Credentials": [
                                        "true"
                                      ],
                                      "Access-Control-Allow-Headers": [
                                        "Authorization, Content-Type, x_api_key, x_hash, x_data, x_timestamp"
                                      ],
                                      "Access-Control-Expose-Headers": [
                                        "Authorization, Content-Type, x_api_key, x_hash, x_data, x_timestamp"
                                      ]
                                    }
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "handle": [
                        {
                          "body": "Client Unauthorized",
                          "handler": "static_response",
                          "status_code": 403
                        }
                      ],
                      "match": [
                        {
                          "not": [
                            {
                              "header": {
                                "Origin": [
                                  "https://example.in"
                                ]
                              }
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "handle": [
                        {
                          "handler": "reverse_proxy",
                          "headers": {
                            "request": {
                              "set": {
                                "Host": [
                                  "{http.reverse_proxy.upstream.hostport}"
                                ]
                              }
                            }
                          },
                          "upstreams": [
                            {
                              "dial": "127.0.0.1:4000"
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            }
          ],
          "tls_connection_policies": [
            {
              "match": {
                "sni": [
                  "dataapi.example.com"
                ]
              },
              "certificate_selection": {
                "any_tag": [
                  "cert0"
                ]
              }
            },
            {}
          ]
        }
      }
    },
    "tls": {
      "certificates": {
        "load_files": [
          {
            "certificate": "/etc/certificates/certificate.pem",
            "key": "/etc/certificates/private.pem",
            "tags": [
              "cert0"
            ]
          }
        ]
      }
    }
  }
}

5. Links to relevant resources:

You haven’t actually described any problem. I’m not sure what you want us to do with that.

I’m sorry for that, slipped through… I’ve updated the post

The 405 status is probably coming from your application. Pre-flight requests are made with the OPTIONS method, you need to make sure your app can always handle that method, to simply populate a response with CORS headers.

If you’re using a middleware stack in your application, the CORS middleware can handle this and respond early with 200 status, before it hits your actual route handlers.

Essentially, this isn’t a Caddy issue, it’s a problem with your app.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.