Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify status code of reverse proxy response #2920

Closed
hackwaly opened this issue Dec 9, 2019 · 24 comments · Fixed by #4021
Closed

Modify status code of reverse proxy response #2920

hackwaly opened this issue Dec 9, 2019 · 24 comments · Fixed by #4021
Labels
feature ⚙️ New feature or request
Milestone

Comments

@hackwaly
Copy link

hackwaly commented Dec 9, 2019

Could it be done by only config?
And are there reverse_proxy response placeholders? Such as headers, status_code, body etc.

@mholt
Copy link
Member

mholt commented Dec 9, 2019

Hi, welcome to the issue tracker!

I am not entirely sure that I understand your post. Do you have 2 questions here?

  1. How to modify the response status code from an upstream?
  2. Whether there are placeholders for reverse proxy? Can you explain more what you mean?

@mholt mholt added the question ❔ Help is being requested label Dec 9, 2019
@AbdelmalekIhdene
Copy link
Contributor

Arguably, you'd say that those configurations should be the responsibility of the upstreams you are passing the request to, i.e. a proxy would only act as a middle-man in a request transaction.
If you want conditionals for different responses then caddy would not be the right answer for you since I'm sure @mholt is steering away from directives like if

@mholt
Copy link
Member

mholt commented Dec 11, 2019

Hmmm no I believe this should be possible with Caddy 2, without imperative syntax -- if it's not possible already, then we should implement it. I just need to know exactly what needs to be implemented. So first, we need some clarification from @hackwaly.

@hackwaly
Copy link
Author

hackwaly commented Dec 11, 2019

I need to use config to achieve:

  • Rewrite headers and status_code of reverse_proxy response (based on reverse_proxy response headers and status_code)

@mholt
Copy link
Member

mholt commented Dec 11, 2019

I almost understand -- can you give an actual example of one such configuration you're trying to accomplish?

@hackwaly
Copy link
Author

hackwaly commented Dec 11, 2019

BTW: I already wrote a go program to get what i want.

Config may like this:

