WordPress Networks & IIS Rewrite Rules on Azure App Service

Standard

This is a bit of an extension to my previous post.

One of the last blogs I moved was a MU or a multi-user WordPress blog, which is now known as a Network. This turned out to be a bit more challenging than the single WP blogs. To setup a new instance, these instructions should mostly do the trick however, based on my testing you’ll still need the rewrite rules below.

From this post and this post, I was able to assemble the following rewrite rules that have worked for my WPMU blog running on the Azure App Services (as of Sept. 13, 2016)! Don’t miss the <httpRedirect enabled="false" ....> line at the bottom – that was very important. You’ll also need those MU settings out of your wp-config.php file too.

web.config:

<system.webServer>
<rewrite>
<rules>
<rule name="WordPress Rule 1" stopProcessing="true">
<match url="^index\.php$" ignoreCase="false" />
<action type="None" />
</rule>
<rule name="WordPress Rule 2" stopProcessing="true">
<match url="^([_0-9a-zA-Z-]+/)?files/(.+)" ignoreCase="false" />
<action type="Rewrite" url="wp-includes/ms-files.php?file={R:2}" appendQueryString="false" />
</rule>
<rule name="WordPress Rule 3" stopProcessing="true">
<match url="^([_0-9a-zA-Z-]+/)?wp-admin$" ignoreCase="false" />
<action type="Redirect" url="{R:1}wp-admin/" redirectType="Permanent" />
</rule>
<rule name="WordPress Rule 4" stopProcessing="true">
<match url="^" ignoreCase="false" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="WordPress Rule 5" stopProcessing="true">
<match url="^" ignoreCase="false" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
<add input="{URL}" pattern="([a-zA-Z0-9\./_-]+)\.axd" />
</conditions>
<action type="None" />
</rule>
<rule name="WordPress Rule 6" stopProcessing="true">
<match url="^[_0-9a-zA-Z-]+/(wp-(content|admin|includes)?.*)" ignoreCase="false" />
<action type="Rewrite" url="{R:1}" />
</rule>
<rule name="WordPress Rule 7" stopProcessing="true">
<match url="." ignoreCase="false" />
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
<httpRedirect enabled="false" destination="http://www.examplesite.com" />
</system.webServer>

wp-config.php:

define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'www.examplesite.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);

WordPress on Azure App Service using MySQL In-app!

Standard

Well, after a very long hiatus from blogging, I thought it was about time I started again. And what better way to start than with an update to my previous post on hosting your WordPress blog in the Azure App Service!

If you have been watching the Azure blogs, specifically from the App Service Team, you may have noticed an interesting one titled “Announcing MySQL in-app (Preview) for Web Apps“. For those of us that just want to host a small blog somewhere and are not concerned about scaling the web app across multiple instances (aka no auto-scaling), this is a pretty intriguing option. I should also note that as of writing this post (September 12, 2016), MySQL in-app is still in preview and not yet at general availability. You should take a look at the product team’s post for a full list of limitations.

