Before configuring the reverse proxy, ensure you have:
- IIS 7 or later installed on Windows Server
- TeamCity running on Tomcat (default port 8111)
- Administrator privileges on the server
- URL Rewrite 2.0 and ARR 3.0 extensions installed
First, enable proxy functionality in Application Request Routing:
# Open IIS Manager # Navigate to Server Node → Application Request Routing Cache # Click "Server Proxy Settings" on right panel # Check "Enable proxy" checkbox # Apply changes
Add this web.config rule to your IIS site:
<configuration> <system.webServer> <rewrite> <rules> <rule name="ReverseProxy TeamCity" stopProcessing="true"> <match url="^teamcity(.*)" /> <action type="Rewrite" url="http://localhost:8111{R:1}" /> <serverVariables> <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" /> <set name="HTTP_X_FORWARDED_SCHEME" value="https" /> </serverVariables> </rule> </rules> </rewrite> </system.webServer> </configuration>
For TeamCity's real-time features, add WebSocket support:
<webSocket enabled="false" /> <handlers> <add name="TeamCityWebSocket" path="teamcity/app/subscriptions*" verb="*" modules="WebSocketModule" resourceType="Unspecified" requireAccess="Execute" /> </handlers>
- 502 Bad Gateway: Verify TeamCity is running on the specified port and check firewall settings
- CSS/JS not loading: Add URL rewrite outbound rules to fix resource paths
- Authentication problems: Configure proxy-preserve-host header properly
For production environments, consider these ARR settings:
# In Server Proxy Settings: - Connection timeout: 120 seconds - Response buffer threshold: 0 (disable buffering) - Enable disk cache - Set cache size to 256MB
To enforce HTTPS:
<rule name="HTTP to HTTPS" enabled="true" stopProcessing="true"> <match url="teamcity(.*)" /> <conditions> <add input="{HTTPS}" pattern="off" /> </conditions> <action type="Redirect" url="https://{HTTP_HOST}/teamcity{R:1}" /> </rule>
Before we begin, ensure you have the following installed:
- IIS 7 or later with Management Console
- TeamCity running on Tomcat (default port 8111)
- URL Rewrite Module 2.0 (download from Microsoft)
- Application Request Routing 3.0 (download from Microsoft)
First, we need to enable proxy functionality in Application Request Routing:
- Open IIS Manager
- Select the server node in the Connections pane
- Double-click "Application Request Routing Cache"
- Click "Server Proxy Settings" in the Actions pane
- Check "Enable proxy"
- Leave other settings as default
- Click Apply
Now let's create the URL Rewrite rule for our TeamCity instance:
<rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
<match url="^teamcity(.*)" />
<action type="Rewrite" url="http://localhost:8111/{R:1}" />
<serverVariables>
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
<set name="HTTP_X_FORWARDED_SCHEMA" value="https" />
</serverVariables>
</rule>
We need to configure TeamCity to recognize the proxy headers:
- Edit the
<TeamCity>\conf\server.xml
file - Add the following connector configuration:
<Connector port="8111" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="60000"
useBodyEncodingForURI="true"
socket.txBufSize="64000"
socket.rxBufSize="64000"
tcpNoDelay="1"
scheme="https"
proxyName="somesite"
proxyPort="443"
secure="true"/>
For TeamCity's WebSocket functionality to work through the proxy:
<rule name="TeamCity WebSocket" enabled="true">
<match url="^teamcity/app/websocket(.*)" />
<conditions>
<add input="{HTTP_UPGRADE}" pattern="websocket" />
</conditions>
<action type="Rewrite" url="ws://localhost:8111/app/websocket{R:1}" />
</rule>
After applying all changes:
- Restart both IIS and TeamCity services
- Access
https://somesite/teamcity
in your browser - Verify all functionality including:
- Main dashboard
- Build logs
- Real-time updates via WebSocket
If you encounter problems:
- 404 errors: Verify the rewrite rule pattern matches your URL structure
- Connection refused: Ensure TeamCity is running and listening on the correct port
- SSL issues: Make sure your IIS site has a valid SSL certificate
- WebSocket failures: Check that the WebSocket rule appears before the main proxy rule