Setup Wordpress in Windows Server 2019

I have recently came across an issue while migrating a website to an on-prem server. The server had Windows server 2019 standard and need to have Wordpress + MySql + PHP intalled. Usually it is easy to setup a Wordpress server with the Internet Information Services(IIS) + Windows Platform Installer(WPI). The setup seems to be very straightforward and you can follow up this simple guide here. The guide is for 2016 but it should work for newer version as well.

I found out that the WPI does not work properly with the latest version of IIS (v10+), only until version 8 express. I even tried to install all the windows features using this simple method:

  1. Download this file Roles.csv
  2. Run PowerShell / CMD in adminstrator mode
  3. Run the command from the same folder.
Import-Csv Roles.csv | foreach{Add-WindowsFeature $_.name }
  1. Then run the IIS + WPI setup to install Wordpress.

But the setup still failed for me. Seems to be the WPI direct links are outdated and have not been updated for the newer version of Windows.

So I took another approach to this. According to Wordpress, to run the application in a server they recommend the host supports:

  • PHP version 7.4 or greater.
  • MySQL version 5.6 or greater OR MariaDB version 10.1 or greater.
  • HTTPS support That’s really it. They also recommend Apache or Nginx as the most robust and featureful server for running WordPress, but any server that supports PHP and MySQL will do.

I have decided to share my experience with this setup which worked for me at the end. Your setup might differ, but the basic idea would be the same. I might add a script at the end of the guide in the future.

Step by step guide to install Wordpress on a Windows Server 2016 and above:

The instructions use Windows PowerShell, and are also suitable for servers with and without the Desktop UI feature installed (Server Core). These instructions can be also used with Windows 10!

We are going to install the following components:

Prerequisites

We need configure some small components before go forward with the setup.

  • Run PowerShell / CMD in adminstrator mode
  • Change into any directory/folder of your choice, I used Downloads folder:
cd ~\Downloads
  • Set the Security Protocol Type for HTTPS downloads to TLS 1.2:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
IIS:
  • Install IIS and Windows features:
Install-WindowsFeature Web-Server,Web-Common-Http,Web-Static-Content,Web-Default-Doc,Web-Dir-Browsing,Web-Http-Errors,Web-App-Dev,Web-CGI,Web-Health,Web-Http-Logging,Web-Log-Libraries,Web-Request-Monitor,Web-Security,Web-Filtering,Web-Performance,Web-Stat-Compression,Web-Mgmt-Tools,Web-Mgmt-Service,WAS,WAS-Process-Model,WAS-NET-Environment,WAS-Config-APIs,Net-Framework-Core -IncludeManagementTools
  • for Win 10 you need to run this:
Enable-WindowsOptionalFeature -FeatureName IIS-WebServerRole,IIS-WebServer,IIS-CommonHttpFeatures,IIS-StaticContent,IIS-DefaultDocument,IIS-DirectoryBrowsing,IIS-HttpErrors,IIS-ApplicationDevelopment,IIS-CGI,IIS-HealthAndDiagnostics,IIS-HttpLogging,IIS-LoggingLibraries,IIS-RequestMonitor,IIS-Security,IIS-RequestFiltering,IIS-Performance,IIS-HttpCompressionStatic,IIS-WebServerManagementTools,IIS-ManagementConsole,IIS-ManagementService,WAS-WindowsActivationService,WAS-ProcessModel,WAS-NetFxEnvironment,WAS-ConfigurationAPI,NetFx3 -Online -All -Source D:\Sources\sxs
  • Enable the Remote Management Service:
Set-ItemProperty HKLM:\SOFTWARE\Microsoft\WebManagement\Server EnableRemoteManagement 1
Set-Service WMSVC -StartupType Automatic
Start-Service WMSVC
URL-rewrite:
  • Download URL Rewrite 2.1 extension for IIS, which enables Permalinks functionality in WordPress:
Invoke-WebRequest "http://download.microsoft.com/download/D/D/E/DDE57C26-C62C-4C59-A1BB-31D58B36ADA2/rewrite_amd64_en-US.msi" -OutFile "rewrite_amd64.msi"
  • and install it:
Start-Process "msiexec.exe" "/i rewrite_amd64.msi /qn" -Wait
FS security:
  • Download File System Security PowerShell Module which adds a number of cmdlets to manage file system permissions not currently present in PowerShell.
