NextJs Streamed Rendering not Working Behind Reverse Proxy

1. The problem I’m having:

We have a layered infra structure with K8s clusters internally, service endpoints exposed by Nginx ingresses and then all publicly facing APIs are served by a Caddyserver acting as a WAF and reverse proxy.
( outer world → [caddy ↔ ingress ↔ applications] )

We are using NextJs for web apps. NextJs is streaming data with text/x-component as protocol. For example when a user waits for data to fill the app, there is a spinner rendered in the browser, which occurs with a streaming connection.

If we connect directly to the Nginx ingresses, everything is working as expected. The spinner is rendered when data is handled server side.
If we use the app via Caddyserver, the spinner is not rendered. The web app looks like it froze and then data is populated.

At first I suspected the weird protocol to be the bad boy, but no. There is no indication in any logs that these responses are being blocked. And, the user gets the data in the end so it can’t be a drop/block issue after all.

I’ve tried the flush_interval -1 config discussed here. But there is no difference in behaviour when I add this to the reverse proxy directive.

What am I missing? Anyone else using NextJs behind Caddy who might have some tricks up the sleeve?

2. Error messages and/or full log output:

None. No logs.

3. Caddy version:

2.7.6 with Coraza v2 (xcaddy builder)

4. How I installed and ran Caddy:

FROM caddy:2.7.6-builder AS builder

WORKDIR /app
RUN xcaddy build --output caddy \
    --with github.com/corazawaf/coraza-caddy/v2@latest

FROM caddy:2.7.6
COPY conf/* /etc/caddy/
COPY --from=builder /app/caddy /usr/bin/caddy
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--watch"]

a. System environment:

Docker, see above

b. Command:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

c. Service/unit/compose file:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

d. My complete Caddy config:

{
        order coraza_waf first
}

(cors) {
        @origin{args[0]} header Origin {args[0]}
        header @origin{args[0]} Access-Control-Allow-Origin "{args[0]}"
        header @origin{args[0]} Vary Origin
}

import endpoints-prod/*
import endpoints-test/*

This config is one of the apps in test for example:’

tks-manager.alpcot.tech {
        coraza_waf {
                load_owasp_crs
                directives `
                Include /etc/caddy/coraza.conf
                Include /etc/caddy/crs-setup-nextjs.conf
                Include /etc/caddy/rules/*.conf
                SecRuleEngine On
                `
        }

        tls ------------
        encode zstd gzip

        import cors https://*.azurewebsites.net

        handle * {
                rewrite * /tks-manager/{uri}
                reverse_proxy ----------
        }

        respond "hello tks"
        log
}

5. Links to relevant resources:

I don’t understand the question. I don’t use NextJS so I can’t help from that angle. Please show evidence of the problem, show your Caddy logs, etc.

1 Like

The question is why Caddy is not letting Transfer-Encoding: chunked through from the response. Responses that are supposed to be streamed are not.

If we let the browser client send requests directly to the Nginx Ingress, the responses are working as expected, the response is chunked and the Transfer-Encoding: chunked header is part of the response. And, the spinner that comes with that stream is rendered in the browser.
The Nginx has proxy_buffering: off to make sure that streams are sent through immediately. And it clearly works.

But, when the browser sends requests via Caddy as a reverse proxy to Nginx, we do not get the Transfer-Encoding: chunked at all and the response is not streamed (well, we do not get the chunks, so…).

It seems there is something missing between Nginx’s response and Caddy’s proxying.

We tried to run the NextJs client behind a local Caddy server, with a super simple reverse proxy only, and then it worked. So it looks like there is a mismatch between Caddy proxying and Nginx streaming responses.

Here is another similar question, but with no reply.

Recap.
After more investigation we figured out that Coraza is temporarily blocking the response stream. Got it verified too.

1 Like

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