Let’s Encrypt & IIS as reverse proxy with Certify the Web

After I have been running Teamcity and Octopus Deploy behind a Microsoft IIS without a certificate for some years I decided to give it a go again.

The reason it's behind using a reverse proxy:

  • Teamcity is hosted on a Tomcat HTTP Server and Octopus Deploy is self hosted. Both running on a custom port.
  • Limited in the number of external IP's ... the Teamcity and Octopus Server is running on a different host(could be run on the same host since they are running on different post).

Octopus Deploy does Have built-in support for Let's Encrypt but that forces me to run it on post 80, which of the above reasons is not possible.


  1. Install Certify
  2. Edit web.config
  3. Run Certify for the selected sites.

Step 1

Go to Certify The Web and download the latest release. You can find the src for the project on GitHub Certify The Web - SSL Manager

Step 2

Edit the Web.config with the following changes:

<?xml version="1.0" encoding="UTF-8"?>
			  <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
                <rule name="LetsEncrypt" enabled="true" stopProcessing="true">
                    <match url="\.well-known/acme-challenge/*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="None" />
                <rule name="Https redirect" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
                        <add input="{HTTP_HOST}" matchType="Pattern" pattern="^domain.tld$" ignoreCase="true" negate="false" />
                        <add input="{HTTPS}" pattern="^OFF$" />
                <rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_HOST}" matchType="Pattern" pattern="^domain.tld$" ignoreCase="true" negate="false" />
                    <action type="Rewrite" url="{R:1}" />

Explanation of the three rules

  • LetsEncrypt
    • This is to allow renewal of the certificate. This is set before the redirect of requests to HTTPS.
  • Https redirect
    • Force https requests of all request that does not math the above rule.
  • ReverseProxyInboundRule1
    • Rewrite the inbound request to the http webserver which in my environment is hosted on a different server. But might also just be localhost.

Step 3

Start Certify the Web where you will be asked to create a new primary contact.

Fill in the form and click "Regsiter Contact". This information is used when requesting certficates from Let's Encrypt.

Click the "New Certificate".


Select the IIS site you want to create a certicate for.

It will then show the hostname on that site. You can then selected what sites you want to create a Certicate for. Remember this hostname needs to be accessible from the outsite. Hence my name here: 'racing.localtest.me' will work not.

You can also select the primary domain for the certicate if there is more than one.

On the Advanced tab there is diffent options, which I havent used yet. But the web hook option would nice if you want to noticed either when a Success or Error eccours when requesting a new certificate.

If everything goes well you will now have a site running https with a valid and FREE certificate.

How to unit test ASP.NET Web API 2 Route Attributes


What I thought was a simple search on the web turned out to be more than that.

The closets to a solution I found was from the person who first made it possible to use Attributes for routing in ASP.NET MVC 4: AttributeRouting not working with HttpConfiguration object for writing Integration tests

But what about ASP.NET Web Api 2?

HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes(); // This don't work. I guess there is needed some more plumbing to know what Controllers to search for attributes, but I'm lost here.
HttpServer server = new HttpServer(config);
using (HttpMessageInvoker client = new HttpMessageInvoker(server))
    using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://localhost/api/accounts/10"))
    using(HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result)

The solution

So … what is the problem.

It turns of that I was missing a simple little line, just after the “config.MapHttpAttributes();”


So finally I got this working.

But why on earth does the HttpServer class or something else not ensure that the config have been initialized.


So I was searching for a reason why this was needed and why this should actually be called.

If you decompile: System.Web.Http.GlobalConfiguration.Configure(Action<HttpConfiguration> configurationCallback)

You will get something like this:

public static void Configure(Action<HttpConfiguration> configurationCallback)
  if (configurationCallback == null)
    throw new ArgumentNullException("configurationCallback");

Why on earth is it done like that … for me this has absolutely nothing to do with “Ensure” … THIS needs to be called after all configuration is done.

Is can be called multiple times with no side effects.

Why ohhh why do you sometime hate us so much Microsoft. :-)

Avoid razor compile errors in MVC 4 when deploying

Yesterday I yet again experienced, that my MVC 4 build went fine when built and deployed using teamcity, but still a compile time bug sneaked into production.

