Why a Next.js Middleware Rewrite Returns 500 Behind a Reverse Proxy
A locale rewrite passed local checks but failed behind the production reverse proxy. The error showed a TLS handshake directed at a plaintext application port. The important difference was the request shape arriving through the proxy.
Trace the resolved target
The rewrite copied the incoming URL and changed its path to an internal English route. In the affected deployment, forwarded protocol information and the application host combined into an HTTPS target on an HTTP listener. Inspecting that resolved URL explained the EPROTO failure.
Match the transport to the actual listener
We adjusted the target to use the transport served by the internal listener. That change addressed the TLS mismatch in this deployment. It is not a universal instruction to force every Next.js rewrite to HTTP: origin handling depends on the framework version, proxy configuration and target.
Changing the scheme can also change the origin. A rewritten request may re-enter routing and interact with canonical redirects. Our subsequent redirect-loop investigation showed why fixing the transport was only part of the routing contract.
Verify the full path
- Exercise the request through the representative TLS-terminating proxy.
- Inspect the effective protocol, host and rewrite target without logging secrets.
- Check unprefixed, language-prefixed and canonical redirect paths.
- Follow redirects to their final response and verify that the expected page renders.
- Check how internal rewrite markers are trusted and whether an external caller can spoof them.
Make deployment health checks representative
A direct request to the application port can miss behavior introduced by forwarded headers. A successful build can miss it too. The deployment check should exercise the visitor's path and distinguish a serving new release from a successful rollback. Record the framework and proxy configuration used in the reproduction so the fix can be evaluated when either changes.