{
  "apps": {
    "proxy_app": {
      "servers": {
        "proxy_server": {
          "routes": [
            {
              "handle": [
                {
                  "handler": "reverse_proxy",
                  "upstreams": [
                    {
                      "dial": "{http.request.header.X-Host}"
                    }
                  ],
                  "headers": {
                    "handler": "headers",
                    "response": {
                      "delete": ["Set-Cookie"],
                      "set": {
                        "X-Set-Cookie": ["{http.handlers.reverse_proxy.response.header.Set-Cookie}"],
                        "Access-Control-Allow-Origin": ["*"]
                      },
                      "set_status_code": "{http.handlers.reverse_proxy.response.status_code >= 400 ? 500 : 200}"
                    }
                  }
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    }
  }
}

@mholt
Copy link
Member

mholt commented Dec 25, 2019

@hackwaly Neat, is the source anywhere?

(Reopening until we implement it here)

@mholt mholt reopened this Dec 25, 2019
@mholt mholt added this to the 2.0 milestone Dec 25, 2019
@mholt mholt added feature ⚙️ New feature or request and removed question ❔ Help is being requested labels Dec 25, 2019
@mholt
Copy link
Member

mholt commented Mar 2, 2020

Ping @hackwaly -- how did you implement that feature?

@hackwaly
Copy link
Author

hackwaly commented Mar 3, 2020

@mholt
clarify: I haven't implement that for caddy. I implement my need in plain go program -- not use caddy.

@fahrradflucht
Copy link

Chiming in here since I want to feature that is in the title even though the issue kind of derailed:

My use case is the following. I have a MinIO backend where I serve a static website from. In case it responds with 404 I have an error handler that rewrites the request to /404.html and reverse proxies again to the same minio backend. Tada 🎉 404-page gets rendered.

The problem is that this will result in a 200 status code for the 404 page which is arguably not ideal. So overwrite the status code would be great.

@mholt
Copy link
Member

mholt commented May 21, 2020

@fahrradflucht So, in your use case, you don't actually want to overwrite the status code, but you just want Caddy's error handler routes to be invoked on whatever error status is returned from the backend, right? Kind of like nginx's intercept_errors directive?

@fahrradflucht
Copy link

fahrradflucht commented May 22, 2020

Maybe I don't fully understand you, but I think I actually want to overwrite the status code. Let me make an example.

Given a Caddyfile like this:

example.com {
	handle_errors {
		@404 {
			expression {http.error.status_code} == 404
		}

		rewrite @404 /404.html
	}

	reverse_proxy https://minio.example.com {
		header_up Host {http.reverse_proxy.upstream.hostport}
        }
}

The 404.html page will be returned for https://example.com/unknown. The problem is that it will be returned with a 200 status code which is not what you usually want. This is why I thought "Well, I need something to tell the reverse_proxy directive to overwrite the status code if the path is /404.html".

Does that make sense? Or am I approaching this totally wrong?

@francislavoie

This comment has been minimized.

@fahrradflucht

This comment has been minimized.

@mholt
Copy link
Member

mholt commented May 22, 2020

@fahrradflucht Is the backend originating the 404 error? I.e. does minio.example.com return a 404 to Caddy for a request to /unknown?

@fahrradflucht
Copy link

@fahrradflucht Is the backend originating the 404 error? I.e. does minio.example.com return a 404 to Caddy for a request to /unknown?

Yes, exactly.

@mholt
Copy link
Member

mholt commented May 22, 2020

@fahrradflucht Okay, then you don't actually want to "overwrite" the status code, you want Caddy to handle the response from the backend as an error, rather than passing it through to the client.

mholt added a commit that referenced this issue May 27, 2020
It's a raw, low-level implementation for now, but it's very flexible.
More sugar-coating can be added after error handling is more developed.
@mholt mholt closed this as completed in 7a99835 Jun 4, 2020
@mholt mholt modified the milestones: 2.x, 2.1 Jun 4, 2020
@mholt
Copy link
Member

mholt commented Jun 4, 2020

This is possible with commit 7a99835

@m90
Copy link
Contributor

m90 commented Sep 19, 2020

@fahrradflucht Sorry for hijacking this issue but I am trying to use the exact same setup (Caddy reverse proxying to MinIO) and have everything working but custom 404 pages.

I tried using the snippet you provided here:

	handle_errors {
		@404 {
			expression {http.error.status_code} == 404
		}

		rewrite @404 /404.html
	}

but it's not having any effect. Did you ever get that setup working?

For the record, this is my complete config:

example.com {
  handle_errors {
    @404 {
      expression {http.error.status_code} == 404
    }

    rewrite @404 /404.html
  }

  reverse_proxy minio:9000

  @document {
    expression {uri}.endsWith("/")
  }

  @noslash {
    not expression {uri}.endsWith("/")
    path_regexp ^[a-z\-/]*$
  }

  handle @noslash {
    redir {uri}/
  }

  handle {
    route @document {
      rewrite {uri}index.html
    }

    rewrite * /static{uri}
  }

  log
}

@francislavoie
Copy link
Member

@m90 it's not currently possible from the Caddyfile (but it is via JSON). Follow the progress on #3712, where Caddyfile support is being worked on.

@francislavoie
Copy link
Member

francislavoie commented May 2, 2021

FYI #4021 is merged, Caddyfile support will be in v2.4.0.

@wlcx
Copy link

wlcx commented Jun 16, 2021

Sorry to comment in an old issue, but this seemed to be the best place for this.

I am in the same situation as @fahrradflucht's comment above: I am reverse proxying to a minio backend serving a static site. This site has a custom 404.html which we want to return in case of an actual 404 from the backend. I've managed to achieve this with the below config, which also alters the final status code to 404 (else the 404 page would be returned with 200!)

However, this feels a little messy so I was wondering if there was a better approach, perhaps involving handle_errors?

reverse_proxy 10.13.37.1:9000 {
    @404 status 404
    handle_response @404 {
        rewrite * /404.html
        reverse_proxy 10.13.37.1:9000 {
            @200 status 200
            handle_response @200 404  # if we get a 200 back (i.e. the 404 page exists) alter our status code to 404
        }
    }
}

@francislavoie
Copy link
Member

francislavoie commented Jun 16, 2021

@wlcx that's the correct way to do it. handle_errors does not get invoked for reverse_proxy responses, because they aren't errors to Caddy. The handle_errors routes are for errors that happen in Caddy.

For next time, please ask your usage questions on the Caddy community forums. We prefer to keep the GitHub issue board for bugs and feature requests. Don't forget to fill out the thread template so we can help you!

@mholt
Copy link
Member

mholt commented Jun 16, 2021

In the future, we could probably introduce some convenience wrapper over that syntax to make it a little simpler to serve custom error pages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ⚙️ New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants