How to Install and Configure PHP in IIS on Windows Server 2025

While ASP.NET is the native application framework for IIS, Windows Server 2025 can also serve PHP applications with excellent performance by using IIS’s FastCGI handler. FastCGI keeps PHP worker processes alive between requests, eliminating the per-request startup overhead of traditional CGI and making IIS a viable platform for PHP-based CMSes, frameworks such as Laravel or Symfony, and custom PHP applications. This guide walks through downloading and extracting the PHP runtime, configuring the FastCGI handler in IIS, mapping the .php file extension, tuning php.ini, and testing the installation — all from PowerShell and the command line on Windows Server 2025.

Prerequisites

  • Windows Server 2025 with IIS 10.0 installed
  • CGI role service installed: Install-WindowsFeature Web-CGI
  • Administrator-level PowerShell session
  • Internet access to download PHP binaries (or a pre-downloaded PHP zip)
  • Visual C++ Redistributable for Visual Studio 2022 (x64) installed — required by PHP 8.x

Step 1: Install the CGI Feature and Required Redistributable

FastCGI in IIS depends on the CGI role service. Ensure it is installed before proceeding:

# Install CGI support (enables FastCGI handler registration)
Install-WindowsFeature -Name Web-CGI

# Verify
Get-WindowsFeature -Name Web-CGI | Select-Object Name, InstallState

Next, install the Visual C++ 2022 Redistributable (x64), which PHP 8.x requires at runtime. Download it from Microsoft’s official URL and install silently:

$vcRedistUrl  = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
$vcRedistPath = "C:installvc_redist.x64.exe"
New-Item -ItemType Directory -Path "C:install" -Force | Out-Null

Invoke-WebRequest -Uri $vcRedistUrl -OutFile $vcRedistPath -UseBasicParsing
Start-Process -FilePath $vcRedistPath -ArgumentList "/install", "/quiet", "/norestart" -Wait
Write-Host "VC++ Redistributable installed."

Step 2: Download and Extract PHP for Windows

Always use the Non-Thread Safe (NTS) x64 build of PHP when pairing with IIS FastCGI. The NTS build omits thread safety overhead because FastCGI uses separate processes rather than threads.

# Download PHP 8.3 NTS x64 (check https://windows.php.net/download/ for the latest version)
$phpVersion  = "8.3.8"
$phpZipUrl   = "https://windows.php.net/downloads/releases/php-${phpVersion}-nts-Win32-vs16-x64.zip"
$phpZipPath  = "C:installphp.zip"
$phpInstPath = "C:php"

Invoke-WebRequest -Uri $phpZipUrl -OutFile $phpZipPath -UseBasicParsing

# Extract to C:php
Expand-Archive -Path $phpZipPath -DestinationPath $phpInstPath -Force

# Verify the PHP binary
& "C:phpphp.exe" -v

You should see output similar to: PHP 8.3.8 (cli) (built: ...)

Add PHP to the system PATH so it is accessible from any console session:

[System.Environment]::SetEnvironmentVariable(
    "Path",
    $env:Path + ";C:php",
    [System.EnvironmentVariableTarget]::Machine
)

Step 3: Configure php.ini

PHP ships with two sample configuration files. Copy the production template and customize it:

Copy-Item "C:phpphp.ini-production" "C:phpphp.ini"

Open C:phpphp.ini in a text editor (e.g., notepad C:phpphp.ini) and adjust the following key directives. You can also apply them with PowerShell string replacement for automation:

# Helper function: set or replace a php.ini directive
function Set-PhpIniValue {
    param([string]$Key, [string]$Value)
    $iniPath = "C:phpphp.ini"
    $content = Get-Content $iniPath
    $pattern = "^s*;?s*${Key}s*="
    $newLine  = "${Key} = ${Value}"
    if ($content -match $pattern) {
        $content = $content -replace $pattern, $newLine
    } else {
        $content += "`n$newLine"
    }
    Set-Content -Path $iniPath -Value $content
}

# Set essential php.ini values
Set-PhpIniValue "error_reporting"       "E_ALL & ~E_DEPRECATED & ~E_STRICT"
Set-PhpIniValue "display_errors"        "Off"
Set-PhpIniValue "log_errors"            "On"
Set-PhpIniValue "error_log"             "C:inetpublogsphp_errors.log"
Set-PhpIniValue "upload_max_filesize"   "64M"
Set-PhpIniValue "post_max_size"         "64M"
Set-PhpIniValue "memory_limit"          "256M"
Set-PhpIniValue "max_execution_time"    "120"
Set-PhpIniValue "date.timezone"         "America/New_York"

# Set the extension directory (where .dll extensions live)
Set-PhpIniValue "extension_dir"         "C:phpext"

# Enable commonly required extensions
$extensions = @(
    "php_mysqli.dll",
    "php_openssl.dll",
    "php_mbstring.dll",
    "php_curl.dll",
    "php_gd.dll",
    "php_intl.dll",
    "php_pdo_mysql.dll",
    "php_fileinfo.dll"
)
foreach ($ext in $extensions) {
    Set-PhpIniValue "extension" $ext
}

