Configuring TeamCity to use HTTPS/SSL on Windows with a PFX file, and redirecting HTTP to HTTPS
Tonight I'm having fun setting up a new build server with TeamCity. Since my build server is accessible over the internet, I wanted to use SSL. I also wanted requests using HTTP to be redirected to HTTPS.
I ran into a few problems because I was using a wildcard certificate that had been issued from a root CA, while most of the guides focus on using self-signed certificates, but I eventually got it working. Here are my notes in case they help you, or in case I need them later.
My configuration
I'm using TeamCity 7.1.5. I installed TeamCity into a non-standard location, T:\TeamCity
, for reasons I won't go into in this post, so of course the paths I'm using below will be different to yours.
Exporting the certificate
The certificate I'm using is a wildcard certificate that had been issued months ago and installed into the Windows certificate store on a web server. My first step was to export the certificate:
When prompted, the private key needs to be included. The file will be saved as a PFX file:
I secured the PFX file with a password, which I wrote down. Then I copied the PFX file to the server.
Converting the PFX to a keystore
TeamCity relies on Tomcat, so PFX files aren't much use. The next step is to convert the PFX file into a Java Key Store file.
Since these are Java Key Store files, we'll of course be needing a Java tool to do the conversion. But fear not, conveniently there's a Java runtime bundled inside of TeamCity. In my case it's at T:\TeamCity\jre\bin
.
The command to do the conversion was:
T:\TeamCity\jre\bin\keytool.exe \
-importkeystore \
-srckeystore T:\TeamCity\conf\ssl\OctopusHQ.com.pfx \
-srcstoretype pkcs12 \
-destkeystore T:\TeamCity\conf\.keystore2
During this conversion you'll be prompted to enter and confirm a new password for the keystore file that you are creating. You'll also be prompted to enter the password for the PFX file when it was exported.
While you may think you can enter two different passwords here, don't be fooled; make sure you enter the same password for both the new key store and the imported PFX file. Otherwise you'll get an error message when Tomcat tries to load the private key:
java.security.UnrecoverableKeyException: Cannot recover key
You can verify the contents of the keystore file using:
T:\TeamCity\jre\bin\keytool.exe -list -keystore T:\TeamCity\conf\.keystore2
Changing the connectors
Next you need to tell the TeamCity bundled Tomcat server to use SSL. Open T:\TeamCity\conf\server.xml
and look for the <Connector>
elements. I replaced the existing connectors with:
<Connector port="80" protocol="HTTP/1.1"
redirectPort="443"
/>
<Connector port="443" protocol="HTTP/1.1"
SSLEnabled="true"
scheme="https" secure="true"
connectionTimeout="60000"
redirectPort="8543"
clientAuth="false"
sslProtocol="TLS"
useBodyEncodingForURI="true"
keystoreFile="T:\TeamCity\conf\.keystore2" keystorePass="<password used for the PFX and keystore>"
/>
The second connector is my HTTPS listener, the first connector just forwards connections to it. At this stage after restarting TeamCity I was able to browse to either http://myserver
or https://myserver
, but the HTTP endpoint still served the contents over HTTP rather than redirecting to HTTPS.
UPDATE: The example above was for TeamCity 7. For TeamCity 10, use the following connector (thanks to Matt Richardson):
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
SSLEnabled="true"
scheme="https"
secure="true"
connectionTimeout="60000"
redirectPort="8543"
clientAuth="false"
sslProtocol="TLS"
useBodyEncodingForURI="true"
keystoreFile="T:\TeamCity\conf\.keystore2"
keystorePass="<password used for the PFX and keystore>"
socket.txBufSize="64000"
socket.rxBufSize="64000"
tcpNoDelay="1"
/>
According to Matt, that now handles the WebSocket communication and prevents the "using legacy polling" warning showing up.
Requiring SSL
The final step was to edit T:\TeamCity\conf\web.xml
. At the bottom of this file, just before the closing </web-app>
element, I added a constraint to force HTTPS:
<security-constraint>
<web-resource-collection>
<web-resource-name>HTTPSOnly</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Diagnostics
If you have problems with your SSL configuration, the best place to look is:
T:\TeamCity\logs\catalina.*.log
Also, don't forget to enable port 443 in Windows firewall!
This took me a few hours to get working, so hopefully my notes can save you some time. The following resources were helpful to me:
- http://confluence.jetbrains.net/display/TCD65/Using+HTTPS+to+access+TeamCity+server
- http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html
- http://stackoverflow.com/questions/4217107/how-to-convert-pfx-file-to-keystore-with-private-key
- http://devnet.jetbrains.com/thread/304538
- https://community.jboss.org/message/367790?_sscc=t
- http://www.itworld.com/development/79351/how-configure-tomcat-always-require-https