Installing Magento CE 2.0 on Windows Server 2012 R2 IIS 8.5

Magento (https://magento.com/) is one of the top 3 Open Source ecommerce platforms. Designed to run on Linux & Apache it could be a challenge to get it running on Windows IIS right from the first time since officially Magento is not supported on IIS.

Where to start from:
1. Deploy IIS 8.5 using Server Manager and add the SMTP server feature(or use an external SMTP server). It will be required later to send order emails from Magento
Install URL-rewrite IIS add on from http://www.iis.net/downloads/microsoft/url-rewrite
2. Install a MySQL server (or have a remote one)
3. Install php (5.5.x, 5.6.x or 7.0.2) http://devdocs.magento.com/guides/v2.0/install-gde/system-requirements.html and enable the required PHP modules as per the official magento documentation.
4. Download Magento https://www.magentocommerce.com/download , extract it in C:\inetpub\wwwroot (or a custom one ex. C:\Websites\Magento – something I recommend in general )
5. Configure php settings required by magento (in this example php 5.6.x was used)
The magento requirement says you have to configure these as a minimum http://devdocs.magento.com/guides/v2.0/install-gde/prereq/php-ubuntu.html#instgde-prereq-timezone
They are safe to be configured in you global php.ini file”

memory_limit = 768M
always_populate_raw_post_data = -1
asp_tags = Off
date.timezone = Europe/Sofia http://php.net/manual/en/timezones.php

Magento however customize some php settings using the .htaccess file. Since we’ll be using IIS these have to be converted in IIS aware setup (web.config). A good article how to configure php settings per IIS website can be found here http://www.iis.net/learn/application-frameworks/install-and-configure-php-on-iis/enable-per-site-php-configuration-on-iis-60-and-iis-7-and-above
Then you can find the cutomized PHP settings in the .htaccess file in the root magento directory
Edit your global php.ini file and add
user_ini.filename = “.user.ini”

Then create an .user.ini file in the root magento directory and copy the .htaccess php settings content for your PHP version. In our case the content for php 5.6 is:

memory_limit = 768M
max_execution_time = 18000
session.auto_start = Off
zlib.output_compression = On
suhosin.session.cryptua = Off

Create another .user.ini file inside pub directory and take the settings from pub\.htaccess:

memory_limit = 256M
max_execution_time = 18000
session.auto_start = Off
zlib.output_compression = Off
suhosin.session.cryptua = Off

6.Converting Magento Apache based .htaccess into IIS web.config
6.1 URL Rewrite Rules
You can use the URL-rewrite IIS settings to import .htaccess URL rewrite rules (URL Rewrite–>Import Rules–>Browse the file and select Import–>remove the non-convertable settings and click apply.
Alternatively place this in web.config into the magento root directory

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name=”Imported Rule 1″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_METHOD}” pattern=”^TRAC[EK]” ignoreCase=”false” />
</conditions>
<action type=”Redirect” url=”{R:0}” redirectType=”Temporary” />
</rule>
<rule name=”Imported Rule 2″ stopProcessing=”true”>
<match url=”^(.*)$” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{URL}” pattern=”^/mobiledirectoryhere/.*$” ignoreCase=”false” negate=”true” />
<add input=”{HTTP_USER_AGENT}” pattern=”&quot;android|blackberry|ipad|iphone|ipod|iemobile|opera” ignoreCase=”false” />
</conditions>
<action type=”Redirect” url=”/mobiledirectoryhere/” redirectType=”Found” />
</rule>
<rule name=”Imported Rule 3″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_FILENAME}” matchType=”IsFile” ignoreCase=”false” negate=”true” />
<add input=”{REQUEST_FILENAME}” matchType=”IsDirectory” ignoreCase=”false” negate=”true” />
</conditions>
<action type=”Rewrite” url=”index.php” />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Place this inside pub\media\web.config

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name=”Imported Rule 4″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_FILENAME}” matchType=”IsFile” ignoreCase=”false” negate=”true” />
</conditions>
<action type=”Rewrite” url=”../get.php” />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Place this inside pub\static\web.config

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name=”Imported Rule 5″ stopProcessing=”true”>
<match url=”^version.+?/(.+)$” ignoreCase=”false” />
<action type=”Rewrite” url=”{R:1}” />
</rule>
<rule name=”Imported Rule 6″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_FILENAME}” matchType=”IsFile” ignoreCase=”false” negate=”true” />
</conditions>
<action type=”Rewrite” url=”../static.php?resource={R:0}” appendQueryString=”false” />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Place this inside pub\web.config

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name=”Imported Rule 7″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_METHOD}” pattern=”^TRAC[EK]” ignoreCase=”false” />
</conditions>
<action type=”Redirect” url=”{R:0}” redirectType=”Temporary” />
</rule>
<rule name=”Imported Rule 8″ stopProcessing=”true”>
<match url=”.*” ignoreCase=”false” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_FILENAME}” matchType=”IsFile” ignoreCase=”false” negate=”true” />
<add input=”{REQUEST_FILENAME}” matchType=”IsDirectory” ignoreCase=”false” negate=”true” />
</conditions>
<action type=”Rewrite” url=”index.php” />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Make sure the rule name are unique in the deployment ! Otherwise you might get HTTP Error 500.52 – URL Rewrite Module Error