Invoke-WebRequest "http://download.microsoft.com/download/D/D/E/DDE57C26-C62C-4C59-A1BB-31D58B36ADA2/rewrite_amd64_en-US.msi" -OutFile "rewrite_amd64.msi"
  • and install it:
Start-Process "msiexec.exe" "/i rewrite_amd64.msi /qn" -Wait
  • Set the PowerShell script execution policy to allow downloaded scripts to be run as long as they have been signed by a trusted publisher:
Set-ExecutionPolicy RemoteSigned CurrentUser

PHP

  • We need install these three main components:
    • PHP
    • PHP Manager for IIS – used to register and configure PHP with IIS
    • Windows Cache Extension for PHP – installed to boost PHP performance.
  • Install latest version of PHP release from here and WinCache from here. I would use any of the latest with Win32-vs[XX]-x[XX].zip at the end for PHP. In this guide I chose php-8.0.3-Win32-vs16-x86.zip for PHP and wincache-2.0.0.2-7.0-nts-vc14-x64.exe for WinCache
$PHP_ZIP = "php-8.0.3-Win32-vs16-x86.zip.zip"
$PHP_PATH = "$env:ProgramFiles\PHP\v8.0"
$PHP_DATA = "$env:ProgramData\PHP\v8.0"

Download the PHP:

cd ~\Downloads
Invoke-WebRequest "http://windows.php.net/downloads/releases/$PHP_ZIP" -OutFile "$PHP_ZIP"

and unzip it:

Expand-Archive "$PHP_ZIP" "$PHP_PATH"

and copy over to C:\ProgramFiles directory:

Copy-Item "$PHP_PATH\php.ini-production" "$PHP_PATH\php.ini"
WinCache:

Download WinCache:

$WINCACHE = "wincache-2.0.0.2-7.0-nts-vc14-x64.exe"
Invoke-WebRequest "https://nchc.dl.sourceforge.net/project/wincache/development/$WINCACHE.exe" -OutFile "$WINCACHE.exe"

and install it:

Start-Process "$WINCACHE.exe" "/Q /C /T:""$env:USERPROFILE\Downloads\$WINCACHE""" -Wait

and copy it to the C:\ProgramFiles\ext\ directory:

Copy-Item "$WINCACHE\php_wincache.dll" "$PHP_PATH\ext\php_wincache.dll"

and finally remove it

Remove-Item "$WINCACHE" -Recurse -Force
PHP Manager:

Now download PHP manager for IIS:

Invoke-WebRequest "http://www.technologist.site/wp-content/uploads/0000/PHPManagerForIIS-1.4.0-x64.msi" -OutFile "PHPManagerForIIS-1.4.0-x64.msi"

and install it

Start-Process "msiexec.exe" "/i PHPManagerForIIS-1.4.0-x64.msi /qn" -Wait

Add PHP Manager PowerShell Snap-In:

Add-PsSnapin PHPManagerSnapin

Register PHP with IIS:

New-PHPVersion "$PHP_PATH\php-cgi.exe"
  • Configure PHP extensions and settings:
Set-PHPExtension php_wincache.dll Enabled
Set-PHPExtension php_mysql.dll Disabled
Set-PHPSetting date.timezone UTC
Set-PHPSetting upload_max_filesize 20M

Relocate the PHP “Logs” and “Upload” directory:

$PHP_LOGS = "$PHP_DATA\Logs"
New-Item $PHP_LOGS -ItemType Directory | Out-Null
Set-PHPSetting error_log "$PHP_LOGS\php_errors.log"

$PHP_UPLOAD = "$PHP_DATA\Upload"
New-Item $PHP_UPLOAD -ItemType Directory | Out-Null
Add-NTFSAccess $PHP_UPLOAD IUSR Modify
Add-NTFSAccess $PHP_UPLOAD IIS_IUSRS Modify
Set-PHPSetting upload_tmp_dir "$PHP_UPLOAD"
PHP is now done setup
Visual C++:

Download Microsoft Visual C++ 2013 Redistributable package:

Invoke-WebRequest "https://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe" -OutFile "vc_redist_2013_x64.exe"

install it:

.\vc_redist_2013_x64.exe /Q

MYSQL