Then a combination of google and talking to a friend led me to a solution. I short, this allows you to define that views should be compiled with certain targets. As compiling views increases the build time conciderably, you may want to avoid it for local development.

How to configure this is all shown here: http://www.dotnetcurry.com/ShowArticle.aspx?ID=698

Windows Server 2008 R2 takes forever to start up–60 minutes or so

So a few weeks ago I disabled Ipv6 from the Local Area Connection on my Windows Server 2008 R2. I was changing the gateway and I thought, I’m not going to use it, so I could just as well disable it.

The server is running:

  • Active Directory
  • Exchange 2010
  • TFS 2010
  • DNS
  • IIS


Today I decided to install some windows updates. There were about 16 of them, and one for Microsoft Exchange 2010 SP1 Rollup2 ( I think the name was ).

It took forever to install … but finally after 1 hour is was done and I reboot the machine. It took forever to boot up ( Applying computer settings ) … again 1 hour … login took about ½ hour.

I could see it answered on the IP address … so it was not frozen or anything like that. Did a little googling and found a post mentioning NOT to disable ipv6 because some part of Windows Server 2008 R2 can’t function with out it, unless you also do some register editing. Ohh My Freaking God.

Microsoft … I’m sending Sons of Anarchy over to do some payback. Smile

Adding users to a TFS Project from the server

I have a few servers running, but they are all external to me, as they are placed in a data center, so my own computer aren't joined to the domain.

  • SS-Exchange: DC, Exchange

This haven't been a problem before at all. So the other day one of my friends asked if I could host a TFS Project for him on my server. No problem, so I created the user in the DC, created the project and the last thing to do was just to add him to the project so he would have access to it, and then the problems started. As my own computer was not part of the domain, I could only add local users, from my own computer. I hadn't been a problem before as my user was “TFS Administrator” so I had access to all projects.

So I started binging/goggling the net, but to no avail. I was puling my hair out … ARGHH.

Then I decided to ask a question on serverfault with the title TFS 2010 - Adding users to a Team Project. Is was slow with comments in the start, but there come a few, buy they did not really help me much.

So I thought it was not possible at all, and a BIG #FAIL by Microsoft.

Then a Anthony come with an interesting comment you can read here.

So I started looking around again as I could not make his suggestion work, probably because I did something wrong since it worked for him. But when jumping around in the “Team Foundation Server Administration Console” I found what I had been looking for all the time. Not the first place to look … but here are the details needed.

Follow the numbers on the above picture.

Again, click the number in the order.

Follow the numbers as before.

The rest for here should be like a walk in the part. God darn this is a well hidden feature that its done from the “Valid Users” properties on the group. But is was here.

Moving a table to another filegroup

So, how does one move a table to another filegroup.

Say I have the following table:

CREATE TABLE [dbo].[Tests](
    [TestID] [int] NOT NULL,
    [TestInt] [int] NOT NULL,
    [TestBigInt] [bigint] NOT NULL,
    [TestID] ASC

Since tables are always stored with the clustered index. Moving the clustered index, also moves the table. So if we want to move the table, we can recreate the CLUSTERED index on another storage group. Here we are moving from “PRIMARY” to “PRIMARY2”.

   ON dbo.Tests(TestID)

This can also be done when the table is online and is also moving the indexes. There are some performance diff if you are moving the table while its still online, so consider if its worth the extra overhead.

You can extend the relation index options with the create index command like this, to move it while its still online.

   ON dbo.Tests(TestID)

Find duplicate rows in MS SQL

So, the other day I was reading T-SQL: Why “It Depends” and in the comments section a guys suggested using the “PARTITION BY” in the OVER clause.

I thought was the heck does that do … so i searched the web for an answer … and wow … what a great way to find duplicate post … and possible also a lot of other things it can be used for that I haven’t thought about.

To the code …

	,CID, Added
FROM Servers
SELECT * FROM Data Where DupeNumber >= 2

This will check for dupes on the CID column … and then select all the rows where DupeNumber is over or equal to 2. You could then instead of select it … you could delete it.

Fancy way … I like it.