Setting up proxy headers in IIS for flask application - flask

I have a flask application on windows running at http://localhost:3333. I want domain example.com to proxy to this application using IIS. I have setup IIS with below settings.
Added server variables HTTP_X_FORWARDED_HOST
Configured URL Rewrite module to redirect example.com to localhost:3333
There is a route in flask which I use to generate URL for forgot password like this url_for('/password_reset',_external=True).
When I access the page via example.com, all works fine where I have redirect() used. But wherever I have url_for(), the URL looks like http://localhost:3333/password_reset instead of http://example.com/password_reset. How do I make url_for() to use the external domain name properly.
Edit 1:
Current web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpRedirect enabled="false" destination="http://localhost:3333" />
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:3333/{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:3333/(.*)" />
<action type="Rewrite" value="http{R:1}://example.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<httpProtocol>
<customHeaders>
<add name="Host" value="{HOST}" />
</customHeaders>
</httpProtocol>
</system.webServer>
<system.web>
<httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" />
<pages validateRequest="false" />
<identity impersonate="false" />
</system.web>
</configuration>
Edit 2:
Solution: I executed this to preserver headers and now the original host is preserved when using url_for().
"C:\Windows\System32\inetsrv\appcmd.exe" set config -section:system.webServer/proxy /preserveHostHeader:"True" /commit:apphost

you could use iis reverse proxy module for that you need to install arr:
https://www.iis.net/downloads/microsoft/application-request-routing
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing
below is sample rule:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="ReverseProxyInboundRule2" enabled="false" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://127.0.0.1:5000/{R:1}" />
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule2" preCondition="ResponseIsHtml1" enabled="false">
<match filterByTags="A, Form, Img" pattern="^http(s)?://127.0.0.1:5000/(.*)" />
<action type="Rewrite" value="http{R:1}://example.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<urlCompression doDynamicCompression="false" />
</system.webServer>
</configuration>

Solution that worked, as per edit.
I executed this to preserver headers and now the original host is preserved when using url_for().
"C:\Windows\System32\inetsrv\appcmd.exe" set config -section:system.webServer/proxy /preserv

Related

AWS equivalent of IIS rewrites

I'm used to working with IIS and when working with Single Page Apps I usually put in an iis rewrite into the webconfig file:
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
This allows me to access a direct path in my application such as: http://www.example.com/dashboard
However this particular project I am working with aws (not iis) and there aren't any guides to achieve the same result. Please can someone point me in the right direction?

URL Rewrite iis server

I want to rewrite a url to index.html. the web.config below does the job until first path.
eg:- test.com/test1 to test.com/index.html but it doesnt work with multiple paths. eg:- test.com/test1/test2
my current web.config
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="redirect all requests" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="index.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I'm not sure what I'm missing here. Please if any of you know, write the correct web.config.
Thank you.
You can try this rule:
<rule name="test" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/([^/]+)" />
</conditions>
<action type="Redirect" url="http://test.com/{C:1}/index.com" redirectType="Found" />
</rule>

IIS rewrite rule not working in live environment

I have 4 servers in azure, 3 are load balanced and the 4th is for CMS purposes only.
SSL certificate has been added for the main website, but not for the sobdomain that the CMS is on.
I wrote a rule that should find any url that doesnt contain "backoffice" and match any other page to change it to https.
This works on regexr.com but for some reason doesnt work
<rewrite>
<rules>
<rule name="http to https" stopProcessing="true">
<match url="(https?:\/\/(?!backoffice).*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com{R:1}" />
</rule>
</rules>
</rewrite>
Url Rewriting 2.1 is installed on all 4 servers and i have created a load balance set in azure for https.
going to https manually works fine (along with loadbalancing).
Additional information:
I've tried many rules, including the existing answer. I can see things happening, like assets being brought in as https, but the page itself does not redirect.
There are 2 load balance sets, one for port 80 and the other for port 443. I don't know if this is corect, or could be a potential cause in the redirect not happening.
Your rule should be like that:
<rule name="http to https" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{REQUEST_URI}" pattern="/backoffice" negate="true" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com{R:0}" />
</rule>
This rule will exclude requests with /backoffice path.
Also for issue of mixing content you need to fix your paths for css/js/images to relatives. Example:
<img src="/path/to/your/image.jpg"/>
Another way to fix mixed content is create outbound rule, which will change your output HTML (replace http: to https:):
<rewrite>
...
<outboundRules>
<rule name="Rewrite external references to use HTTPS" preCondition="IsHTML">
<match filterByTags="Script, Link, Img, CustomTags" customTags="HTML5Tags" pattern="^http://(.*)$" />
<action type="Rewrite" value="https://{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
<customTags>
<tags name="HTML5Tags">
<tag name="Video" attribute="src" />
</tags>
</customTags>
</outboundRules>
</rewrite>
Using the previous answer as a starting point, i made a few minor changes, to use HTTP_HOST rather than REQUEST_URI for the pattern negation and it works.
<system.webServer>
<rewrite xdt:Transform="InsertIfMissing">
<rules>
<rule name="http to https" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{HTTP_HOST}" pattern="^backoffice\.WEBSITENAME\.com$" negate="true" />
</conditions>
<action type="Redirect" url="https://www.WEBSITENAME.com/{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>

Rule not working in rewrite rules despite valid regex

Our webconfig file uses Url Rewrite, essentially pushing any http traffic to https
This works fine other than developing locally. For a while we have to simply remember to comment out the code from the web.config and uncomment it again for commit. Naturally this isn't a good way to work.
The code is simple
<rewrite>
<rules>
<rule name="Redirect-AllWWW-ToSecureNonWWW">
<match url="^((?!local).)*$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?:www\.)(.+)$" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}"/>
</rule>
<rule name="Redirect-AllNonSecure-ToSecureNonWWW-ExcludingLocalhost">
<match url="^((?!local).)*$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^localhost$" negate="true" />
<add input="{HTTPS}" pattern="^off$" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
</rules>
</rewrite>
And as per the regex101 , it works!
https://regex101.com/r/3Mz6w1/1
However, when on localhost, I am still directed to HTTPS
Why does it work in regex101 and not in my web.config file
This seems to be related to Redirect rule not working
quote from URL Rewrite Module Configuration Reference
A rewrite rule pattern is used to specify a pattern to which the current URL path is compared.
...
A pattern is specified within a <match> element of a rewrite rule.
According to this piece of official information, you must be sure that <match url compares only with URL paths which never contain host names, not the entire URL.
For Url Rewrite Module, URL path of this question is questions/44944175/rule-not-working-in-rewrite-rules-despite-valid-regex for example. No stackoverflow.com no https:// no query strings but only the path without leading slash.
To ignore requests for host names containing local you need some conditions looking for a local match with HTTP_HOST header.
<rewrite>
<rules>
<rule name="Redirect-AllWWW-ToSecureNonWWW" stopProcessing="true">
<match url=".*" />
<conditions>
<!-- continue if http host name does not contain "local" -->
<add input="{HTTP_HOST}" pattern="local" negate="true" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)(.+)$" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
<rule name="Redirect-AllNonSecure-ToSecureNonWWW-ExcludingLocalhost" stopProcessing="true">
<match url=".*" />
<conditions>
<!-- continue if http host name does not contain "local" -->
<add input="{HTTP_HOST}" pattern="local" negate="true" />
<add input="{HTTPS}" pattern="^off$" />
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)" />
</conditions>
<action type="Redirect" url="https://{C:1}/{R:0}" />
</rule>
</rules>
</rewrite>