Migrating to this service was fairly straightforward! Below is the approach I took.

  1. You’ll need to have an App Service Plan for this. I prefer to create a plan before the web app, but you can create both at the same time. Here’s some quick instructions on how to create one. When selecting a specific plan type (Free, Shared, Basic, Standard, or Premium), you should make yourself aware of the limitations to each plan. For example, Always On is not supported by Free and Shared plans. Backup is only support in Standard and Premium. RAM scales up as the plans go up. You can always scale up and down after you create the plan too.
  2. Create your new web app. For this you’ll want to pick the ‘WordPress’ template. This link will get you right to the correct blade in the Azure Portal.
  3. Fill out the fields as per your requirements. For the Database Provider field, be sure to pick “MySQL In App (Preview)” as shown below. Application Insights is enabled by default, your call on leaving this way. There is a WordPress plugin to fully enable it in your blog should you so desire however, I am not sure how frequently it’s maintained, so use as your own risk. I do have plugin version 2.2 running on my blog, which is at version 4.6.1.
  4. Once your web app is spun up, there’s a few things I like to do and these are optional:
    • Configure your custom domain, found under Custom domains > Add
    • Enable Always On, found under Application settings > Always On.
    • Turn off the Affinity Cookie because you can only have a single instance of your site using MySQL in-app., found under Application settings > APR Affinity. More info here.You’re now ready to migrate your blog over to your new web app!
  5. For moving MySQL, I grabbed a backup of the database in .sql format. You may need to compress it of it’s greater 8MB. You’ll need to take that file and import it into your MySQL instance. Because it’s in a protected sandbox environment, MySQL cannot be accessed remotely so you’ll need to use phpMyAdmin. To get there, open the “MySQL In App (Preview)” blade in your web app and click “Manage” as show below. Once in phpMyAdmin, make sure there’s an empty DB called “azuredb”. Select it, click the “Import” tab and follow the instructions.
  6. Next up – your content! You’ll probably need everything in your WordPress home directory including things like the folders wp-admin, wp-content, wp-includes, and files wp-config.php, wp-login.php to name a few. Once you’ve got the files required all together, you’ll need to make a small change to your wp-config.php. From the product team blog post mentioned above, they include some sample code for parsing the db connection string provided by the app service. I’ve included it below. Be sure to just replace the MySQL settings in your wp-config.php or your site may not work. You may also need to adjust an references to the home directory, if a plugin has added them to your wp-config.php. The web app hosted home directory will be “D:\home\site\wwwroot”. Good idea to keep a backup of that file as well.
    /*Add at the begining of the file*/
    $connectstr_dbhost = '';
    $connectstr_dbname = '';
    $connectstr_dbusername = '';
    $connectstr_dbpassword = '';
    
    foreach ($_SERVER as $key =&gt; $value) {
        if (strpos($key, "MYSQLCONNSTR_localdb") !== 0) {
            continue;
        }
        
        $connectstr_dbhost = preg_replace("/^.*Data Source=(.+?);.*$/", "\\1", $value);
        $connectstr_dbname = preg_replace("/^.*Database=(.+?);.*$/", "\\1", $value);
        $connectstr_dbusername = preg_replace("/^.*User Id=(.+?);.*$/", "\\1", $value);
        $connectstr_dbpassword = preg_replace("/^.*Password=(.+?)$/", "\\1", $value);
    }
    
    // ** MySQL settings - You can get this info from your web host ** //
    /** The name of the database for WordPress */
    define('DB_NAME', $connectstr_dbname);
    
    /** MySQL database username */
    define('DB_USER', $connectstr_dbusername);
    
    /** MySQL database password */
    define('DB_PASSWORD', $connectstr_dbpassword);
    
    /** MySQL hostname : this contains the port number in this format host:port . Port is not 3306 when using this feature*/
    define('DB_HOST', $connectstr_dbhost);
    
  7. Upload your files to your web app. I used FTP to move them, FileZilla specifically, but use whatever works best for you. Make sure your WordPress root ends up under “D:\home\site\wwwroot”. As a best practice, I delete the WordPress files created as part of the web app creation, but do what you think is best. You can find your FTP credentials under the Properties blade. I prefer to use FTPS whenever possible. If you don’t know your FTP user’s password, it can be reset under the Deployment credentials blade.
  8. You may need to adjust any DNS entries to reflect the different host and to align with your WordPress config. I use Fiddler to run a quick test to make sure the site is operational and run some quick tests before I flip my DNS entries.
  9. One last thing to do – update your Permalinks config. In your blog, just go to Settings > Permalinks, validate that your preferred structure is selected and click ‘Save Changes’. This will cause your web.config file to be updated to correctly support permalinks. This is especially important if you have moved from Apache on a Linux box. Other than that – you’re all set!

Hopefully that helps you move your blog to an Azure Web App using MySQL in-app…. And yes… this blog is hosted in an Azure Web App with MySQL in-app.

Hosting a WordPress Site on Azure Web Apps

Standard