6.2 Convert the Mime Types

[Update Needed]

6.3 Convert all Remaining Settings

[Update Needed]

7. NTFS permissions
IIS APPPOOL\ApplicationPoolIdentity” (ex. “IIS APPPOOL\MagentoLive”) need to have :
READ&EXECUTE access on the magento directory (C:\Websites\Magento)
MODIFY access on magento \app\etc directory (for security purposes this should be removed after the installation is complete
MODIFY access on magento \var directory
MODIFY access on magento \pub\media directory
MODIFY access on magento \pub\static directory
MODIFY access on the PHP Temp directory  (otherwise it throws an errors like “We’re sorry, an error has occurred while generating this email” on the Storefront or “Could not determine temp directory, please specify a cache_dir manually” in the Admin panel
In case PHP Temp directory is not specified in php.ini then PHP takes the folder in the TEMP Environment variable (C:\Windows\Temp by default).

The Default ACL on C:\Windows\Temp on Windows 2012 R2 is (icacls output)
C:\Windows\Temp CREATOR OWNER:(OI)(CI)(IO)(F)
NT AUTHORITY\SYSTEM:(OI)(CI)(F)
BUILTIN\Administrators:(OI)(CI)(F)
BUILTIN\Users:(CI)(S,WD,AD,X)
BUILTIN\IIS_IUSRS:(OI)(CI)(S,RD)
In case magento is the single website on your IIS server you can directly grant the IIS_IUSERS MODIFY permissions
Important Security Notice: for all magento directories where you grant write access make sure you remove scripts execution in IIS (go to each folder–>Handled-Mappings–>Edit Feature Permissions–> uncheck Script)
8. Setup PHP OpCache (don’t miss this step! – it’s a great performance boost)

Edit you global php.ini and insert:

inside [php] section
zend_extension=php_opcache.dll (the DLL file must be present in your php extensions directory)
inside [opcache] section
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.use_cwd=1
opcache.revalidate_freq=60
opcache.fast_shutdown=1

9. Setup SSL on you IIS website – a lot of content exist on Internet how to do this. It doesn’t matter if you do this before or after the Magento Installation. It’s important to avoid using self-signed certificate.

10. Magento Installation
There are two ways to do this:
A) using the http://yoursite.com/setup web based wizard

or

B) using command line

cd magentorootdirectory 

php magento setup:install –admin-firstname John –admin-lastname Doe –admin-email [email protected] –admin-user admin –admin-password yourpassword –base-url http://yoursite.com –db-host=localhost –db-name DB –db-user DBuser –db-password yourDBpassword –use-rewrites 1 –use-secure-admin 1 –session-save db

List of support command line parameters can be found here http://devdocs.magento.com/guides/v2.0/install-gde/install/cli/install-cli-install.html

When you install from the website the Magento installation may hang on (freeze on) Installing schema.. or Upgrading schema.. usually around 4% or 5%.
This happens due to IIS FastCGI “Activity timeout” settings (by default 30 seconds)

Adjust the settings to a higher enough value to allow the setup to finish. ex. 3600 (1h)

Then retry the installation by :
deleting magentorootdirectory\app\etc\config.php and magentorootdirectory\app\etc\env.php
dropping the MySQL DB tables
re-running the setup from http://yoursite.com/setup
Until you retry the installation Magento website will return HTTP error 500 Internal Server Error

The installation might fail to deploy the static content making Storefront and the Admin page looking badly formatted(missing pictures, CSS styles, js, etc). To resolve this run:

“php bin\magento setup:static-content:deploy en_US”

http://devdocs.magento.com/guides/v2.0/install-gde/trouble/tshoot_no-styles.html
https://github.com/magento/magento2/issues/1312
When using non en-US Locale (Admin–>Stores–>Configuration–>General–>Locale Options) even after deploying static content, the StoreFront will still be badly formatted (Admin will be now OK). Two ways to solve this:
A) Set en-US locale in the Admin panel
B) Deploy static content for your locale

“php bin\magento setup:static-content:deploy bg_BG”

http://devdocs.magento.com/guides/v2.0/config-guide/cli/config-cli-subcommands-static-view.html

11. Magento Store Configuration

[More updates will follow]