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:

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.

Audiocodes IP Phone Manager Custom Placeholders

Audiocodes, Audiocodes…oh, Audiocodes. I continually battle with your poorly written documentation for your excellent products. It’s either you write your documentation poorly, I’m just a terrible reader of technical documentation, or maybe it’s somewhere in the middle. Usually I blame myself, but I really think it’s you this time.

AudioCodes Logo

A great example of this is AudioCodes IP Phone Manager Express, a centralized management server for AudioCodes VoIP phones that is free for the first 500 phones purchased. The program sits on top of IIS, installs and utilizes SQL Express, and leverages option 160 (custom option) from DHCP for directing phones for registration. These guys have an excellent write-up on how to install it (just don’t have two option 160s like I did, for some stupid reason).

So you get it installed, phones are registering with it, the wind is against your back, and now you want to customize options. If you follow the administrative manual that comes bundled with the download (or just download it here), you might think you’re limited to just the placeholder values that come with it. Page 21 in the manual demonstrates how to enter the values for the placeholders, but it doesn’t show you where. The manual for the IP Phone Manager (non-express, download it here), has more information to explain what’s going on, but even it lacks some clear, explicit directions for creating those placeholder values.

This is my biggest complaint about AudioCodes documentation: instructions and documentation isn’t always clear and straightforward, written from the perspective of someone installing this stuff.

So how do you create those placeholders? Turns out it relatively simple, and makes sense once you connect the dots.

To create placeholders, you create the variable values in the configuration templates. Go to Phones Configuration > Templates > select the phone template you want to adjust:

IPP Template

In the above example, I’m creating a multicast group for paging. Also, I kept the naming scheme consistent, but you don’t need to include “ITCS_” for the variable, as long as it matches later. (09/22/16) Correction: you do need to keep the naming scheme the same, at least from what I can tell in setting region placeholders. When you enter the placeholder name, IPP appends the name with “%ITCS_<yourPlaceHolder>%”.

Then, you can create your ‘Regions’ for customizing configurations, and then add your customized values to each region like this:

IPP Region Values

Next, change the region of the phone(s), if you haven’t done this already:

IPP Phone Options

Finally, update the phone configurations. Go to Users > Manage Multiple Devices, add the devices you want to update, select the action “Generate IP Phones Configuration Files” or “Update Configuration File”, then click “Generate IP Phones Configuration Files”:

IPP Update Config

Generating will restart the phone, updating will not. I prefer generating, but you may not want to avoid the phone restart.

That’s it.

AudioCodes has a great system here, and it’s pretty cool that it comes free. The only hiccup I’ve encountered with the program so far is that I have some phones that I can’t issue commands to for some reason. There are some users that I can’t put in regions or update configurations, and when I try, IPP tells me that the user is not approved, but when I try to approve the user, it says the user is already approved. It’s very strange, and thankfully I don’t worry about it much because the users are in the default region, but I could see this being an issue for sure. I haven’t reached out to AudioCodes yet for support, but I’ll update something here when I do.

Happy phone managing!

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.

 

Skype for Business: “Prerequisite installation failed: MSSpeech_TTS_pt-BR_Heloisa”

While doing a Skype for Business deployment, I encountered this strange error that was preventing the S4B server components from installing: “Prerequisite installation failed: MSSpeech_TTS_pt-BR_Heloisa”.

The log file showed the following:

languageErrors

After doing some Googling, the consensus was to find the MSI file and replace it.

The file was located here: C:\ProgramData\Microsoft\Skype for Business Server\Deployment\cache\6.0.9319.0\setup\speech\pt-BR\

However, the question was where to get the speech files. I tried getting them from the ISO, but it appeared the files on the ISO were corrupted, so I had to get the files here:

Microsoft Speech Platform – Server Runtime Languages (Version 10.1)

I ended downloading what I needed, but subsequent MSI files were also having problems, so I ended up just replacing MSIs in the the directories “pt-BR” through “zh-TW” just to be safe.

The installation then continued successfully as expected.

Hope this helps someone.

Update (06/07/16): Had this problem again (forgot to replace ISO), and I found out that if you keep the S4B ISO mounted or DVD in the system, then S4B will re-download the bad packages from the ISO/DVD. Dismount or eject the media, then copy the MSI files.

Update 2 (09/20/16): You can also just re-download the ISO. Problem solved. 😀