[GH-ISSUE #131] UI flashing with IIS reverse proxy #88

Closed
opened 2026-03-15 12:29:10 +03:00 by kerem · 9 comments
Owner

Originally created by @kustanbruno on GitHub (Jun 26, 2023).
Original GitHub issue: https://github.com/axllent/mailpit/issues/131

We are upgrading from mailhog to mailpit. We are trying to use mailpit with IIS as reverse proxy, the configuration seems to be working, but the UI is always refreshing. There are no errors shown in the browser console nor in the output of mailpit. The network tab of the browser shows 2 request repeating:

I was able to replicate the problem in postman too. When connecting via ip address without IIS as reverse proxy, de output looks like this:
image

With IIS as reverse proxy, the output looks like this:
image

Mailhogs websocket endpoint seems to have no problem with the IIS as reverse proxy:
image

How should we troubleshoot this problem?

Originally created by @kustanbruno on GitHub (Jun 26, 2023). Original GitHub issue: https://github.com/axllent/mailpit/issues/131 We are upgrading from mailhog to mailpit. We are trying to use mailpit with IIS as reverse proxy, the configuration seems to be working, but the UI is always refreshing. There are no errors shown in the browser console nor in the output of mailpit. The network tab of the browser shows 2 request repeating: - wss://mailhog.cooldigit.hu/api/events - https://mailhog.cooldigit.hu/api/v1/messages?limit=50 I was able to replicate the problem in postman too. When connecting via ip address without IIS as reverse proxy, de output looks like this: <img width="1663" alt="image" src="https://github.com/axllent/mailpit/assets/33034369/4a53d9be-fa17-4358-8bd6-08da11797a0f"> With IIS as reverse proxy, the output looks like this: <img width="1674" alt="image" src="https://github.com/axllent/mailpit/assets/33034369/b53501e5-f088-41c1-8d68-deedd9da5a55"> Mailhogs websocket endpoint seems to have no problem with the IIS as reverse proxy: <img width="1639" alt="image" src="https://github.com/axllent/mailpit/assets/33034369/1a815ac3-2516-453f-a556-41b77dd2f19b"> How should we troubleshoot this problem?
kerem 2026-03-15 12:29:10 +03:00
Author
Owner

@axllent commented on GitHub (Jun 27, 2023):

I can't really say how IIS works, however it appears to be that IIS is closing the websocket connection. Each time the websocket reconnects Mailpit will refresh the messages automatically (so that part is expected). How long does it "hold" the connection for (it appears to immediately disconnect based on what I can see)?

So the issue here is your IIS proxy - if you find out why it's not holding the websocket connection (abnormal closure), then I suspect you'll have your solution. Sorry I can't be more help here, but I really have zero experience in over 15 years with IIS.

<!-- gh-comment-id:1608833559 --> @axllent commented on GitHub (Jun 27, 2023): I can't really say how IIS works, however it appears to be that IIS is closing the websocket connection. Each time the websocket reconnects Mailpit will refresh the messages automatically (so that part is expected). How long does it "hold" the connection for (it appears to immediately disconnect based on what I can see)? So the issue here is your IIS proxy - if you find out why it's not holding the websocket connection (abnormal closure), then I suspect you'll have your solution. Sorry I can't be more help here, but I really have zero experience in over 15 years with IIS.
Author
Owner

@doughless commented on GitHub (Jul 17, 2023):

I ran into this when trying to set this up at work, too. Apparently, IIS's advanced request routing does not support permessage-deflate:
https://serverfault.com/questions/1037407/websocket-based-website-behind-a-reverse-proxy-in-iis
https://stackoverflow.com/questions/38933815/iis-8-websockets-with-permessage-deflate

I was able to get it working using the following workaround:

  1. Add HTTP_SEC_WEBSOCKET_EXTENSIONS as an allowed server variable, then
  2. Add the following to your HTTP rewrite rule (I have separate rewrite rules for HTTP and WS, I noticed it only fixed the issue when rewriting the server variable specifically with the HTTP rule):
<serverVariables>
  <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
</serverVariables>
<!-- gh-comment-id:1638915147 --> @doughless commented on GitHub (Jul 17, 2023): I ran into this when trying to set this up at work, too. Apparently, IIS's advanced request routing does not support permessage-deflate: https://serverfault.com/questions/1037407/websocket-based-website-behind-a-reverse-proxy-in-iis https://stackoverflow.com/questions/38933815/iis-8-websockets-with-permessage-deflate I was able to get it working using the following workaround: 1. Add HTTP_SEC_WEBSOCKET_EXTENSIONS as an allowed server variable, then 2. Add the following to your HTTP rewrite rule (I have separate rewrite rules for HTTP and WS, I noticed it only fixed the issue when rewriting the server variable specifically with the HTTP rule): ``` <serverVariables> <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /> </serverVariables> ```
Author
Owner

@axllent commented on GitHub (Jul 18, 2023):

Thanks @doughless, I am sure this will help some. Given what you now know, do you think it is fairly easy to document the steps needed in order to set up a proxy for Mailpit using ISS? What I mean is, if I was to get a simple set of instructions of how to set it up on ISS, I could then document this in the Mailpit Wiki for other users to refer to.

<!-- gh-comment-id:1639270279 --> @axllent commented on GitHub (Jul 18, 2023): Thanks @doughless, I am sure this will help some. Given what you now know, do you think it is fairly easy to document the steps needed in order to set up a proxy for Mailpit using ISS? What I mean is, if I was to get a simple set of instructions of how to set it up on ISS, I could then document this in the Mailpit Wiki for other users to refer to.
Author
Owner

@doughless commented on GitHub (Jul 18, 2023):

@axllent Sure, this is what I put together, hopefully I remembered everything:

Install prerequisites

URL Rewrite 2.1
Application Request Routing 3.0

Enable Application Request Routing proxy

Open IIS Manager, select your server, then open the Application Request Routing Cache feature:

ARR feature

Next, click Server Proxy Settings...
Server proxy settings

Finally, check “Enable proxy” and click Apply.
Enable proxy

Add server variables

Because Application Request Routing doesn’t work with the permessage_deflate WebSocket extension, you will need to add the HTTP_SEC_WEBSOCKET_EXTENSIONS server variable to URL Rewrite to allow your rewrite rules to remove the Sec-WebSocket-Extensions header value.

To do this, open IIS Manager, select your website, and open the URL Rewrite feature:
URL Rewrite

Then click on View Server Variables... and add a server variable named HTTP_SEC_WEBSOCKET_EXTENSIONS:
View server variables
http_sec_websocket_extension

You can then close IIS Manager; you will need to manually add the URL Rewrite rules to your web.config, because URL Rewrite's UI doesn't allow setting server variables to an empty string value.

Configure URL Rewrite rules

Edit the web.config for your website, and add the following rewrite rules:

  • Replace MP_WEBROOT with your MailPit web root; or remove it from the regex patterns if you are not using a custom web root.
  • You only need to replace localhost:8025 with your MailPit server and port if you are running MailPit on a different server than your IIS reverse proxy, or you configured MP_UI_BIND_ADDR to use a different port.
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="MailPit Reverse Proxy" stopProcessing="true">
                    <match url="^(MP_WEBROOT.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{SERVER_PROTOCOL}" pattern="wss" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="http://localhost:8025/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
                    </serverVariables>
                </rule>
                <rule name="MailPit WebSocket Reverse Proxy" stopProcessing="true">
                    <match url="^(MP_WEBROOT.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{SERVER_PROTOCOL}" pattern="wss" />
                    </conditions>
                    <action type="Rewrite" url="ws://localhost:8025/{R:1}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>
<!-- gh-comment-id:1641054844 --> @doughless commented on GitHub (Jul 18, 2023): @axllent Sure, this is what I put together, hopefully I remembered everything: ### Install prerequisites [URL Rewrite 2.1](https://www.iis.net/downloads/microsoft/url-rewrite) [Application Request Routing 3.0](https://www.iis.net/downloads/microsoft/application-request-routing) ### Enable Application Request Routing proxy Open IIS Manager, select your server, then open the Application Request Routing Cache feature: ![ARR feature](https://github.com/axllent/mailpit/assets/527742/b29923c5-39cc-4b23-8de8-d56df1a954ab) Next, click Server Proxy Settings... ![Server proxy settings](https://github.com/axllent/mailpit/assets/527742/22b6e828-3654-4707-943d-57e242501706) Finally, check “Enable proxy” and click Apply. ![Enable proxy](https://github.com/axllent/mailpit/assets/527742/c01e5011-ee54-4069-a6e1-c1cc11e46263) ### Add server variables Because Application Request Routing doesn’t work with the permessage_deflate WebSocket extension, you will need to add the HTTP_SEC_WEBSOCKET_EXTENSIONS server variable to URL Rewrite to allow your rewrite rules to remove the Sec-WebSocket-Extensions header value. To do this, open IIS Manager, select your website, and open the URL Rewrite feature: ![URL Rewrite](https://github.com/axllent/mailpit/assets/527742/3a4966f6-891b-4236-9bd2-3d4385f463bf) Then click on View Server Variables... and add a server variable named HTTP_SEC_WEBSOCKET_EXTENSIONS: ![View server variables](https://github.com/axllent/mailpit/assets/527742/19e26078-d887-4f66-98ff-9964035e98d1) ![http_sec_websocket_extension](https://github.com/axllent/mailpit/assets/527742/dd113aa2-ee65-4473-a773-d0254568c853) You can then close IIS Manager; you will need to manually add the URL Rewrite rules to your web.config, because URL Rewrite's UI doesn't allow setting server variables to an empty string value. ### Configure URL Rewrite rules Edit the web.config for your website, and add the following rewrite rules: - Replace MP_WEBROOT with your MailPit web root; or remove it from the regex patterns if you are not using a custom web root. - You only need to replace localhost:8025 with your MailPit server and port if you are running MailPit on a different server than your IIS reverse proxy, or you configured MP_UI_BIND_ADDR to use a different port. ```xml <configuration> <system.webServer> <rewrite> <rules> <rule name="MailPit Reverse Proxy" stopProcessing="true"> <match url="^(MP_WEBROOT.*)" /> <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> <add input="{SERVER_PROTOCOL}" pattern="wss" negate="true" /> </conditions> <action type="Rewrite" url="http://localhost:8025/{R:1}" /> <serverVariables> <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /> </serverVariables> </rule> <rule name="MailPit WebSocket Reverse Proxy" stopProcessing="true"> <match url="^(MP_WEBROOT.*)" /> <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> <add input="{SERVER_PROTOCOL}" pattern="wss" /> </conditions> <action type="Rewrite" url="ws://localhost:8025/{R:1}" /> </rule> </rules> </rewrite> </system.webServer> </configuration> ```
Author
Owner

@doughless commented on GitHub (Jul 18, 2023):

Thought I'd include a mention to you, @kustanbruno, to see if this helps you.

<!-- gh-comment-id:1641058745 --> @doughless commented on GitHub (Jul 18, 2023): Thought I'd include a mention to you, @kustanbruno, to see if this helps you.
Author
Owner

@axllent commented on GitHub (Jul 23, 2023):

My apologies for the late reply @doughless - I was away for a few days. That is great, thank you! I have linked it to the Troubleshooting wiki page for now, but will hopefully (one one day not too far away) create and add it directly to a more suitable documentation website for Mailpit 👍

<!-- gh-comment-id:1646955515 --> @axllent commented on GitHub (Jul 23, 2023): My apologies for the late reply @doughless - I was away for a few days. That is great, thank you! I have linked it to the [Troubleshooting](https://github.com/axllent/mailpit/wiki/Troubleshooting) wiki page for now, but will hopefully (one one day not too far away) create and add it directly to a more suitable documentation website for Mailpit :+1:
Author
Owner

@kustanbruno commented on GitHub (Jul 24, 2023):

Hi @doughless, thanks a lot, the configuration works. Your tutorial was really detailed and easy to follow. 👍

I had to add around the two rewrite rules.

<!-- gh-comment-id:1647437989 --> @kustanbruno commented on GitHub (Jul 24, 2023): Hi @doughless, thanks a lot, the configuration works. Your tutorial was really detailed and easy to follow. 👍 I had to add <rules></rules> around the two rewrite rules.
Author
Owner

@pranithan-kang commented on GitHub (Aug 21, 2025):

@axllent Sure, this is what I put together, hopefully I remembered everything:

Install prerequisites

URL Rewrite 2.1 Application Request Routing 3.0

Enable Application Request Routing proxy

Open IIS Manager, select your server, then open the Application Request Routing Cache feature:

ARR feature

Next, click Server Proxy Settings... Server proxy settings

Finally, check “Enable proxy” and click Apply. Enable proxy

Add server variables

Because Application Request Routing doesn’t work with the permessage_deflate WebSocket extension, you will need to add the HTTP_SEC_WEBSOCKET_EXTENSIONS server variable to URL Rewrite to allow your rewrite rules to remove the Sec-WebSocket-Extensions header value.

To do this, open IIS Manager, select your website, and open the URL Rewrite feature: URL Rewrite

Then click on View Server Variables... and add a server variable named HTTP_SEC_WEBSOCKET_EXTENSIONS: View server variables http_sec_websocket_extension

You can then close IIS Manager; you will need to manually add the URL Rewrite rules to your web.config, because URL Rewrite's UI doesn't allow setting server variables to an empty string value.

Configure URL Rewrite rules

Edit the web.config for your website, and add the following rewrite rules:

  • Replace MP_WEBROOT with your MailPit web root; or remove it from the regex patterns if you are not using a custom web root.
  • You only need to replace localhost:8025 with your MailPit server and port if you are running MailPit on a different server than your IIS reverse proxy, or you configured MP_UI_BIND_ADDR to use a different port.

I took the web.config above to put in IIS and found that it returns 500.12. I later realized that the rules must be wrapped with the <rules> tag. So, the final web.config must be:

<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="MailPit Reverse Proxy" stopProcessing="true">
                    <match url="^(MP_WEBROOT.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{SERVER_PROTOCOL}" pattern="wss" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="http://localhost:8025/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
                    </serverVariables>
                </rule>
                <rule name="MailPit WebSocket Reverse Proxy" stopProcessing="true">
                    <match url="^(MP_WEBROOT.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{SERVER_PROTOCOL}" pattern="wss" />
                    </conditions>
                    <action type="Rewrite" url="ws://localhost:8025/{R:1}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>
<!-- gh-comment-id:3209298719 --> @pranithan-kang commented on GitHub (Aug 21, 2025): > [@axllent](https://github.com/axllent) Sure, this is what I put together, hopefully I remembered everything: > > ### Install prerequisites > [URL Rewrite 2.1](https://www.iis.net/downloads/microsoft/url-rewrite) [Application Request Routing 3.0](https://www.iis.net/downloads/microsoft/application-request-routing) > > ### Enable Application Request Routing proxy > Open IIS Manager, select your server, then open the Application Request Routing Cache feature: > > ![ARR feature](https://github.com/axllent/mailpit/assets/527742/b29923c5-39cc-4b23-8de8-d56df1a954ab) > > Next, click Server Proxy Settings... ![Server proxy settings](https://github.com/axllent/mailpit/assets/527742/22b6e828-3654-4707-943d-57e242501706) > > Finally, check “Enable proxy” and click Apply. ![Enable proxy](https://github.com/axllent/mailpit/assets/527742/c01e5011-ee54-4069-a6e1-c1cc11e46263) > > ### Add server variables > Because Application Request Routing doesn’t work with the permessage_deflate WebSocket extension, you will need to add the HTTP_SEC_WEBSOCKET_EXTENSIONS server variable to URL Rewrite to allow your rewrite rules to remove the Sec-WebSocket-Extensions header value. > > To do this, open IIS Manager, select your website, and open the URL Rewrite feature: ![URL Rewrite](https://github.com/axllent/mailpit/assets/527742/3a4966f6-891b-4236-9bd2-3d4385f463bf) > > Then click on View Server Variables... and add a server variable named HTTP_SEC_WEBSOCKET_EXTENSIONS: ![View server variables](https://github.com/axllent/mailpit/assets/527742/19e26078-d887-4f66-98ff-9964035e98d1) ![http_sec_websocket_extension](https://github.com/axllent/mailpit/assets/527742/dd113aa2-ee65-4473-a773-d0254568c853) > > You can then close IIS Manager; you will need to manually add the URL Rewrite rules to your web.config, because URL Rewrite's UI doesn't allow setting server variables to an empty string value. > > ### Configure URL Rewrite rules > Edit the web.config for your website, and add the following rewrite rules: > > * Replace MP_WEBROOT with your MailPit web root; or remove it from the regex patterns if you are not using a custom web root. > * You only need to replace localhost:8025 with your MailPit server and port if you are running MailPit on a different server than your IIS reverse proxy, or you configured MP_UI_BIND_ADDR to use a different port. > > <configuration> > <system.webServer> > <rewrite> > <rule name="MailPit Reverse Proxy" stopProcessing="true"> > <match url="^(MP_WEBROOT.*)" /> > <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> > <add input="{SERVER_PROTOCOL}" pattern="wss" negate="true" /> > </conditions> > <action type="Rewrite" url="http://localhost:8025/{R:1}" /> > <serverVariables> > <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /> > </serverVariables> > </rule> > <rule name="MailPit WebSocket Reverse Proxy" stopProcessing="true"> > <match url="^(MP_WEBROOT.*)" /> > <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> > <add input="{SERVER_PROTOCOL}" pattern="wss" /> > </conditions> > <action type="Rewrite" url="ws://localhost:8025/{R:1}" /> > </rule> > </rewrite> > </system.webServer> > </configuration> I took the `web.config` above to put in IIS and found that it returns 500.12. I later realized that the rules must be wrapped with the `<rules>` tag. So, the final web.config must be: <configuration> <system.webServer> <rewrite> <rules> <rule name="MailPit Reverse Proxy" stopProcessing="true"> <match url="^(MP_WEBROOT.*)" /> <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> <add input="{SERVER_PROTOCOL}" pattern="wss" negate="true" /> </conditions> <action type="Rewrite" url="http://localhost:8025/{R:1}" /> <serverVariables> <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /> </serverVariables> </rule> <rule name="MailPit WebSocket Reverse Proxy" stopProcessing="true"> <match url="^(MP_WEBROOT.*)" /> <conditions logicalGrouping="MatchAll" trackAllCaptures="false"> <add input="{SERVER_PROTOCOL}" pattern="wss" /> </conditions> <action type="Rewrite" url="ws://localhost:8025/{R:1}" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
Author
Owner

@doughless commented on GitHub (Aug 21, 2025):

I took the web.config above to put in IIS and found that it returns 500.12. I later realized that the rules must be wrapped with the <rules> tag.

Thank you, I fixed the original comment.

<!-- gh-comment-id:3210859600 --> @doughless commented on GitHub (Aug 21, 2025): > I took the `web.config` above to put in IIS and found that it returns 500.12. I later realized that the rules must be wrapped with the `<rules>` tag. Thank you, I fixed the original comment.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/mailpit#88
No description provided.