Write-Host "php.ini configuration complete."

Create the log directory and grant IIS write access:

New-Item -ItemType Directory -Path "C:inetpublogs" -Force | Out-Null
icacls "C:inetpublogs" /grant "IIS_IUSRS:(OI)(CI)M"

Step 4: Register PHP as a FastCGI Handler in IIS

IIS needs to know to pass .php files to php-cgi.exe via FastCGI. Register the FastCGI application and the file extension handler using the WebAdministration module:

Import-Module WebAdministration

# Register the FastCGI application (the PHP CGI binary)
$phpCgiPath = "C:phpphp-cgi.exe"

Add-WebConfiguration -Filter "system.webServer/fastCgi" -PSPath "IIS:" -Value @{
    fullPath           = $phpCgiPath
    maxInstances       = 8
    idleTimeout        = 300
    activityTimeout    = 120
    requestTimeout     = 120
    instanceMaxRequests = 10000
    environmentVariables = @(
        @{ name = "PHP_FCGI_MAX_REQUESTS"; value = "10000" }
    )
}

# Map the .php extension to the FastCGI handler
New-WebHandler -Name "PHP_via_FastCGI" `
               -Path "*.php" `
               -Verb "*" `
               -Modules "FastCgiModule" `
               -ScriptProcessor $phpCgiPath `
               -ResourceType "File" `
               -PSPath "IIS:"

Write-Host "FastCGI handler registered."

Alternatively, you can register the handler using appcmd, which is useful in environments where PowerShell module access is restricted:

cd C:WindowsSystem32inetsrv

# Add FastCGI application
appcmd set config -section:system.webServer/fastCgi /+"[fullPath='C:phpphp-cgi.exe']"

# Add handler mapping at the server level
appcmd set config -section:system.webServer/handlers `
    /+"[name='PHP_FastCGI',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='C:phpphp-cgi.exe',resourceType='File']"

Step 5: Test PHP with phpinfo()

Create a test file in your site root and load it in a browser to confirm PHP is executing:

# Create a phpinfo test file in the default web site root
Set-Content -Path "C:inetpubwwwrootphpinfo.php" -Value ""

Navigate to http://localhost/phpinfo.php. You should see PHP’s full configuration page listing the version, loaded extensions, and all php.ini values. After confirming it works, delete the file — leaving phpinfo() publicly accessible is a security risk:

Remove-Item "C:inetpubwwwrootphpinfo.php"

Step 6: Install WinCache for Performance

WinCache is Microsoft’s opcode and user-data cache for PHP on Windows. It dramatically reduces PHP parse time by caching compiled bytecode in shared memory:

# Download WinCache for PHP 8.3 (NTS x64) from PECL
$winCacheUrl  = "https://pecl.php.net/get/WinCache-2.0.0.8-8.3-nts-vs16-x64.zip"
$winCachePath = "C:installwincache.zip"

Invoke-WebRequest -Uri $winCacheUrl -OutFile $winCachePath -UseBasicParsing
Expand-Archive -Path $winCachePath -DestinationPath "C:installwincache" -Force

# Copy the DLL to PHP's extension directory
Copy-Item "C:installwincachephp_wincache.dll" "C:phpext"

# Enable in php.ini
Add-Content "C:phpphp.ini" "`nextension=php_wincache.dll"
Add-Content "C:phpphp.ini" "wincache.fcenabled=1"
Add-Content "C:phpphp.ini" "wincache.ucenabled=1"

# Restart IIS to pick up the new configuration
iisreset /restart

Step 7: PHP Manager for IIS (Optional GUI Tool)

PHP Manager for IIS is a free GUI extension for IIS Manager that simplifies PHP registration, php.ini editing, and extension management without PowerShell. Install it via the Web Platform Installer or download the MSI from CodePlex/GitHub:

# Install PHP Manager via winget (if available in your environment)
winget install --id PHPIISManager.PHPManagerForIIS --silent

# Or use WebPI command line
WebpiCmd-x64.exe /Install /Products:PHPManager

After installation, open IIS Manager and click your server node. A new PHP Manager icon appears in the feature pane, allowing you to register PHP runtimes, view configuration recommendations, and manage extensions through a guided interface.

Conclusion

PHP is now fully operational on IIS under Windows Server 2025, running through FastCGI for maximum performance and stability. You configured a production-appropriate php.ini with sensible memory limits, error logging, and key extensions such as MySQLi, cURL, and OpenSSL. WinCache adds opcode caching to further reduce per-request overhead. From here you can deploy WordPress, Laravel, or any other PHP application by placing its files in the site root and ensuring the application pool identity has write access to folders that need it (uploads, cache, sessions). Consider pairing this PHP installation with a MariaDB or MySQL instance on the same server or a dedicated database host for a complete LAMP-equivalent stack on Windows Server 2025.