As I am sure you’ve been able to guess, this site WordPress is hosted on Azure using an Azure Web App with a ClearDB hosted MySQL database behind the scenes. It’s fairly straightforward to set this up, but I have found lately that I need to use both Azure Preview Portal and the current Azure Portal for best results. Here are the steps I follow:

  1. Create your MySQL database.

    I use the Azure Preview Portal for this as the integration with ClearDB is much more complete, in fact, you may not even realize it’s a different service provider in the background. I know you are supposed to be able to do this together with creating the “Scalable WordPress” app under “Web + Mobile” , but I find it often doesn’t allow you to select the Mercury (free) or Titan ($3.50/mo) pricing tiers for the database. Fill in all the blanks being sure to set the location to the same location that you want to host your WordPress app in. It’s good to create a new Resource Group here which will also be used with your Web App.

  2. Create your WordPress Web App.

    Switch over to the Azure Portal. Reason being: The preview portal doesn’t let you select the MySQL database created in step #1. In the Azure Portal, select “Web Apps” and then click the new button. You’ll be able to find “WordPress” under the “From Gallery” category.  Give it a Url. Under Database be sure to select “Use and existing MySQL database”. Select the correct “Subscription” (aka “App Service Plan”) under Webscalegroup and the correct subscription under “Subscription” (clear as mud, right?). Lastly there are a bunch of Deployment Settings to complete. These deployment keys can be generated here. As I am sure you have noticed, they cannot be directly copied into the Configure Web App screen in the Azure Portal and even if you could, some of the characters are not valid for Azure. To fix this up, Luis Cantero has published tool to help you out. It can be found at the bottom of his post on this very topic. As his instructions state: “Just paste the entire code from the WP API above and press the button”. Simply grab that result from key generator, publish it in his tool, then copy each of the individual keys to the corresponding line in the Configure Web App screen. Once you’re done, click the next button ( forward arrow), select the database you created in step one, review and accept the term, and click the check button to create your site. It will take a few minutes for the site to create, be patient and then head over to your azurewebsites.net url, run the wizard and you’re all done.

Happy Blogging!

Uploading a File to an Azure Storage Container

Standard

Here’s the scenario: You have a file or blob of sorts that needs to be stored in an Azure Storage Container. That’s great – how do you get it to the container?? I have done this a few times and PowerShell is definitely my preferred method but I can never remember the steps. So, for my benefit and maybe others, here they are:

1: Get-AzurePublishSettingsFile

This will actually pop open IE (or your default browser), have you log into Azure, and then automatically download a .publishsettings file. You’ll need this file to import and set up your subscriptions. More information on this command can be found on MSDN here.

2: Import-AzurePublishSettingsFile <pathToPublishSettingsFile>

This import command does exactly as it describes, allows you to import the .publishsettings file from step 1 to your local PowerShell environment. When this import completes, it will tell you which subscription (only matters if you have multiple) has been set as the default subscription. If you need to change this, use step 3, if not, proceed to step 4. More information on this command can be found on MSDN here.

3: Select-AzureSubscription <subscriptionName>

This command is optional and simply sets the current Azure subscription to be used in the existing context. More information on this command can be found on MSDN here.

4: $context = New-AzureStorageContext -StorageAccountName <storageAccountName> -StorageAccountKey <storageAccountKey>

This command generates a new Azure Storage Context and stores it in the variable $context. This will be used to tell PowerShell where the new blob is going to be stored in Azure. Your storage account name and key are both found within the Azure management site. More information on this command can be found on MSDN here.

5: Set-AzureStorageBlobContent -Blob “<blobName>” -Container <containerName> -File “<sourceFileName>” -Context $context -Force

This is where the magic happens. Set-AzureStorageBlobContent, again, does exactly as it describes. The Blob parameter is what the file (or blob) will be called once uploaded to the Azure container. Container is the target container within your Azure storage account. The File parameter is the full path and name of the source file that you want to uploaded to the Azure container. Context is the context variable from step 4. Once executed, you will see a status appear at the top of your PowerShell console which shows the percentage uploaded until the upload is complete. More information on this command can be found on MSDN here.

For bulk uploading, the best thought I have is to read a directory that is to be uploaded, then run this command in a loop. If anyone has a better way – please feel free to comment on this post and I’ll update it and give credit for the suggestion!

Visio Shapes for Office 365 / SharePoint 2013

Standard

