title: Nginx as reverse proxy: How to display a custom error page for upstream errors, UNLESS the upstream says not to?
body: <p>I have an Nginx instance running as a reverse proxy. When the upstream server does not respond, I send a custom error page for the 502 response code. When the upstream server sends an error page, that gets forwarded to the client, and I'd like to show a custom error page in that case as well.</p>
  <p>If I wanted to replace all of the error pages from the upstream server, I would set <a href="https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors" rel="nofollow noreferrer"><code>proxy_intercept_errors on</code></a> to show a custom page on each of them. However, there are cases where I'd like to return the actual response that the upstream server sent: for example, for API endpoints, or if the error page has specific user-readable text relating to the issue.</p>
  <p>In the config, a single <code>server</code> is proxying multiple applications that are behind their own proxy setups and their own rules for forwarding requests around, so I can't just specify this per each <code>location</code>, and it has to work for any URL that matches a <code>server</code>.</p>
  <p>Because of this, I would like to send the custom error page, <em>unless</em> the upstream application says not to. The easiest way to do this would be with a custom HTTP header. There is a similar question about <a href="https://stackoverflow.com/q/44402862/5936187">doing this depending on the <em>request</em> headers</a>. Is there a way to do this depending on the <em>response</em> headers?</p>
  <p>(It appears that <a href="https://stackoverflow.com/q/68558912/5936187">somebody else already had this question</a> and their conclusion was that it was impossible with plain Nginx. If that's true, I would be interested in some other ideas on how to solve this, possibly using OpenResty like that person did.)</p>
  <p>So far I have tried using OpenResty to do this, but it doesn't seem compatible with <code>proxy_pass</code>: the response that the Lua code generates seems to overwrite the response from the upstream server.</p>
  <p>Here's the <code>location</code> block I tried to use:</p>
  <pre><code>location / {
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_pass http://localhost:65000;
  
          content_by_lua_block{
            ngx.say(&quot;This seems to overwrite the content from the proxy?!&quot;)
          }        
  
          body_filter_by_lua_block {
            ngx.arg[1]=&quot;Truncated by code!&quot;
            ngx.arg[2]=false
            if ngx.status &gt;= 400 then
              if not ngx.resp.get_headers()[&quot;X-Verbatim&quot;] then
                local file = io.open('/usr/share/nginx/error.html', 'w')
                local html_text = file:read(&quot;*a&quot;)
                ngx.arg[1] = html_text
                ngx.arg[2] = true
                return
              end
            end
      }
  }
  </code></pre>