Serve To Me Windows

Posted on  by

When you're thinking of a development, local web server with PHP you're probably thinking of an AMP stack: Apache, MySQL and PHP. In some cases your live environment may dictate using Microsoft Internet Information Services (IIS) -- typically the case with corporate deployments or when you're working with a client that's invested in the Windows platform. In those cases you are better off using IIS yourself to prevent nasty surprises from discrepancies between your local and live environments, most notably the fact that IIS does not understand .htaccess files.

In this article we will see how to create a local IIS development server on Windows 10 Professional with multiple versions of PHP and MySQL.

Prerequisites

But Windows Server 2016 and Windows Server 2019 are built on Windows 10, which means apps heavily dependent on the OS ecosystem might be hard to move since the internals are so different. The Welcome screen may be displayed for 30 seconds, and the logon script interacts with me when I try to log on to a computer that is running Windows Vista or Windows Server 2008 Problem description. On a computer that is running Windows Vista or Windows Server 2008, you enabled the 'Run logon scripts synchronously' Group Policy.

Make sure that you have Windows 10 Professional or Enterprise. As far as I can tell you only get IIS Express on Windows 10 Home which is not the same thing. Opinions seem to differ, even on the official support forums. If you have trouble finding some of the features and options in this article on Windows 10 Home you need to upgrade to Professional.

Running server software is taxing for your computer's CPU, disk and memory. While not absolutely necessary, I recommend an Intel Core i5 or AMD Ryzen 5 processor, an SSD and 8GB of RAM. More is better. I am writing this tutorial on a 2013 Intel NUC with an underwhelming laptop-class i5-4250U CPU, 16GB of 1666MHz RAM and an NVMe SSD. The SSD and extra memory, even if it's of the slow kind, make all the difference in the world.

Installing IIS

Press the Windows key and the R key at the same time to get the Run dialog. Type appwiz.cpl and press Enter. This opens the Programs and Features control panel page.

On the left hand side menu click on Turn Windows features on or off. A new dialog, Windows Features, appears. Under Internet Information Services select the following features (select the features in bold type):

  • Web Management Tools
    • IIS Management Console
  • World Wide Web Services
    • Application Development Features
      • CGI
      • ISAPI Extensions
      • ISAPI Filters
      • Server-Side Includes
    • Common HTTP Features
      • Default Document
      • Directory Browsing
      • HTTP Errors
      • HTTP Redirection
      • Static Content
    • Health and Diagnostics
      • HTTP Logging
      • Logging Tools
      • Request Monitor
      • Tracing
    • Performance Features (the entire subcategory)
    • Security
      • Basic Authentication
      • Digest Authentication
      • Request Filtering
      • URL Authorization
      • Windows Authentication

Your selection should look like the following picture:

Click on OK and follow the prompts on your screen to reboot your computer after the installation is complete.

Installing PHP

You can download pre-built PHP binaries for Windows from the official PHP site for Windows. You need to download the ZIP file for the Non Thread Safe edition of the PHP version you need. For example, if you have the 64-bit edition of Windows 10 you need to download the x64 Non Thread Safe edition, the first link in this box:

For this tutorial I downloaded PHP 7.2, 7.3, 7.4 and 5.6.

Take stock of the VC15, VC14 etc prefixes in each version of PHP you downloaded. You will need to download and install the respective Microsoft Visual C++ redistributable package that corresponds to it. Look on the left hand side on the PHP site. For example, this is the file for VC14 and VC15 that's suitable for 64-bit Windows 10 installations.

Create a directory C:PHP and put each version of PHP in a subdirectory. For example, PHP 7.4 is to be extracted in the directory C:PHP7.4. The following screenshots should give you a better idea.

For each PHP version you need to copy the php.ini-development file to php.ini and edit it to configure your version of PHP. This is inside each PHP version's folder, e.g. C:PHP7.4php.ini.

I made the following changes in my INI files:

The first two lines address the unrealistically small upload size limit. You need it to be substantially bigger to install Joomla extensions and WordPress plugins using the upload method, for example.

The rest of the file is what I explained in my article on improving PHP performance on Windows.

Please note that the XDebug section only makes sense if you are installing XDebug. You can download it from PECL but please make sure the version you download corresponds to the PHP version you are installing it for. You also need to uncomment and adapt the zend_extension line.

Installing MySQL