This little things are pretty useful for diagramming out Office 365 & SharePoint 2013 environments: http://www.microsoft.com/en-us/download/details.aspx?id=35772

One little trick to using them: After you add the shape to your diagram it will be blue, just turn off the theme for that item (or select many and turn of the theme for them all).

Creating a Site-to-Site Connection between Azure and pfSense 2.0.0.3

Standard

This was a big of a tricky endeavour and obviously a topic that I I don’t typically cover on this blog.  The whole reason for the post actually directly relates back to my Moving to Office 365 post as I haven’t get succeeded in moving enough of my operations to the cloud such that I am not dependent on my main internet connection any more.

I was able to find a few resources on this topic which were helpful with my initial configuration:

How you can connect an Azure cloud to a pfSense network over IPSec – Excellent how-to article to get you started!

After repeatedly not successfully establishing a connection between the two networks and only seeing ERROR: invalid flag 0x08 in my IPsec log I concluded that something had changed after the articles were written.  After lots of digging I found couple changes which were required:

1) The first thing I found in this article which indicated that the encryption algorithm had moved to AES 265 from AES 128.  Change made, still saw the same error.

2) The second obvious thing missing from the above article is after step 12 (Create Gateway).  Along with the Create Gateway function now, you have the choice of creating a Static Routing or Dynamic Routing Gateway.  Doing a bit more research I came across this (same as issue 1) article which recommends that you create a dynamic routing gateway.  Fair enough, it sounds like it would be the easiest for me to maintain.  WRONG! Scrolling further down that article, you find the ‘Key exchange’ property, on a static routing gateway it is IKE v1, on a dynamic routing gateway it is IKE v2.  What is the significance of this you ask? I refer you to this discussion on the pfSense form.  IKEv2 is not supported by racoon which is the foundation of the pfSense IPSec implementation.  A quick removal of my current Azure gateway and creation of a static routing gateway worked beautifully!  Connection established!

 

 

Moving to Office 365

Standard

With the full GA release of Office 365 Wave “15”, I thought it was about time I started to really see what I could do with this platform.  I have been an avid SkyDrive and Outlook.com user for my personal email for sometime now, so why not see what else I can do with the cloud & Office 365 with my little experimental company.  I should also mentioned that my little company is a Microsoft registered partner and I have enrolled in the Cloud Essentials program to make this endeavour a bit more cost effective.

My objectives for this experiment:

  1. Enable Office 365 for my company and federate authentication with my on-premise Active Directory
  2. Federate my on-premise Active Directory with Azure Active Directory
  3. Leverage Windows Intune to decommission my on-premise System Center deployment

My primary reason behind federating with Azure Active Directory for is really for the challenge – just to see if I can do it.  However, secondary to that is that I am normally working remotely and of course, I would not be very happy if my my company internet connection was down and I could not log into my Office 365 account.  I am aware that I could use the Access Control Services that come with Office 365 and DirSync, but realistically my company may want to authenticate more than just Office 365 against my on-premise Active Directory.

Here is a nice video that explains how this federation works.

Here is a little diagram of my current state:

Experiment-CurrentState

And here is one of my end-state goal:

Experiment-EndState

Thank you to Buck Woody for the very nice Azure Visio shapes!

I’ll be honest – I think this plan is going to work based on what I have read, but I really don’t know fore sure.  I will continue to update this post with my full experience as I plug away at this experiment.

——————————

Update 1 (March 6, 2013 8:55 AM MT):

Currently provisioning an new Windows Server 2012 VM using Hyper-V.  I will be adding  the Active Directory role to this server and joining it to my existing domain.  This server will be used to federate with Azure Active Directory for authentication.

Office 365 account is setup and running with my domain. Just waiting to finish with Active Directory before adding user accounts.

——————————

Update 2 (March 6, 2013 10:50 AM MT):

Server 2012 deployed with Active Directory and Active Directory Federated Services running.  Server is joined to my existing domain and has been promoted to a domain controller.  ADFS has been configured and after getting myself a trial SSL certificate, I have been able to add it to my Azure Active Directory service.  This part was surprisingly easy, just ran through the wizards that came with Server 2012 and it appears to be working.  Don’t forget that ADFS has to have port 443 open on your firewall.