Install MySQL 5.7 installation (find the latest version from this list here). In this guide we are using mysql-8.0.22-winx64.zip:

$MYSQL_ZIP = "mysql-8.0.22-winx64"
$MYSQL_URL = "https://dev.mysql.com/get/Downloads/MySQL-5.7/$MYSQL_ZIP.zip"
$MYSQL_NAME = "MySQL"
$MYSQL_PROD = "$MYSQL_NAME Server 8.0"
$MYSQL_PATH = "$env:ProgramFiles\$MYSQL_NAME"
$MYSQL_BASE = "$MYSQL_PATH\$MYSQL_PROD"
$MYSQL_PDTA = "$env:ProgramData\$MYSQL_NAME\$MYSQL_PROD"
$MYSQL_DATA = "$MYSQL_PDTA\data"
$MYSQL_INIT = "$MYSQL_PDTA\mysql-init.sql"

Download MySQL:

Invoke-WebRequest "$MYSQL_URL" -OutFile "$MYSQL_ZIP.zip"

Unzip it:

Expand-Archive "$MYSQL_ZIP.zip" "$MYSQL_PATH"

and install/copy it:

Rename-Item "$MYSQL_PATH\$MYSQL_ZIP" "$MYSQL_BASE"

Set MySQL “bin” directory to the search Path variable:

$env:Path += ";$MYSQL_BASE\bin"
setx Path $env:Path /m

Create MySQL Option File:

Set-Content "$MYSQL_BASE\my.ini" "[mysqld]`r`nbasedir=""$MYSQL_BASE""`r`ndatadir=""$MYSQL_DATA""`r`nexplicit_defaults_for_timestamp=1"

Create MySQL database directory:

New-Item $MYSQL_DATA -ItemType Directory | Out-Null

Initialise MySQL database files:

mysqld --initialize-insecure

Install and start MySQL as a Windows service:

mysqld --install
Start-Service MySQL
Get-Service MySQL

Create a MySQL initialisation script to set a password for the root user (Replace PASSW0RD in the above command with your own strong password.):

Set-Content $MYSQL_INIT "ALTER USER 'root'@'localhost' IDENTIFIED BY 'PASSW0RD';"

Add the following lines in preparation for running WordPress:

Add-Content $MYSQL_INIT "CREATE DATABASE wordpress;"
Add-Content $MYSQL_INIT "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'PASSW0RD';"
Add-Content $MYSQL_INIT "GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost';"

and execute the script:

mysql --user=root --execute="source $MYSQL_INIT"

delete the script at the end:

Remove-Item $MYSQL_INIT
MySQL is now done setup

Wordpress

Download and unzip WordPress:

$IIS_PATH = "$env:SystemDrive\inetpub"
$WORDPRESS_PATH = "$IIS_PATH\wordpress"
$WORDPRESS_URL = "https://wordpress.org/latest.zip"
$WORDPRESS_ZIP = "wordpress.zip"

Invoke-WebRequest "$WORDPRESS_URL" -OutFile "$WORDPRESS_ZIP"
Expand-Archive "$WORDPRESS_ZIP" "$IIS_PATH"

Grant the modify rights for the following accounts to the WordPress directory:

Add-NTFSAccess $WORDPRESS_PATH IIS_IUSRS Modify
Add-NTFSAccess $WORDPRESS_PATH IUSR Modify

Create a IIS website for WordPress:

$WebAppPool = New-WebAppPool "WordPress"
$WebAppPool.managedPipelineMode = "Classic"
$WebAppPool.managedRuntimeVersion = ""
$WebAppPool | Set-Item

New-Website "WordPress" -ApplicationPool "WordPress" -PhysicalPath "$WORDPRESS_PATH"
Start-Website "WordPress"

Remove the “Default Web Site” if you want.

Remove-Website "Default Web Site"
Wordpress is now done setup

Setup Wordpress

  1. Open localhost or 127.0.0.1 in and web browser
  2. Select your preferred language
  3. Click Let’s go
  4. Complete the Database Connection Details page with the database name “wordpress” and username “wordpress” with passord from the previous step
  5. Submit
  6. Enter sitename, email and username along with password (this is your wp-admin login for the site you are creating). Diabling the Search Engine Visibility is up to you. Keep a copy of the credentials you just setup
  7. Done