
August 20, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
If you need to host PHP on IIS for a Windows Server environment, the only production-viable method today is FastCGI via the Web Platform Installer or manual binary mapping. Legacy ISAPI filters are obsolete and insecure. This guide walks through configuring PHP 8.4 on IIS 10/11 with correct handler mappings, OPcache tuning, and URL rewriting so your Laravel, WordPress, or custom application runs reliably without the performance penalties that plague default installations.
How Do You Install and Configure PHP to Host PHP on IIS?
The most common mistake when setting out to host PHP on IIS is downloading the wrong PHP build or using the deprecated Web Platform Installer feed that still points to EOL versions. In 2026, you should manually download the current stable Non-Thread Safe (NTS) x64 zip from windows.php.net. Thread-safe builds add unnecessary overhead because IIS FastCGI manages process isolation itself; NTS is faster and the recommended standard.
Download and Extract the Correct Build
- Navigate to
windows.php.net/downloadand select VS16 x64 Non Thread Safe for PHP 8.4 (or 8.3 LTS). - Extract to
C:\php. Avoid paths with spaces; they cause silent failures in handler mappings. - Rename
php.ini-developmenttophp.ini. Never use the production template unmodified—it disables error display but also sets restrictive defaults unsuitable for initial debugging. - Add
C:\phpto your system PATH so CLI commands likephp artisanorcomposerresolve correctly.
Register FastCGI in IIS
Open IIS Manager, select the server node, and open Handler Mappings. Add a new Module Mapping:
- Request path:
*.php - Module:
FastCgiModule - Executable:
C:\php\php-cgi.exe - Name:
PHP_via_FastCGI
Click "Request Restrictions", go to the "Mapping" tab, and ensure "Invoke handler only if request is mapped to:" is unchecked. Without this, POST requests and framework routing often return 404s.
What Are the Critical php.ini Settings When You Host PHP on IIS?
Default php.ini values assume Apache mod_php semantics. On IIS FastCGI, misconfigured directives cause intermittent 500 errors, slow page loads, or file upload failures. These are the settings I verify on every production deployment.
; Performance & Stability
max_execution_time = 300
memory_limit = 256M
post_max_size = 64M
upload_max_filesize = 64M
realpath_cache_size = 4096K
realpath_cache_ttl = 600
; OPcache (mandatory for production)
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
; Session handling (avoid file locking on NTFS)
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?database=0"
; Error handling
display_errors = Off
log_errors = On
error_log = C:\inetpub\logs\php-errors.log OPcache is non-negotiable. Without it, PHP recompiles every script on each request. With validate_timestamps=0, you gain 3–5x throughput. The tradeoff is that code changes require an explicit cache clear—either recycle the application pool or call opcache_reset() via a deploy hook. On my legal-tech portals running on shared EC2 infrastructure, disabling timestamp validation reduced average response time from 320ms to 85ms under load.
Session storage matters more on Windows than Linux. NTFS file locking causes session contention under concurrent requests. Redis eliminates this bottleneck entirely. If Redis isn't available, use SQL Server or PostgreSQL session drivers instead of the default file handler.
How Do You Configure URL Rewriting for Laravel and WordPress on IIS?
IIS doesn't read .htaccess files. Frameworks like Laravel and WordPress depend on clean URLs, which requires the URL Rewrite 2.1+ module. Install it via Microsoft's official download center or Chocolatey (choco install urlrewrite). After installation, create a web.config in your site root.
Laravel web.config Template
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Laravel" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="index.php/{R:1}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
<staticContent>
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
</staticContent>
</system.webServer>
</configuration> Critical detail: Set your Laravel public directory as the IIS site physical path—not the project root. Pointing IIS at C:\sites\myapp instead of C:\sites\myapp\public exposes .env, storage/, and vendor files. This is the #1 security vulnerability I audit on client sites migrated from Apache.
WordPress Permalinks
WordPress generates its own web.config when you save permalink settings, but only if the site root is writable by the IIS_IUSRS group. If auto-generation fails, manually add the standard WordPress rewrite rule block. Always verify pretty permalinks work before going live; broken internal links destroy technical SEO foundations.
How Do You Secure and Optimize PHP on IIS for Production?
Security and performance aren't afterthoughts—they're configuration decisions made during setup. Here's what separates a fragile dev box from a resilient production host.
| Configuration Area | Default / Insecure | Production Recommendation | Impact |
|---|---|---|---|
| PHP Version | 8.1 / 8.2 (EOL soon) | 8.4 NTS x64 | Security patches + JIT improvements |
| OPcache | Disabled | Enabled, validate_timestamps=0 | 3–5x throughput increase |
| Session Storage | Files (NTFS) | Redis or Database | Eliminates lock contention |
| Error Display | On (dev default) | Off + log_errors=On | Prevents info leakage |
| Upload Limits | 2MB / 8MB | 64MB+ based on app needs | Prevents user-facing failures |
| FastCGI Max Instances | Auto (often too low) | 2–4 per CPU core | Handles traffic spikes |
| TLS Version | TLS 1.0/1.1 enabled | TLS 1.2+ only | PCI/DPA compliance |
FastCGI Process Tuning
In IIS Manager → FastCGI Settings → Edit your PHP entry, adjust these values:
- Max Instances: Set to 2× CPU cores for compute-bound apps, 4× for I/O-bound. Monitor with Performance Monitor → FastCGI\Active Requests.
- Instance Max Requests: 10000. Recycles workers before memory fragmentation degrades performance.
- Activity Timeout: 300 seconds (matches
max_execution_time). Mismatches cause mysterious 500 errors mid-request. - Request Timeout: 310 seconds (slightly higher than activity timeout to allow graceful shutdown).
File Permissions That Actually Work
IIS runs under IIS_IUSRS by default. Your PHP application needs write access to specific directories only—not the entire site root. Grant modify permissions to:
storage/andbootstrap/cache/(Laravel)wp-content/uploads/andwp-content/cache/(WordPress)- Custom upload/log directories defined in your app
Never grant write access to the application root or vendor/. Use icacls from an elevated prompt for precise control:
icacls "C:\sites\myapp\storage" /grant "IIS_IUSRS:(OI)(CI)M" /T
icacls "C:\sites\myapp\bootstrap\cache" /grant "IIS_IUSRS:(OI)(CI)M" /T Monitoring and Validation
Create a health.php endpoint (protected by IP whitelist or auth) that outputs phpinfo() and OPcache status. After deployment, verify:
- OPcache shows "Cache Full: false" and high hit rate (>95%)
- Loaded extensions include opcache, pdo_mysql/pdo_pgsql, mbstring, openssl, curl
$_SERVER['SCRIPT_NAME']reflects correct path (framework routing depends on this)- No "Unable to open" warnings in PHP error log
For ongoing monitoring, integrate Windows Performance Monitor counters for FastCGI active requests and queue length with your existing observability stack. If you're managing multiple client sites, consider whether a DevOps automation approach would reduce manual configuration drift across servers.
Deploying and Maintaining PHP Applications on IIS
Once you successfully host PHP on IIS, operational discipline prevents regression. Deployments should follow the same zero-downtime principles used on Linux: atomic symlink swaps, pre-warmed OPcache, and automated health checks. While Deployer and Envoy are Linux-native, PowerShell scripts or MSDeploy can replicate the workflow on Windows.
After each deploy, recycle the application pool to invalidate OPcache cleanly:
Import-Module WebAdministration
Restart-WebAppPool -Name "MyAppPool" Never edit php.ini on a live server without testing in staging first. Configuration changes require an app pool recycle to take effect, and syntax errors will take down all sites sharing that pool. For teams managing hosted client sites, maintain separate app pools per tenant to isolate failures.
Keep PHP updated. Subscribe to the PHP Windows release RSS feed or use Chocolatey (choco upgrade php) for patch management. Security releases for Windows builds sometimes lag Linux by 24–48 hours; plan maintenance windows accordingly. Test every minor version upgrade against your application's test suite before production rollout—Windows-specific edge cases in filesystem handling and locale functions do surface between versions.
Next Steps After You Host PHP on IIS Successfully
Getting PHP running on IIS is the foundation, not the finish line. From here, focus on three priorities: benchmark your application under realistic load using tools like k6 or wrk targeting your Windows host, implement structured logging that feeds into your existing monitoring (ELK, Datadog, or even Windows Event Log forwarding), and document your exact configuration in version-controlled infrastructure-as-code templates. If you're evaluating whether IIS is the right long-term platform versus migrating to Linux, or need help optimizing an existing Windows-hosted PHP application, reach out to discuss your specific architecture.