Download the Windows MySQL installer. The link is for version 8.0 (the MySQL version following 5.7; it's a weird versioning scheme, I know). Run it and follow all the on-screen prompts to install MySQL. It should be self-explanatory.

First time setup

Before you create your very first site on IIS we're going to make some environment changes to save our sanity later on.

Install the PHP Manager

Using PHP on IIS is notoriously complicated and frustrating. Unless you use PHP Manager for IIS. This nifty IIS add-on handles all the nitty-gritty details for you. Go ahead and install it.

Now we need to run the IIS Manager application to configure it. Hold down theWindows key and press R to open the Run dialog. In there type InetMgr.exe and press Enter.

Double click on the PHP Manager icon (highlighted in the screenshot above).

Under PHP Setup click on the Register new PHP version link.

The dialog that opens allows you to register a new PHP version with the PHP Manager. Enter the path to your PHP version's php-cgi.exe file e.g. C:PHP7.4php-cgi.exe and press OK. That's it.

Repeat for all PHP versions you've installed.

If you've ever had to manually set up PHP on IIS you're probably crying with joy. If you never had to do that, trust me, this was a super easy process compared to what we had to do a few years ago...

Import self-signed TLS certificates for HTTPS

I've written before how to forge your own SSL (TLS) certificates for HTTPS development on local Windows servers. However, the resulting .crt files are meant to be used with Apache and are not compatible with IIS. We have to convert them to a format IIS understands and import them before we start defining sites on IIS.

While there are online converters that will do that for you I don't trust them. Maybe I'm paranoid. Maybe it's me having spent a long time doing web application security. In any case, we'll be using the OpenSSL command line.

You will need the following files:

  • certificate.key.pem Your certificate private key file
  • certificate.cert.pem Your certificate file
  • ca-chain.cert.pem The Certification Authority chain file

If you were following my tutorial for SSL certificates open a PowerShell terminal and run the following from your CA path:

Windows

You will need to enter the key file password (called chageme in the other tutorial) and a password for the PFX file.

Now go back to IIS Manager and click on Server Certificates.

From the right hand menu choose Import...

An Import Certificate dialog opens.

Browse to your certificate (PFX) file you created earlier and enter the password you used when creating it. Select the Web Hosting certificate store and check the Allow this certificate to be exported box. Click on OK to finish importing the certificate. You are now ready to create HTTPS sites!

It's important to know that this will only work reliably if you've followed the instructions on my other tutorial on letting all browsers trust your custom certification authority. If you skip that step browsers will tell you your site is insecure and will refuse to connect to it.

Using an application pool

By default, each site on IIS runs under its own Application Pool. The Application Pool determines which Windows user is accessing the files on your computer when you load a page on said site. This doesn't make sense for our local development environment because it makes management of Windows access controls unnecessarily complicated. We are going to instead use one Application Pool for all of our sites.

Go back to IIS Manager and click the Application Pools item on the left hand side menu.

Click on Add Application Pool... from the right hand side pane.

In the dialog enter the name Dev Sites. If you choose a different name you will have to adjust the following instructions accordingly.

Set the .NET CLR version to No Managed Code. We are creating and Application Pool for PHP sites, we are not going to be running any .NET code.

Leave the other options as-is and click on OK.

We are now going to create a folder for our sites under your user account.

Go to your user account's home directory (%UserProfile%) and create a folder named Sites.

Right click on the folder and select

Sites folder Properties, then click on the Security tab. Click on the Edit button to change permissions. Click the Add button to add a user group for access control.

In the big search box enter IIS AppPoolDev Sites and click on Check Names. It will become underlined.

You might wonder what just happened. There is no such user or group on your computer if you search for it! IIS creates that special user group when it starts the Application Pool. All sites under that Application Pool will be using this Windows user group to access the files. And no, you cannot see it if you are looking for it. You will only know how to find it if you read Microsoft's documentation on Application Pools.

Back to the Permissions for Sites dialog click on Dev Sites and choose Allow under Full Control. This allows IIS to have read and write permissions to this folder which is required for mundane tasks like installing Joomla or WordPress and their extensions and plugins.

Important note: if you are going to be using symlinks or folder junctions to other directories from your sites you need to repeat the permissions exercise for these other folders as well. Otherwise IIS will not have access to the linked files and folders. Of course this only applies to advanced users like yours truly and I'm mentioning it because I typically read my own blog posts as reference when I have to resolve some stupid issue after installing a new computer...

Domain names for your sites

There are two ways to set up your IIS environment.

One way is to create a single site that responds to localhost URLs, e.g. http://localhost/example. That's the default configuration of IIS out of the box and I strongly discourage it. All your sites will be set up as subdirectories of a single domain name which carries significant implications e.g. in how images will be inserted into articles or pasting relative SEF URLs / permalinks instead of using your CMS' article link features. If you value your sanity don't do it.

Windows

The other way is using a different domain name for each of your sites. What I mean with this is using something like http://example.local.web for your site instead of http://localhost/example. This is how I am setting up my local servers and what I'm using in this tutorial.

There are two ways to go about these domain names for local development.

The first one is to use a real domain name under your control that you don't otherwise use for any purpose (in other words, one of the domain names you bought a while back thinking you'll do something with it but never got around to it) with a DNS service such as Amazon Route 53. The A record you create must point to 127.0.01 and all subdomains set up as CNAMEs. If your domain is example.com its A record would be pointing to 127.0.0.1, site.example.com would be a CNAME to example.com, site2.example.com would be a CNAME to example.com and so on and so forth. Make sure the TTL of the domain record is rather short to prevent long delays between setting up a subdomain and being able to use it. The drawback is that you need a DNS server or service and the technical know-how to set it up. Moreover, this solution only works if your computer is on-line which may not be the case for a laptop or if you're working with spotty Internet coverage (e.g. when you're waiting for a month for your telco to reconnect you to the Internet after moving houses and have to rely on a very expensive and limited 4G connection; been there). If all that sounds like arcane knowledge please read on.

