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.