IIS compression issues when proxying responses from internal web applications

I have a web server configuration where IIS serves as a proxy to forward requests to an internal application server. While the proxy functionality is operating correctly, I’m encountering challenges in ensuring that the responses are compressed before they return to the client.

My Setup:

  • An internal web application hosted at https://backend.local which is not accessible to the public.
  • A public IIS server available at https://public.example that manages the main website and proxies requests to the internal application.
  • I aim to redirect requests from https://public.example/service/PATH to https://backend.local/PATH.

I am using the URL Rewrite module alongside the ARR extension. Below is my current web.config configuration:

<system.webServer>
    <rewrite>
        <rules>
            <rule name="Forward to internal service" stopProcessing="true">
                <match url="^service/(.*)" />
                <conditions>
                    <add input="{CACHE_URL}" pattern="^(https?)://" />
                </conditions>
                <action type="Rewrite" url="{C:1}://backend.local/{R:1}" />
                <serverVariables>
                    <set name="HTTP_ACCEPT_ENCODING" value="" />
                </serverVariables>
            </rule>
        </rules>
        <outboundRules>
            <rule name="FixAbsoluteLinks" preCondition="HtmlContent">
                <match filterByTags="A, Form, Link, Script" pattern="^http(s)?://backend.local/(.*)" />
                <action type="Rewrite" value="/service/{R:2}" />
            </rule>
            <rule name="FixRedirects" preCondition="HtmlContent">
                <match serverVariable="RESPONSE_LOCATION" pattern="^http(s)?://backend.local/(.*)" />
                <action type="Rewrite" value="/service/{R:2}" />
            </rule>
            <preConditions>
                <preCondition name="HtmlContent">
                    <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                </preCondition>
            </preConditions>
        </outboundRules>
    </rewrite>
    <urlCompression dynamicCompressionBeforeCache="false" />
</system.webServer>

The concern is that omitting the clearing of the HTTP_ACCEPT_ENCODING header leads to an error: HTTP Error 500.52 - URL Rewrite Module Error. Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip").

On the contrary, when I do clear this header, there are no compression results observed when the content is sent back to the client. I’ve tried typical solutions such as setting dynamicCompressionBeforeCache="false" and verifying the order of the modules.

Curiously, when I implement straightforward rewrite rules within the same application (like /old/PATH to /new/PATH), compression operates flawlessly. The challenge only arises when trying to rewrite responses to a different server.

Is there any possible way to ensure IIS compresses the final response after executing the outbound rewrite rules?

I encountered this exact scenario when implementing a similar proxy setup. The fundamental issue is that IIS compression happens before outbound rewrite rules are processed, which creates a conflict when you need to modify the response content. The solution I found was to implement a two-stage compression approach. Configure your internal application server to handle compression directly instead of relying on IIS proxy compression. On your backend.local server, enable compression at the application level or through its web server configuration. Alternatively, you can modify your rewrite rule to preserve the original Accept-Encoding header but add a custom condition to handle compression timing. Remove the serverVariables section that clears HTTP_ACCEPT_ENCODING, and instead add to preserve the original header. Then configure a custom outbound rule that processes uncompressed content first, applies your rewrites, and triggers compression as a final step. This requires adding specific conditions to ensure the compression module processes the response after your outbound rules complete their URL transformations.

had similar headache with arr compression. try moving compression to application level on backend server instead of iis proxy. alternatively use a custom module that compresses after outbound rules execute - worked for me but requires some custom code development.

interesting setup! have you tried using the preCondition approach but in reverse? like creating a condition that only applies compression after your outbound rules finish processing? im curious - does your backend.local server support brotli or just gzip? sometimes switching compression algorithms can bypass this timing issue.