Setting up reverse proxy using ARR in IIS

When I initially set up Team City at work, I’ve used localhost on Port 85 as the default Port 80 was already assigned to a default Website in IIS. However not many people have access to the server where the site was running and they couldn’t change build configuration and check detailed error logs. So I wanted to use Application Request Routing (ARR) to forward incoming requests from teamcity.app.branch.local to localhost:85 where Team City was set up to listen to.

I found an MSDN article with very detailed instructions and I followed the steps carefully. It was well explained across 3 webpages (so kudos to the author) and dealt with things like the initial forwarding using inbound/outbound rules, fixing the problem with http compression and dealing with rewriting anchor tags and form action links.

It all worked fine and I was really happy until I saw a message in Team City telling me there was a problem with Web Sockets. After some Googling, it turns out there’s no easy way around it, so I decided to revert the changes I made for ARR in IIS and just updated the Server URL in Team City (Administration -> Server Administration -> Global Settings) and was able to access the UI through teamcity.app.branch.local:85.

The way ARR works as I understand it is that it forwards requests from a domain to another web app. Since teamcity.app.branch.local DNS was pointing to a particular server and running on Port 80, which in my case was the default website in IIS 8.5, I believe you could only add the following rewrite rules in Web.config without having to go through all the steps in the link above:

<system.webServer>
	<rewrite>
		<rules>
			<rule name="ReverseProxyInboundRule1" stopProcessing="true">
				<match url="(.*)" />
				<action type="Rewrite" url="http://localhost:85/{R:1}" />
				<serverVariables>
					<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
					<set name="HTTP_ACCEPT_ENCODING" value="" />
				</serverVariables>
			</rule>
		</rules>
		<outboundRules>
			<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
				<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:85/(.*)" />
				<action type="Rewrite" value="http{R:1}://teamcity.app.branch.local/{R:2}" />
			</rule>
			<rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
				<match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
				<action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
			</rule>
			<rule name="AnchorTagRule" preCondition="ResponseIsHtml1">
				<match pattern="href=(.*?)http://localhost:85/(.*?)\s" />
				<action type="Rewrite" value="href={R:1}http://teamcity.app.branch.local/{R:2}" />
			</rule>
			<rule name="FormActionRule">
				<match pattern="action=(.*?)http://localhost:85/(.*?)\\" />
				<action type="Rewrite" value="action={R:1}http://teamcity.app.branch.local/{R:2}\" />
			</rule>
			<preConditions>
				<preCondition name="ResponseIsHtml1">
					<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/(.+)" />
				</preCondition>
				<preCondition name="NeedsRestoringAcceptEncoding">
					<add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
				</preCondition>
			</preConditions>
		</outboundRules>
	</rewrite>
</system.webServer>

The above will forward request from teamcity.app.branch.local to localhost:85 so change the URLs according to your requirements. It’s as simple as this. The steps in the MSDN article will create those inbound/outbound rules in Web.config but I don’t think you need to go through all those steps, just make sure you’ve got ARR and URL Rewrite installed on your server, that’s it.