Skip to main content

IIS URL Rewrite Basic Walkthrough

Over the years doing various Skype for Business deployments, or just doing some vanilla web server work, I’ve needed a reverse proxy that was simple and easy to deploy. There are quite a few out there such as HAProxy (my preference), NGINX, and then some commercial products like KEMP. However, the deployments I was doing didn’t really need the investment of a major appliance, and some of the users I was working with preferred to steer clear of Linux/Unix systems, so a great choice for this is IIS Application Request Routing. This is a simple reverse proxy that, after a few tweaks, can do the job well with minimal effort.

However, I wanted to get a little more complicated with the reverse proxy and it’s URL rewrite rules, so I decided dig in and figure out the URL rewrite logic a little better, which is the focus of this post. This is going to be GUI focused, but there are certainly better ways to do this via XML, but this was the easier approach that I took at the time.

(If you’re looking on how to set up IIS ARR, check this blog out, read the documentation from Microsoft on IIS ARR, or google it.)

Simple goals here:

  • Create two rules to reverse proxy the “cookies” and “cupcakes” traffic to the web server, both for HTTP and HTTPS
  • Create a catch-all rule to send everything else to giantmidgets.org

Setting Up HTTP Reverse Proxy Rule/Back-References Demonstrated

After setting up the server farms that the URL rewrite will direct traffic to, go to the root of the server and open up ‘URL Rewrite’, then I clicked ‘Add Rule(s)…’

Add Rule(s)...

I went ahead and selected ‘Inbound Blank Rule’. I want to keep this simple.

I named it something useful (I’m creating a rule for HTTP and HTTPS separately). Then I put in the pattern I needed:

Routing Rule for Match URL

This is a regex that looks for anything with “www.consentfactory.com/”, and for the URL path to either have “cupcakes” or “cookies”, then whatever string is available after that.

Next, I set up my conditions:

HTTP Conditions

The condition basically requires the FQDN to be present. Next comes the routing rule:

Route to Server farm rules
Something is wrong here.

Here I’m stating that the action type is to route to the server farm (basically the ARR component of this), then to send it as HTTP with the path taken from after the FQDN of the request. However, note the “Path” field; it says “/{R:0}”, but what the heck does that value come from? To see that value, click on ‘Test Pattern’ up at the top of the rule under ‘Match URL’:

Match URL Pattern Test

Input the URL that you’re trying to reverse proxy in the ‘Input data to test’ field, then click ‘Test’. This is actually how you can see those ‘{R:X}’ values will be derived. These are called ‘back references‘, and the format ‘{R:X}’ refers to matching rules from the ‘Match URL’ section. {R:0} will always contain the entire string being sent, which is why my routing action for routing to the web server is incorrect because if I were to leave it like that, anything after the FQDN would be sent, which currently would add “/www.consentfactory.com/cookies” to “www.consentfactory.com”, looking like “www.consentfactory.com/www.consentfactory.com/cookies”.

There are two ways to fix this.

One approach would be to just correct the routing action to use {R:1} and {R:2}, like this:

Routing rules with {R:1} and {R:2} concatenated

However, my preferred approach is to keep the regex more simple, which allows us to use the original routing action of {R:0}, so I configure my regex URL matching to look like this:

Cleaner Match URL with "www.consentfactory.com/" removed

Which tests out our back-reference values to look like this, thereby allowing the {R:0} rule:

{R:0} is cookies/mdm.pdf, {R:1} is cookies, and {R:2} is /mdm.pdf

Now that’s done, the HTTP rule is set up. The only thing left is to set up the HTTPS rule, and a catch all for anything that isn’t in a subdirectory.

HTTPS Reverse Proxy

The HTTPS rule is the same as the HTTP rule, except we adjust the condition to look for HTTPS being used like this:

HTTPS condition is set to 'on'

The routing rule will be configured like this:

Note the 'Scheme' field is set to HTTPS

Catch-All Redirect Rule

Finally, I’m creating a rule to just catch anything that isn’t a specific subdirectory of consentfactory.com. The rule will be the same as the HTTP rule, but the routing action will actually be a redirect somewhere else, like this:

Redirection to Another Site Using 'Redirect', the url of the site, and '301 Permanent' for redirect t ype