Next steps: Prove that my Azure AD is working / provide authentication services and figure out how to connect it to Office 365.

——————————

Update 3 (March 6, 2013 1:45 PM MT):

There seems to be a very distinct difference between the ‘Active Directory’ service you can use via https://manage.windowsazure.com and the Active Directory that is found at https://activedirectory.windowsazure.com.  As far as I can tell, they are both based on the same under-lying service – ACS – but they both seem to offer very different interfaces.

Best I can figure right now, federation was not the correct route.  I should have gone down the DirectorySync (DirSync) route from the bigging.  Now to demote my newly promoted DC and turn it into a DirSync box.  More info here.

And a good article on demoting a Server 2012 Domain Controller.

——————————

Update 4 (March 6, 2013 3:20 PM MT):

——————————

Directory Sync is up and running… and syncing all my user accounts and service accounts.  Given that this is really an experimental Active Directory, there are a lot of service accounts.  DirSync really wasn’t too bad to get going.  Just took time reading through the guides and waiting for components to install.

Next tasks: Try to filter the user accounts that are sync’d via DirSync and take another crack at SSO.

One good thing to remember: DirSync cannot be on a Domain Control or server running ADFS.

——————————

Update 5 (March 6, 2013 9:10 PM MT):

After lots of research and testing, I have determined that because I signed up for Windows Intune, I am stuck on an Office 365 Wave 14 tenant for the time being.  Service request is open with Microsoft to see if I can do anything about this.  Haven’t found a way to force an upgrade yet either.

Still working on SSO.

——————————

Update 6 (March 6, 2013 10:10 PM MT):

A very helpful post from Sean Deuby seems to be debunking my theory about using Azure Active Directory as an authentication mechanism for my Office 365 tenant:

“If you’re running Office 365 with the federated identity + directory synchronization option, you’re already running a hybrid Active Directory where your user’s on-premises AD identity is authenticated to Office 365 via federation and their accounts are provisioned or de-provisioned in your own little cloud AD via the dirsync process.”

I may need to take a closer look at using an Azure VM if I want to achieve this type of authentication distribution as highlighted in this StackOverflow post.

——————————

Update 7 (March 11, 2013 7:30 PM MT):

Well, this sure is proving to be an adventure. After 5 days, numerous emails and phone conversations, the closest I am on getting my tenant either upgraded to Wave 15 from Wave 14 or just simply getting it deleted so I can associate a new tenant with my partner account is being told to contact the partner support group.  I did attempt that today. Tried giving them a call at 6:00 PM PT – the referral I got said that their hours were until 6:30 PM PT time – no luck.

Will update again soon.

——————————

Update 8 (March 12, 2013 10:10 AM MT):

Success! If you are registering as a Microsoft Partner and did not have a Wave 15 tenant – deal with partner support.  I had to end up giving up my original onmicrosoft.com domain, but I also had nothing in my tenant so it didn’t really matter to me.  If you don’t want to give up your onmicrosoft.com domain or you have content that you don’t want to lose, you have to wait for the upgrade email.

On to doing what I started!

——————————

Update 9 (May 17, 2013 12:30 PM MT):

Well, I have managed to get a Wave 15 tenant all set up (got busy of course and this little initiative has taken a bit of a backseat).  I have spend some time researching cloud authentication strategies and I *think* password sync with Azure Active Directory is possible, but only with Windows Server 2012 Essentials.  Here is my current evidence for this.  Hopefully I have more time in the coming weeks to to dig more into this.

On the flip side, I do have DirSync running and only synchronizing a subset of my user accounts (have lots of service accounts that certainly don’t need to be in Azure AD).  That was fairly easy to set up.  Haven’t gone for SSO yet due to the high risk of auth failures if my on-prem connection is down.  Going to take another look at the VPN options from Azure VMs as well.

——————————

Key Learnings:

  • If you’re going to integrate Office 365 with your on-premise environment, start here.
  • If using Azure Connect to an on-premise DC, be sure to populate the Azure VM’s IPv6 DNS address with your on-prem machines Azure Connect IPv6 address.

Resources: