
干我们这行的谁没被本地多站点折腾过。新接一个项目要跑起来本机已经装了MySQL、Redis、一堆服务结果又撞上端口冲突要么就是Apache和Nginx抢80端口要么就是改个hosts文件半天不生效更别提同时维护两三个项目时来回切换环境配置那叫一个酸爽。所以当我第一次用phpstudy的Nginx一次性把几个站点的虚拟主机配好后那种感觉真的是“清爽”。这篇东西我就围绕“phpstudy nginx 创建虚拟主机”这件事把从原理到实操、从单个站点到多站点部署、再到问题和避坑的完整经验都写出来。无论你是刚入门的新手还是被Windows下环境折腾到头疼的老手相信都能从这里找到一些可以直接抄作业的思路。1. 为什么要用phpstudy配nginx的虚拟主机1.1 虚拟主机、空间和端口到底是怎么一回事很多人一听到“虚拟主机”“空间”这两个词就懵觉得是什么高深的东西。其实道理很简单一台真实的服务器或者你本地这台电脑只有一个公网IP但你不可能一个IP只跑一个网站那样成本太高了。这时候nginx就充当“房东”的角色把一台机器按“域名”或“端口”划分成很多个独立的小隔间每个隔间就是一个“虚拟主机”也就是我们常说的“空间”。在我的理解里用nginx做虚拟主机就类似于在一栋大楼里隔出很多办公室每个办公室有自己的门牌号域名和端口进去之后有独立的办公区域网站根目录互不干扰。整个世界就是这么运作的你输入blog.example.comnginx一看这个域名就知道你是要去A隔间输入shop.example.com就把你引向B隔间。这样做最大的好处是一份nginx进程能同时跑N个网站每个网站有自己独立的目录、独立的配置、独立的行为。不像是以前用IIS一个站点配不好其他站全都跟着遭殃。1.2 为什么是phpstudy而不是自己裸装nginx这个问题我被人问过很多次既然要学nginx为什么不直接去官网下载Windows版的nginx压缩包自己解压配置非要套一个phpstudy我自己两种方式都用过。裸装nginx的好处是干净、纯粹没有多余的东西但问题也很明显nginx只是个Web服务器它本身不处理PHP动态请求你得自己去配PHP-FPM去处理环境变量去处理各种路径问题。在Windows上这一步尤其烦人因为win下压根没有标准的php-fpm模式你得用php-cgi.exe去跑还要处理进程守护。当年我就是卡在这里浪费了整整一个下午。phpstudy的聪明之处在于它把nginx、Apache、PHP、MySQL这些“生态系统”里的组件都整合到了一起并且处理好了它们之间的协作关系。你在界面上点一下开关nginx起来了php-cgi进程也起来了代码只要丢进网站目录就能跑。对于本地开发、小项目演示、甚至做网关反代来说这完全够用而且省去了大量无关紧要的底层维护成本。所以我的结论是如果你是生产环境、追求极致性能和定制化那就老实裸装nginx如果你只是为了本地开发、快速搭建演示环境、或者在一个项目里让nginx充当其他服务的反向代理那phpstudy就是最优解没有之一。2. 环境准备与nginx启用2.1 phpstudy的安装与nginx一键启用这个按部就班来就行。去phpstudy官网下载对应版本的安装包我建议直接装Windows版如果你在Linux服务器上就装Linux版。安装完打开面板左侧菜单栏会看到“服务”之类的一排入口里面列了各种软件。这里要注意默认情况下phpstudy可能安装了Apache也安装了nginx但在同一个时间点80端口只能被其中一个占用。所以你要做的第一件事就是先看Apache是不是处于运行状态如果是先把它停掉然后再去启动nginx。启动nginx后面板上如果显示状态是“绿色”的那就说明成功了。这时候打开浏览器输入localhost如果看到一个默认的欢迎页面环境就是通的。注意如果在win10/win11上启动nginx时被防火墙拦截记得选择“允许访问”否则局域网内的其他设备访问不到你这里的站点排查起来又是一通折腾。2.2 选择哪个PHP版本更合理phpstudy里内置了多个PHP版本比如5.6、7.0、7.4、8.0等。选择标准不是越新越好而是看你的项目兼容哪个环境。你如果用的是老项目比如某些cms系统PHP版本太高反而不行报错报到你怀疑人生新项目用ThinkPHP这种框架PHP环境适中即可。我的习惯是默认装一个PHP 7.4一个PHP 8.1两个版本并行。这样老项目走7.4新项目走8.1切换时直接在phpstudy里绑定站点的PHP版本就能完成。3. 创建虚拟主机一篇文章搞懂核心配置3.1 第一步准备站点目录和域名解析在配置虚拟主机之前先要在本地把“域名”和“目录”准备好。首先在你的硬盘上建立一个专门存放网站的根目录例如D:\wwwroot\demo。在这个目录下放一个最简单的index.html或index.php用来后面验证配置是否生效。其次本地需要把域名解析到本机。什么意思呢你访问demo.test这个域名时操作系统需要知道它应该指向哪台服务器。在本地开发环境下这个域名永远不会被真实DNS解析因为.test这类后缀是专门用来做本地测试的。所以我们必须手动修改Windows下的hosts文件。用管理员权限打开记事本然后编辑C:\Windows\System32\drivers\etc\hosts文件在末尾加一行127.0.0.1 demo.test这样当你访问demo.test时系统就会把请求交给本机的nginx去处理。这一步很多人会忘记或者改完不生效我后面会在问题排查里专门讲hosts不生效的典型原因。3.2 两种创建站点的方式我推荐哪一种phpstudy提供了两种创建虚拟主机的方式很多人只知道第一种遇到第二种能解决的问题就傻眼。第一种面板添加站点。在phpstudy面板的“网站”选项卡里点击“创建网站”填入域名demo.test选择网站目录D:\wwwroot\demo再选好PHP版本一键创建。这种方式最省心适合新手也适合那些只是临时起个站点测一下的场合。它本质上是帮你在nginx的配置目录里生成一个server块配置只是把细节隐藏在了图形界面后面。第二种直接修改nginx配置文件。这也是我说的“推荐掌握”的方式。点击phpstudy面板上的“nginx”图标选择“配置文件”打开nginx.conf。如果你看到文件末尾有类似include vhosts/*.conf;这句话那就说明你还有独立的vhosts配置目录可用。进入这个目录新建一个demo.conf自己手写server块。这种方式更自由尤其是当你想配置一些面板里做不了的高级功能比如复杂rewrite、负载均衡列表、自定义错误页等时就能体现出优势了。我的建议是新手先用面板走通一遍然后再手动写一遍配置文件。只有把配置文件的每一行都看明白你在真机上出问题时才不慌。3.3 server块配置逐行解析直接抄作业下面这个配置是我日常常用的一个最小可用模板拿来即可用server { listen 80; server_name demo.test; root D:/wwwroot/demo; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { root D:/wwwroot/demo; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } access_log logs/demo.test.access.log; error_log logs/demo.test.error.log; }我来一行一行拆解这个文件的核心部分server { ... }一个server块就是一个虚拟主机的最小单元。nginx就是靠这个块来判断如何处理发往本机的请求。listen 80监听80端口。如果你本地80被别的程序占用了这里可以改成listen 8080配上server_name之后你访问时就需要加上端口号比如demo.test:8080。server_name demo.test这是虚拟主机配置的灵魂。nginx收到一个HTTP请求后会取出请求头中的Host字段然后用这个字段和所有server块里的server_name做匹配匹配上哪个就用哪个的配置。root D:/wwwroot/demo站点根目录也就是用户访问时能看到文件的物理路径。注意路径的斜杠方向在Windows上也要用正斜杠/用反斜杠\有时会出问题。index index.php index.html默认首页文件。访问域名根时nginx会依次尝试解析这两个文件。location /表示处理所有未被其他location规则匹配到的请求这是兜底逻辑。try_files $uri $uri/ /index.php?$query_string这一句尤其对PHP框架很重要它实现了“如果找不到真实文件则转发到index.php处理”的效果典型的前端控制器模式。location ~ \.php$用正则表达式匹配以.php结尾的请求将它们转发给fastcgi也就是PHP进程处理。fastcgi_pass 127.0.0.1:9000是phpstudy默认的PHP监听地址和端口一般不用改。$document_root$fastcgi_script_name就是告诉PHP进程请求的脚本具体在哪个路径。提示如果你把配置文件放在vhosts目录下记得重启nginx让配置生效。在phpstudy界面里点“重启”按钮或者用命令行执行nginx -s reload二选一即可。3.4 伪静态配置框架开发绕不开的一关现在大多数PHP框架ThinkPHP、Laravel都是单入口模式即所有请求都走public/index.php然后由框架内部根据路由规则去分发到具体控制器。这种模式下如果你不做伪静态配置那用户访问任何一个页面都得带上一长串index.php/admin/user/index之类的路径不仅丑还容易暴露目录结构。nginx里要做到“隐藏index.php”还是在server块内做文章。核心就是前面写的这条location / { try_files $uri $uri/ /index.php?$query_string; }它做了什么假设用户访问的是demo.test/user/indexnginx先去找D:/wwwroot/demo/user/index这个文件找不到再去找D:/wwwroot/demo/user/index/这个目录也找不到最后它退而求其次把请求转交给/index.php?user/index去处理。接下来PHP框架收到参数后解析路由并完成业务逻辑。如果你用的是Laravel它的入口文件在public目录下那你的root就要指向D:/wwwroot/demo/public否则会404。这一点我在部署多个项目时踩过太多次坑了很多人以为是伪静态没生效其实是root路径指错了。3.5 给本地站点配置HTTPS现在的浏览器对HTTP站点越来越不友好很多浏览器功能摄像头、麦克风、本地存储都只允许在HTTPS环境下运行。本地开发时想上HTTPS用phpstudy面板也能实现。实际上你只需要生成一个自签名SSL证书然后在nginx配置里加上两个listen指令和证书路径server { listen 443 ssl; server_name demo.test; ssl_certificate D:/phpstudy_pro/Extensions/ssl/demo.test.pem; ssl_certificate_key D:/phpstudy_pro/Extensions/ssl/demo.test.key; root D:/wwwroot/demo; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } }证书可以用OpenSSL命令行自己生成也可以借助phpstudy自带的证书工具。有一点需要注意自签名证书由于不是由受信任的证书颁发机构签发本地浏览器第一次访问时会提示“不安全”这时候手动选择继续访问即可浏览器会记住你的选择。4. 多站点同时跑端口、进程与资源管理4.1 配置多个server块一个nginx跑多个项目我经常跟人说nginx最值得表扬的一点就是对多站点支持特别友好。当你要加第二个虚拟主机时不需要去动主配置只要再写一个新的server块或者新建一个vhosts/xxx.conf文件就能把新的站点独立出来。举个例子你有一个后台管理系统和一个前台商城可以这样规划站点域名站点根目录用途admin.demo.testD:/wwwroot/admin/public管理后台shop.demo.testD:/wwwroot/shop/public商城前台然后在vhosts目录下分别新建admin.conf和shop.conf各自写一个server块各自指定server_name和root目录。重启nginx后两个站点就同时跑起来了彼此完全隔离。这个方案比“一个站点下用二级目录区分前后台”要干净得多。你直接在nginx这一层就把域名的归属分清楚了后面做权限控制、日志拆分、甚至流量统计时都会轻松很多。4.2 nginx常用命令与Windows下的重启方式在Linux上我们习惯用systemctl restart nginx但在Windows上由于phpstudy把nginx封装成面板服务了很多人不敢随便敲命令。其实不用怕一样可以手动操作。打开Windows命令提示符CMD切换到nginx所在目录一般在phpstudy_pro\Extensions\nginx-x.x.x就可以执行nginx -t nginx -s reload nginx -s stopnginx -t是测试配置语法是否正确改完配置文件后先跑一下这个能帮你拦住80%的手滑错误。nginx -s reload是平滑重载配置生产环境也常用这个不会中断现有服务。nginx -s stop是停止nginx。实在嫌命令行麻烦phpstudy面板上的“重启nginx”按钮效果等同于nginx -s reload。但你会看到控制台界面一闪而过万一配置有错你还没看清楚就没了。所以我自己调试配置时一律用命令行手动执行nginx -t确认无误后再去面板重启。4.3 日志怎么查访问日志和错误日志是排障的第一来源服务器出现问题第一个应该打开的就是日志而不是代码。nginx的日志分为访问日志和错误日志两种。访问日志记录每一次HTTP请求包括来源IP、访问时间、请求URL、状态码、UserAgent等。错误日志则记录nginx自身运行过程中的错误比如配置加载失败、PHP进程连接不上等。在phpstudy里nginx的默认日志路径通常在phpstudy_pro\Extensions\nginx-x.x.x\logs目录下。如果你自定义了access_log和error_log的路径就去你指定的位置找。举个例子之前有次我配好虚拟主机后访问首页一直返回502我一头雾水。打开错误日志一看里面写着connect() failed (10061: No connection could be made because the target machine actively refused it) while connecting to upstream这说明phpstudy里的PHP服务没有启动nginx转发PHP请求时找不到对应的进程。启动PHP后问题立刻消失。这种经验不翻日志的话打死也猜不出来。5. 常见问题排查与避坑实录5.1 打开域名显示404或403先别急着怀疑nginx如果你配好站点后访问域名直接404最常见的原因有三个一是hosts文件没有配置或者格式错了域名前后有空格二是站点根目录下面没有index.html或index.php这个默认首页文件三是nginx配置里的root路径指向的目录不存在。如果是403那多半是权限问题nginx进程没有权限读取你指定的Web目录。Windows下一般通过修改文件夹的“属性-安全”权限给Everyone添加“读取和执行”权限即可。虽然不严谨但本地开发好用。注意改完hosts文件后最好执行一下ipconfig /flushdns否则浏览器里访问还是走的旧的DNS缓存这个坑非常具有迷惑性。5.2 CSS、JS加载不出来样式全丢了站点能打开图片也能显示但样式表全部丢失控制台还一堆报错。这种问题一眼就能判断是静态资源路径出了问题。最常见的原因是你用了绝对路径去写资源比如/css/style.css而这个站点又被部署在了某个子目录下导致路径拼接错误。解决办法有两种一是把所有静态资源引用改成相对路径二是给静态资源单独加上location规则并指定alias路径location /static/ { alias D:/wwwroot/demo/static/; }这样nginx会把demo.test/static/xxx.css直接映射到D:/wwwroot/demo/static/xxx.css不走PHP处理速度和正确性都有保障。5.3 PHP文件变成下载或直接显示源码这是让我很多同事血压飙升的问题。页面打开没有渲染成HTML而是直接展示出?php echo ... ?这种源码或者变成一个文件下载。出现这个现象的原因基本可以锁定为nginx没有把.php结尾的请求转发给PHP-FPM处理。排查思路很简单看你的location ~ \.php$配置块是不是写错了或者fastcgi_pass指向的地址和phpstudy里PHP实际监听的端口不一致。phpstudy的PHP有时候监听的是127.0.0.1:9000有时是127.0.0.1:9001具体去看面板上“PHP进程”的监听状态即可。确定这个端口号后回填到配置文件里再重启nginx。5.4 改了配置不生效原因可能和“缓存”有关有一次我改完nginx配置后刷新浏览器怎么也看不到变化一直怀疑是自己语法错了结果nginx -t又显示一切正常。最后用无痕模式打开浏览器一看全都正常了——是浏览器缓存不是nginx的问题。如果在开发环境调试时发现旧页面一直不消失可以先用“隐身窗口”打开网址试试。如果隐身窗口能正常显示新内容说明是浏览器缓存了旧的CSS、JS或整个HTML页面按CtrlShiftR强制刷新就好。5.5 端口被占用80端口到底被谁抢了本地开发最经典的问题启动nginx后报80端口被占用或者启动成功但访问localhost时打开的是别的软件比如IIS、迅雷、Java进程。排查方式是在命令行里执行netstat -ano | findstr :80看到最后一列的PID后再到任务管理器里找到对应进程关掉它。这个处理方式简单粗暴但要注意有些系统服务比如World Wide Web Publishing Service会强制占用80端口需要打开“服务管理器”手动禁用。如果是其他占用程序按需决定是否关闭或者直接把nginx改到8080端口。6. 进阶玩法反向代理、多项目部署与请求限制6.1 nginx反向代理怎么用和虚拟主机有什么关系虚拟主机解决的是“一个服务器跑多个网站”的问题反向代理解决的是“一个入口分发到多个后端服务”的问题但两者通常同时出现。我在本地做微服务项目调式时前端要分别请求后端接口、文件服务、消息服务端口各不一样。为了不让前端代码里写满各种带端口号的请求地址我就在nginx里新建一个虚拟主机把某个域名作为统一入口然后用proxy_pass把请求分发到对应的内网服务上server { listen 80; server_name api.demo.test; location /order/ { proxy_pass http://127.0.0.1:8081; } location /user/ { proxy_pass http://127.0.0.1:8082; } }这样前端只需要记一个域名api.demo.test后端拆成多少个服务都是内部的事。这种玩法在你对接微服务、做跨域联调时极其好用能帮你少写很多CORS配置。6.2 多个web项目同时部署共享一个域名端口怎么做多项目部署有两种常见思路。一种是用不同域名区分配置多个server块前面已经说过了另一种是只有一个域名但有不同路径前缀这时候就要在同一个server块里用多个location来做分发server { listen 80; server_name example.test; location /projectA/ { alias D:/wwwroot/projectA/; } location /projectB/ { alias D:/wwwroot/projectB/; } }需要注意alias和root是有区别的alias是路径映射前缀替换root是目录拼接访问什么路径就往root目录的对应子目录里找。很多人把这两个搞混结果部署出来的项目不是404就是路径错乱。生产环境里我更推荐用独立子域名的方式区隔项目因为这样日志、配置、证书、安全策略都可以完全隔离。但在某些场景下比如客户只给了一个域名或者你不想频繁申请SSL证书那路径前缀方案也够用。6.3 请求体大小限制等常用参数调整本地调试时经常要模拟文件上传但如果上传的文件超过了nginx的默认限制nginx会直接返回413错误。此时需要在http块或server块里增加client_max_body_size 20m;这个参数的单位是兆字节写成多少就是多少。在Spring Boot这类后端走maxFileSize限制之外nginx这层也要兜底否则你后端写max-file-size10mbnginx却只允许2MB请求根本到不了后端就被拦了。类似这种参数还有连接超时时间、缓存路径等都是实际部署时绕不开的细节。我的建议是先把自己项目的典型请求大小摸清楚再据此配置client_max_body_size不要拍脑袋随便写个100m。调得太大一旦被人利用来灌数据服务器内存很容易被打满。另外如果不想让自己的站点在响应头里暴露X-Powered-By这类信息可以在http块里加上proxy_hide_header X-Powered-By;或者干脆在fastcgi层面处理。虽然对本地开发影响不大但在生产环境做安全加固时这种细节也算基本功。这些内容写到这里其实都是我一次次踩坑之后积累下来的经验。最早我配虚拟主机也是在phpstudy自带的Apache里弄后来切到nginx后才发现很多东西的原理是通用的——无论是Apache里的VirtualHost还是nginx里的server块核心思路都绕不开“域名匹配 目录映射 请求分发”这三板斧。只要理解了这三板斧遇到再复杂的部署需求你都能顺着这个思路去拆解。最后再分享一个小技巧每次新增一个站点我会顺手在vhosts目录下建一个同名备份文件里面记录了这个站点的目录结构、PHP版本、框架入口等信息。三个月后再回来看这个文件你会感激当时自己的这个习惯。毕竟配置会忘项目会迭代但一个清晰的记录能让未来的自己和接手的人少掉一大把头发。