Windows Server 2016 部署 IIS+PHP+MySQL 完整实战指南

发布时间:2026/10/5 17:43:49
Windows Server 2016 部署 IIS+PHP+MySQL 完整实战指南 前阵子帮客户在一台 Windows Server 2016 上部署一个老 PHP 项目本来想着半小时搞定结果从 IIS 到 PHP 再到 MySQL 一路踩坑断断续续折腾了大半天。回头看这套环境本身并不复杂但网上教程版本参差不齐要么只讲了 IISPHP 的对接要么 MySQL 部分一笔带过很少有一篇能把版本选型、FastCGI 配置和错误排查一起写透的文章。今天就把这次完整实测通过的过程整理出来从版本下载、IIS 角色安装、处理程序映射、php.ini 关键参数到 MySQL 安装以及 PHP 连库验证全部按照能直接复现的方式写系统运维的新手可以参考有经验的朋友也可以直接拿来当排查手册。1. 搭建前的版本选型与下载思路1.1 为什么在 Windows Server 2016 上选 IIS 10.0 FastCGIWindows Server 2016 自带的 IIS 10.0和系统集成度非常高不需要额外安装装完角色就是可用的 Web 服务器。很多人习惯在 Windows 上用 Apache 或 Nginx 跑 PHP确实能跑但既然系统自带了 IIS直接用 IIS 在某些场景下更省事图形化管理界面成熟和 Windows 防火墙、AD 域控、文件权限模型的配合都是原生的配合“应用程序池”的隔离机制一个站点挂了不会把整台服务器拖垮做网站隔离和资源限制也比 Apache 方便。PHP 在 IIS 下主要有两种跑法老一代的 ISAPI 方式和现在的 FastCGI 方式。ISAPI 早就被微软和 PHP 官方放弃了性能和稳定性都不行现在 PHP 官方在 Windows 平台推荐的就是 FastCGI。FastCGI 模式下php-cgi.exe 作为独立的 FastCGI 进程常驻IIS 通过 FastCgiModule 把请求转发给 PHP 处理PHP 进程可以复用不会每个请求都重新启动一个进程性能和资源占用都能接受。MySQL 作为数据库层则是因为绝大多数 PHP 项目的默认搭配就是 MySQL/MariaDB兼容性最好MySQL 社区版完全免费对于 Windows Server 上的中小型业务系统来说这套组合的成本几乎为零而且生态成熟遇到问题社区资料也多。1.2 PHP 版本怎么选NTS、VC 运行库、x64 这三件事必须搞清楚去 windows.php.net 下载 PHP 时最容易踩的第一个坑就是版本选错。IIS FastCGI 方式必须选NTSNone-Thread Safe版本也就是下载页面上标注 Non Thread Safe 的 zip 包。千万别下成 TSThread Safe版本那是给 Apache 模块方式用的用 FastCGI 跑 TS 版本虽然有时候也能跑但属于非官方推荐组合稳定性和性能都有隐患。另一个坑是 VC 运行库。PHP 不同版本依赖不同的 Microsoft Visual C Redistributable 运行库少了它 php-cgi.exe 会直接启动失败报 502.3 错误。版本对应关系大概是这样的PHP 版本需要的 VC 运行库线程安全版本选择PHP 5.6VC11VS2012通常选 TSPHP 7.0 - 7.3VC15VS2015-2019NTSPHP 7.4VC15VS2015-2019NTSPHP 8.0 - 8.3VC 2015-2022NTSPHP 8.4VC 2015-2022NTS具体到 Windows Server 2016 IIS 10.0我实测最省心的组合是PHP 7.4 NTS x64因为很多生产环境里的老 PHP 项目在 PHP 8.x 下多多少少会有些兼容性问题而 PHP 7.4 处于一个功能够用、兼容性又好的平衡点。如果项目代码是基于 PHP 8 开发的直接用 PHP 8.2 或 8.3 NTS 也没问题操作流程完全一样。x86 和 x64 的选择上如果服务器内存足够、没有依赖 32 位扩展直接用 x64 版本。但要注意如果 PHP 项目用到了某些老旧的第三方扩展比如某些加密组件只出了 x86 版就老老实实回到 x86整个链路 PHP、MySQL 客户端库都需要统一位数。MySQL 方面新部署建议直接用 MySQL 8.0 社区版性能和稳定性都比 5.7 好如果是老项目迁移且代码里用了非常老的连接方式可以考虑 MySQL 5.7但要注意 5.7 的生命周期已经接近尾声。下载地址就直接去 MySQL 官网选 MySQL Community Server 的 ZIP Archive 包Windows 下我用 ZIP 包而不是 MSI 安装包因为 ZIP 方式更容易控制安装目录和数据目录。2. 安装 IIS 10.0 角色与 PHP 基础配置顺带把运行库装齐2.1 通过服务器管理器安装 IIS 和 CGI 功能在 Windows Server 2016 上打开“服务器管理器”点击“添加角色和功能”一路下一步到“服务器角色”页面勾选Web 服务器(IIS)。这里注意系统会提示添加所需功能直接确认即可。继续点到“角色服务”页面在“应用程序开发”分类下一定要勾选CGI这个子项因为 FastCGI 模块是由 CGI 角色服务提供的漏掉这一步后面 IIS 里根本没有 FastCgiModule 可以用这是新手最早期遇到的一个大坑。如果已经装过 IIS 但没有勾 CGI可以在“服务器管理器 - 管理 - 添加角色和功能”里重新跑一遍向导在角色服务里补勾 CGI过程是增量完成的不会影响现有站点。装完后可以在浏览器里访问http://localhost看到 IIS 默认欢迎页说明 Web 服务本体已经正常。另外建议顺便把“管理工具”里的“IIS 管理器”固定到任务栏后面所有 Web 层面的配置都在里面操作。IIS 管理器虽然能从服务器管理器打开但频繁切换真的很烦。2.2 解压 PHP、安装 VC 运行库、配置 php.ini把下载好的 PHP zip 包解压到一个不含空格和中文的路径比如C:\PHP。网上有人喜欢放到C:\inetpub\wwwroot\php下面我不是很推荐PHP 是程序运行环境和网站内容分离会更清晰也方便以后升级。安装 PHP 之前先把对应的 VC 运行库装上。最保险的办法是直接安装Visual C Redistributable for Visual Studio 2015-2022最新版可以从微软官网下载 vc_redist.x64.exe这个运行库是向后兼容的包含了旧版本 VC 的 CRT 组件一把梭装完 PHP 7.4 到 PHP 8.x 都不会再有运行库缺失的问题。装完最好重启一下确保环境变量生效。接下来配置 php.ini。PHP 目录里默认有两个模板文件php.ini-development和php.ini-production开发环境直接用 development 模板生产环境建议用 production 模板再调。复制一份php.ini-development改成php.ini然后用记事本打开。关键配置项我逐个说明extension_dir C:\PHP\ext这个必须填绝对路径。很多人在这里只填extPHP 在命令行下可能没问题但通过 FastCGI 运行时的工作目录可能不是 PHP 目录扩展路径就找不到了随之而来的就是各种扩展不生效的问题。extensionmysqli extensionpdo_mysql extensionmbstring extensioncurl extensionopenssl extensiongd把extension前面的分号去掉就是启用对应扩展我一般至少启用上面这几个。其中 mysqli 和 pdo_mysql 是 PHP 连 MySQL 的两种方式mbstring 很多老项目的字符处理依赖它curl 和 openssl 是访问 HTTPS 接口或者做第三方登录时的常用扩展gd 则是验证码和图片处理的基础。date.timezone Asia/Shanghai不设置时区PHP 的 date 函数会比北京时间少 8 小时初看没啥但日志和业务时间全错位排查问题会很痛苦。cgi.fix_pathinfo 1这个参数在 IIS FastCGI 模式下是必须开启的否则访问类似http://域名/index.php/home这种带 PATH_INFO 的路由时请求会 404很多现代化框架和路由组件都依赖这个设置。fastcgi.impersonate 1开启后 PHP 会模拟 IIS 请求方的 Windows 身份配合 IIS 的身份验证机制文件权限管理更安全这是 PHP 官方在 Windows/IIS 下的推荐配置。顺手把几个资源限制也调一下避免后面被默认值坑到max_execution_time 300 memory_limit 256M post_max_size 64M upload_max_filesize 64M改完保存用管理员权限打开命令提示符切到C:\PHP目录执行php -v和php -m。前者能看到 PHP 版本信息和加载的 ini 文件路径后者能看到当前启用了哪些扩展如果 mysqli 已经出现在列表里说明 PHP 这层已经没问题了。提示命令行下php -m结果里没有 mysqli 时先别急着怀疑 PHP 文件有问题检查一下extension_dir是否指向了正确的 ext 目录这是最常见的原因。3. IIS 与 PHP 的 FastCGI 对接处理程序映射与配置文件两手抓3.1 在 IIS 管理器中添加处理程序映射PHP 安装好之后接下来的核心操作是把 IIS 和 php-cgi.exe 关联起来。打开 IIS 管理器在左侧连接树里选中服务器节点或者具体某个站点双击中间的“处理程序映射”图标点击右侧操作栏的“添加模块映射”弹窗里按下面填请求路径*.php模块FastCgiModule可执行文件C:\PHP\php-cgi.exe名称PHP_via_FastCGI点击确定后IIS 会弹出一个询问“是否创建 FastCGI 应用程序”的对话框这里必须点“是”因为只有确认后 IIS 才会在 applicationHost.config 里自动写入 fastCgi 节点配置否则模块映射指向一个不存在的 FastCGI 应用访问 PHP 页面还是 502。这个界面操作看起来很直观但实际生产环境中我更建议直接在配置文件里操作原因很简单GUI 一次只能配一条映射和默认参数很多高级参数比如请求超时、进程回收阈值在这个弹窗里没有暴露出来必须到配置文件里改。3.2 手工修改 applicationHost.config 的高级配置IIS 的主配置文件在C:\Windows\System32\inetsrv\config\applicationHost.config修改前先备份。用管理员权限的记事本打开搜索fastCgi节点正常情况下已经有一条刚才通过 GUI 添加的 application 记录结构类似下面这样fastCgi application fullPathC:\PHP\php-cgi.exe arguments monitorChangesToC:\PHP\php.ini activityTimeout90 requestTimeout300 instanceMaxRequests10000 environmentVariables environmentVariable namePHP_FCGI_MAX_REQUESTS value10000 / environmentVariable namePHPRC valueC:\PHP / /environmentVariables /application /fastCgi几个关键属性我说明一下requestTimeout默认 90 秒。如果 PHP 脚本执行时间较长超过这个时间 IIS 会直接断开请求返回 502实测很多报表导出、批量数据处理场景都会触发建议调到 300 秒甚至更长。instanceMaxRequests控制 php-cgi.exe 进程在处理多少请求后自动回收。PHP 长驻内存跑久了不可避免会有内存碎片和资源泄漏设置一个阈值让进程定期重生比让进程无限跑下去更健康一般设 10000 比较合适。monitorChangesToC:\PHP\php.ini让 FastCGI 进程监控 php.ini 文件变化以后改了 php.ini 之后不需要手工重启 IIS 或 php-cgi小改动自动生效。PHPRC环境变量明确告诉 PHP 从哪里读取配置文件防止因为工作目录不同导致找不到 php.ini。配置文件里还对应有一条 handler 记录搜索PHP_via_FastCGI能找到handlers add namePHP_via_FastCGI path*.php verbGET,HEAD,POST modulesFastCgiModule scriptProcessorC:\PHP\php-cgi.exe resourceTypeFile / /handlers这里注意 path 是*.phpverb 要包含常见请求方法scriptProcessor 路径和 fastCgi 里的 fullPath 必须完全一致大小写和反斜杠都不能出错。改完配置文件后在管理员命令行执行iisreset重启 IIS或者用“IIS 管理器 - 右侧操作 - 重新启动”都行。3.3 默认文档、目录权限与测试页处理程序映射配置好后还要处理默认文档。IIS 的默认文档列表里默认有 index.html、Default.htm 这类但没有 index.php。在 IIS 管理器里选中站点双击“默认文档”点击右侧“添加”输入index.php并上移到第一位。这样访问http://服务器IP/就能自动找到 index.php 作为首页。接着在站点对应的物理路径下新建一个test.php内容就一行?php phpinfo();然后浏览器访问http://服务器IP/test.php看到一整版 PHP 配置信息说明 IIS 和 PHP 的 FastCGI 通信已经通了。如果这时候看到的是源代码内容说明处理程序映射没生效优先检查站点级别有没有继承服务器级别的 handler如果直接 404检查请求路径后缀是不是真的以 .php 结尾。目录权限方面IIS 的默认站点物理路径在C:\inetpub\wwwroot。在资源管理器里右键该目录安全标签页确认IIS_IUSRS至少拥有“读取和执行”权限。如果项目里有上传目录、缓存目录或者日志目录需要单独给IIS_IUSRS加“修改”权限否则 PHP 程序写入文件时会报权限不足。4. MySQL 安装与 PHP 连接 MySQL 的完整验证4.1 MySQL 8.0 的 ZIP 方式安装与初始化MySQL 我用的是 ZIP 方式安装解压到C:\MySQL然后在同目录新建一个my.ini配置文件。下面是一份实测可用的最小配置[mysqld] basedirC:/MySQL datadirC:/MySQL/data port3306 character-set-serverutf8mb4 default-storage-engineINNODB max_connections500 [client] default-character-setutf8mb4这里注意路径分隔符用正斜杠/反斜杠在某些情况下会被当成转义符处理。字符集建议直接设成 utf8mb4现在绝大多数业务和接口都是中文环境utf8mb4 能完整支持 emoji 和四字节中文生僻字老项目默认的 latin1 或 utf8 升级到 utf8mb4 几乎是无痛迁移。配置写好之后用管理员权限打开命令提示符切换到C:\MySQL\bin目录执行初始化命令mysqld --initialize-insecure--initialize-insecure的意思是把 data 目录初始化出来并且 root 账号初始密码为空适合本机首先进入再设置密码的场景。如果用--initialize不带 insecureMySQL 会生成一个随机临时密码写到日志里那个找起来比较麻烦。初始化成功后再注册 Windows 服务mysqld --install MySQL net start MySQL服务启动后执行mysql -uroot应该能直接进入 MySQL 命令行然后马上设置 root 密码ALTER USER rootlocalhost IDENTIFIED BY 这里换成你的强密码; FLUSH PRIVILEGES;4.2 创建业务数据库和专用账号很多教程到这里就直接用 root 连接 PHP 项目了这在生产环境里风险很大。root 拥有所有数据库的所有权限一旦 PHP 代码被注入漏洞攻击者拿到数据库权限后就是整个实例沦陷。实际部署时强烈建议为每一个业务创建独立的数据库和独立的账号权限只给到这一个库。CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4; CREATE USER webapplocalhost IDENTIFIED BY WebApp2024; GRANT ALL PRIVILEGES ON mydb.* TO webapplocalhost; FLUSH PRIVILEGES;用 MySQL 8.0 时这里有个坑8.0 默认的认证插件是caching_sha2_password而老版本的 PHP mysqli 扩展和很多老的数据库连接工具比如 PHP 7.0 以下的 mysqli或者某些老版本的 PDO 驱动不认识这个插件连接时会直接报The server requested authentication method unknown to the client。解决办法是在创建用户时显式指定老认证插件CREATE USER webapplocalhost IDENTIFIED WITH mysql_native_password BY WebApp2024;如果用户已经创建好了也可以用下面这句把认证方式改过来ALTER USER webapplocalhost IDENTIFIED WITH mysql_native_password BY WebApp2024;用 PHP 7.4 及以上的版本其实已经支持 caching_sha2_password 了但如果以后要迁移到 PHP 5.x/7.0 的老技术栈提前用 mysql_native_password 更省心。注意MySQL 8.0 里虽然还能用 mysql_native_password但这个插件在 MySQL 9.0 里会被移除到时候再考虑升级方案也不迟。4.3 PHP 连接 MySQL 的正确姿势与验证脚本PHP 连接 MySQL 有两个主流途径mysqli 扩展和 PDO_MySQL。老项目很多用 mysqli新项目更流行 PDO因为 PDO 可以跨数据库类型预处理语句支持也更好用。本文实测验证时用 mysqli 做演示因为更直观、排查问题也更简单。在网站根目录新建一个mysql_test.php?php $host 127.0.0.1; $user webapp; $pass WebApp2024; $dbname mydb; $conn new mysqli($host, $user, $pass, $dbname); if ($conn-connect_errno) { die(连接失败: . $conn-connect_error); } echo 连接成功MySQL 版本: . $conn-server_info . br; echo 当前数据库: . $conn-query(SELECT DATABASE())-fetch_row()[0] . br; $conn-close();浏览器访问http://服务器IP/mysql_test.php如果页面正常显示 MySQL 版本号和当前数据库名说明 IIS、PHP、MySQL 三层链路已经全部打通。如果在这里报Class mysqli not found回 php.ini 检查extensionmysqli是否去掉分号、extension_dir 是否绝对路径如果报Access denied检查账号密码和授权语句。注意测试完成后务必删除test.php和mysql_test.php这两个文件会暴露 PHP 配置和数据库连接信息是生产环境里禁用级别的文件。5. 常见问题与排错实战502、500、404 逐个击破5.1 访问 PHP 页面报 502、500、404 分别是什么问题把这段时间踩过的坑和网上社区里高频出现的问题整理成三类首先是状态码层面的区分。502.3 Bad Gateway这是 FastCGI 模式下最经典的错误。现象是浏览器返回“502.3 - Bad Gateway”或者“FastCGI 进程意外退出”。出现这个错误时打开 Windows 事件查看器查看应用程序日志基本能看到 php-cgi.exe 崩溃或者无法加载的异常记录。最常见原因有三个一是 VC 运行库没装或者装错位数php-cgi.exe 启动时找不到 DLL二是 php.ini 里 extension_dir 指向错误加载扩展时失败三是 php-cgi.exe 路径写错IIS 根本没找到这个可执行文件。排错时先到 C:\PHP 目录下手动执行php -c C:\PHP\php.ini -v如果命令行能正常输出版本说明 PHP 本身是好的问题在 IIS 这边的配置。500 Internal Server Error通常是 PHP 语法错误、php.ini 配置有误或者扩展加载过程中报错导致的。IIS 默认会把详细错误信息隐藏掉可以在站点的“错误页”里点右侧“编辑功能设置”把“详细错误”打开再把 web.config 里的 customErrors 临时关掉就能看到真正的错误信息。一般这样排查几下就能定位到具体脚本问题。404访问 .php 文件报 404 时基本是处理程序映射没生效。在 IIS 管理器里选中具体的站点点“处理程序映射”确认PHP_via_FastCGI在这个站点下是“已启用”状态。如果服务器节点有、站点节点没有需要在站点级别重新添加因为 IIS 的配置默认不会继承到所有子站。5.2 PHP 装不上 mysqli/pdo_mysql 扩展的原因这个问题的出现频率绝对排得上前列。首先用php -m看当前加载的扩展列表确认有没有 mysqli 和 pdo_mysql。没有的话按这个顺序排查第一php.ini里extensionmysqli前面是不是还有分号去掉分号后保存并重启 IIS或者触发 FastCGI 进程回收。第二extension_dir是不是C:\PHP\ext这个绝对路径很多人在这里只写ext加上绝对路径后问题消失。第三确认C:\PHP\ext目录下真的有php_mysqli.dll这个文件不同版本的 PHP 扩展文件名可能略有不同但核心名称都是 php_mysqli.dll。第四如果上述都没问题用php -i查看Loaded Configuration File确认命令行用的 php.ini 和 FastCGI 用的 php.ini 是同一个很多时候会出现系统里有多个 PHP 目录、多个 php.ini 文件改了一个另一个还在用旧配置的情况。最近踩过的一个冷门坑是PHP 7.4 的 ext 目录下已经没有php_mysql.dll了因为 PHP 7.0 就把老式mysql_*函数彻底移除了如果老项目代码里还在用mysql_connect()要么把代码迁移成 mysqli/PDO要么就得回到 PHP 5.6没有第三种办法。5.3 权限、超时、MySQL 认证插件等冷门但致命的坑这三个坑平时不会遇到遇到一次就能让人折腾一晚上。权限问题。IIS 默认匿名用户是IUSRFastCGI 进程默认也以这个身份运行如果网站物理目录没有给 IUSR 或 IIS_IUSRS 权限PHP 页面会直接空白或者报无权访问。给目录加权限时注意网站根目录只需要“读取和执行”真正需要写入的只有上传目录、缓存目录、日志目录几个特定文件夹建议精确到目录级别授权而不是整个站点给写权限。超时问题。前面在 applicationHost.config 里调过requestTimeout如果项目有导出大量数据、批量生成图片这类长时间任务还会遇到浏览器请求超时。除了把 requestTimeout 调大还要同时调大 php.ini 里的max_execution_time这两个是不同层面的超时IIS 一层、PHP 一层任何一个先到都会断。MySQL 8.0 认证插件问题。前面创建用户时特意指定了mysql_native_password如果已经用了默认的caching_sha2_passwordPHP 7.0 以下版本连接时会直接报错PHP 7.4 及以上一般能正常连接。开发时如果发现网页能开但登录数据库时直接 500优先怀疑这个原因。5.4 常见问题速查表现象最常见原因处置方法访问 .php 显示源码而非执行处理程序映射未添加或未生效IIS 管理器添加模块映射确认站点级 handler 状态502.3 Bad GatewayVC 运行库缺失或 php.ini 配置错误安装 vc_redist 运行库检查 extension_dir命令行 php -v 验证FastCGI 进程意外退出php-cgi.exe 崩溃缺少 DLL检查事件查看器日志检查扩展路径与位数是否匹配500 Internal Server ErrorPHP 语法错误或扩展不兼容打开详细错误页逐条排查脚本PHP 页面时间差 8 小时date.timezone 未设置php.ini 设date.timezone Asia/Shanghai并重启 IISClass mysqli not foundmysqli 扩展未启用或路径错误php.ini 启用 extensionmysqli检查 extension_dir 绝对路径MySQL 8.0 连接报认证方式错误caching_sha2_password 不被老客户端支持创建用户时指定 mysql_native_password上传大文件超时或失败多个超时参数和文件大小限制同时调整 requestTimeout、max_execution_time、upload_max_filesize网页能开但后台登录 500数据库连接失败检查 PHP 连接脚本、MySQL 账号权限、认证插件这套环境我现在已经完整部署过好几次总结下来最值得注意的还是版本对应关系PHP 选 NTS、VC 运行库别漏装、php.ini 的 extension_dir 必须写成绝对路径、处理程序映射和 fastCgi 配置要保持一致。踩过一次坑之后我现在每部署完一台机器都会先跑php -v、php -m确认基础状态再进 IIS 加映射最后用 phpinfo 和数据库连接脚本做端到端验证顺序走对了半小时真能搞定。如果你也在 Windows Server 上搭这套环境碰上了我上面没写到的坑欢迎回来跟我交流。