The second and more straightforward method is using 'fake' domain names which only resolve on your site using Windows' hosts file. Traditionally, this required editing files by hand. However, there's an app for that: Hosts File Editor. Yes, it requires elevated privileges because the hosts file is a system file and requires those privileges.

In the IP Address always enter 127.0.0.1 i.e. your localhost IP address. In Host Names enter your fake domain names separated with spaces. I use the convention sitename.local.web but you could use anything you want as long as it's not a real domain name you want to access over the Internet (the hosts file has priority over DNS). For example, your site would be www.foobar.web or www.mysite.david. Keep in mind that foobar.web and www.foobar.web are two different host names therefore you must enter BOTH, separated by a comma, if you plan on using both of them for your site.

Also keep in mind the checkbox at the very left of each line. You need to check it for the line to be active. Inactive lines take no effect. And do remember to Save (top left in the toolbar) when adding or modifying host names.

Creating sites

Go back to the IIS Manager window and click on the Sites entry. This is where we're managing our sites.

From the right hand pane click on the Add Website... link.

In the dialog that opens enter a Site Name. This is just for your reference. Enter whatever you want here.

Click on the Select... button next to the Application Pool and choose the Dev Sites application pool we selected earlier. Remember, this is important for access control. If you forget to set it you'll have to come back and fix it because your site won't be loading!

In the Physical path navigate to the directory which will be holding your site's files. It must be a subdirectory of the Sites folder we created earlier. Remember, the reason we're doing that is to avoid access control issues.

Leave the type to http and IP address to All Unassigned and Port to 80.

Under Host Name enter one of the domain names you created earlier, either through DNS or via Hosts File Editor.

Click on OK. Your local site is now operational.

If you want to add HTTPS or another (sub)domain the site should be listening to, first select the site you want to modify from the left-hand pane. From the right hand pane select Bindings...

Serve To Me Windows

In the new dialog click on the Add... button. Hey, that looks familiar, doesn't it?!

For HTTPS set the Type to https and enter the same Host name as before. Leave the IP address to All Unassigned and Port to 443.

Select the Require Server Name Indication. This is required because you'll eventually have more than one site listening to the same IP address (127.0.0.1).

Remember to select the SSL certificate you imported earlier. Finally click on OK.

If you want to set up another hostname (e.g. the www subdomain) click on Add... again. This time repeat the process once for HTTP (for the www subdomain) and once again for HTTPS.

If you have more than one local sites you want to set up repeat the entire process under Creating Sites once for each site you want to create.

Web.config

Remember when I said in the very beginning that IIS doesn't support .htaccess files? It has its own type of site configuration file called web.config and which is an XML document. This file is used to set up things like URL rewriting (mandatory for Joomla SEF URLs and WordPress permalinks) as well as other types of fine tuning of the site.

If you are installing a Joomla site remember to rename the web.config.txt file to web.config to enable SEF URLs with rewriting -- strongly recommended mode of operation.

If you are installing a WordPress or ClassicPress site you'll be disappointing to find out that the Codex doesn't have anything for you. In fact, WordPress was only ever meant to be used with Apache. However, there are third party solutions to that.

Serve To Me Windows 8

Is it worth it?

As with everything else in life, whether going into all this trouble to set up your own server on Windows 10 when there are prepackaged AMP (Apache - MySQL - PHP) servers such as MAMP, WAMPServer and XAMPP is a matter of perspective.

In my humble opinion it is worth the trouble anyway since you get to install the versions of PHP which are most relevant to you. If you're working with upgrading or reimplementing old sites you might want to install even older versions of PHP such as 5.3, a version that became end of life in August 2014. At the time of this writing, May 2020, the only two viable ways for using such an antiquated version of PHP are either using a self-built Windows server or using an older Linux distribution.

Then there's the point I made in the beginning of this post. If your deployment environment is IIS it makes sense to also develop on IIS. This way you can catch most – but not all! – issues during local development instead of when deploying to a development or staging server. This can save you a lot of time and frustration. That's pretty my use case. I develop software which produces security-enhancing web.config files for Joomla! sites so I really need to test them on an actual IIS server instead of guessing whether it will work on not.

Finally, as I've alluded in other similar articles, the process of building a server is a very useful learning journey. You will find it much easier dealing with live server issues when you know how the server works under the hood instead of treating it as a scary black box. Knowledge of how things work is incredibly empowering.