Hopefully this helps explain that process a bit. It helps me to see examples, so maybe this will help others.

(Edit (20171023): my HTTPS routing rule image was incorrect. It didn’t use “https://” for the ‘Scheme’, which is what we want it to route to.

Exchange 2016 Updates: Don’t forget to activate the components!

I’ve done a number of Exchange and Skype for Business server deployments over the last year, and recently I moved to Exchange 2016 versus 2013 just to get the deployments up and running on the latest. However, after performing my upgrade to Exchange 2016 (per these instructions), my EWS connections between Skype for Business and Exchange were not working correctly. Of course, Exchange isn’t fully running for anyone, I’m still testing things out, so not a big deal, but still. What the hell is going on?

In S4B, when I run Test-CSExStorageConnectivity, I’m getting “Test-CsExStorageConnectivity : ExCreateItem exchange operation failed, code=50043”.

testcsexstorageconnectivityerror

The standard response, and search result in Google, for a 50043 error is to check and make sure that your “ExchangeAutodiscoverUrl” property after running Get-CSOAuthConfiguration is configured for the Exchange server’s autodiscover metadata json URL (“https://<exchangeAutodiscover>/autodiscover/metadata/json/1”). But what happens if you’ve already checked that? The URL is correct and you’re good to go, so what changed?

Wait, didn’t I say I upgraded to the latest Exchange 2016 CU (CU3)? Did I completely follow the instructions?

Hmm..let’s check the Exchange server components (something new, AFAIK, to Exchange 2016):

Well. Guess I didn’t the follow instructions at the end that states you to have run the following:

Set-ServerComponentState EX2016SRV1 –Component ServerWideOffline –State Active –Requester Maintenance

followtheinstructions

I’m going to start tagging moments like this as ‘ya dummy’ moments.

Now, let’s check the component status:

get-servercomponentsactive

And then running Test-CSExStorageConnectivty works, and all is well.

So I guess one thing to look at if you’re getting a 50043 error and your have the Metadata URL correct is to verify that EWS is running on your Exchange box.

Skype for Business/Lync Server and Exchange UM: Errors with Event IDs 1079 & 1136

During a recent Skype for Business-Exchange 2013 deployment, I tried running all calls to a DID, then to an Exchange 2013 UM Auto Attendant. After some hiccups I had it working, but painfully, dialing by extension and transfers did not work from the Auto Attendant. After doing some investigating, the Skype server wasn’t giving me an errors, and my syslog from the Audiocodes gateway was indicating calls were transferring.

However, the Exchange server gave me two errors regarding unified messaging: 1079 and 1136.

1079:

exUMError1079

1136:

exUMError1136

I tried lots of solutions, tested my environment numerous times, but nothing was working. If you look these errors up when doing a Skype for Business server deployment, you’ll often see Microsoft KB 3069206 come titled, “Exchange UM Auto Attendant cannot transfer calls to a phone or extension number in Skype for Business Server 2015“. Looks great and promising…

…but I’ve already updated the server to the latest CU.

With more Google-fu, I found my solution: I needed to change my certificate for the Exchange server.

According to this TechNet thread, the certificate assigned to the UM services on the Exchange server needs to have it’s subject name be the same as the Exchange UM server’s name. I had used the same UCC-SAN cert for UM services that I set up for the Skype for Business Edge server, and added all the subject alternative names needed.

The fix: perform a new certificate request from the internal CA, apply the certificate to the UM services, then restart the UM services on the Exchange server..

After that, call transfers worked!

Hope this helps someone.

 

Creating New Powershell Virtual Directories in Exchange 2013

I encountered the most bizarre issue: after removing my Powershell Virtual Directory, I could not for the life of me recreate the VD. I continually received the following error:

New-PSSession : [subdomain.mail.domain.com] Connecting to remote server mail.domain.com failed with the following
error message : The WinRM client sent a request to an HTTP server and got a response saying the requested HTTP URL was not available. This is usually returned by a HTTP server that does not support the WS-Management protocol. For more information, see the about_Remote_Troubleshooting Help topic.

Nothing online was helping, until I read something randomly about adding the Exchange Snap-In in a regular Powershell window. So I typed the following in Powershell:

add-pssnapin Microsoft.Exchange.Management.PowerShell.SnapIn

Bingo. Directory created.

Weird.