IIS7 URL Redirect with Regex

I'm preparing for a major overhaul of our shopping cart, which is going to completely change how the urls are structured. For what its worth, this is for Magento 1.7.
An example URL would be:
{domain}/item/sub-domain/sub-sub-domain-5-16-7-16-/8083770?plpver=98&categid=1027&prodid=8090&origin=keyword
and redirect it to {domain}/catalogsearch/result/?q=8083710
My web.config is:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Magento Required" stopProcessing="false">
<match url=".*" ignoreCase="false" /> <conditions>
<add input="{URL}" pattern="^/(media|skin|js)/" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions> <action type="Rewrite" url="index.php" />
</rule>
<rule name="Item Redirect" stopProcessing="true">
<match url="^item/([_\-a-zA-Z0-9]+)/([_\-a-zA-Z0-9]+)/([_\-a-zA-Z0-9]+)(\?.*)" />
<action type="Redirect" url="catalogsearch/result/?q={R:3}" appendQueryString="true" redirectType="Permanent" />
<conditions trackAllCaptures="true">
</conditions>
</rule>
</rules>
</rewrite>
<httpProtocol allowKeepAlive="false" />
<caching enabled="false" />
<urlCompression doDynamicCompression="true" />
</system.webServer>
</configuration>
Right now it seems the redirect is completely ignored, even though in the IIS GUI the sample url passes the regex test. Is there a better way to redirect or is there something wrong with my web.config?
Turns out the answer is here. Can't have a Question Mark in the regex, as IIS treats it as a query string and it needs to be captured in the "conditions" section of the web.config.
So I just took (\?.*) off the end of regex, and added:
<conditions logicalGrouping="MatchAny" trackAllCaptures="true">
<add input="{QUERY_STRING}" pattern=".*" />
</conditions>