⭐ 推荐:社区规则条款 V1.0

小皮面板怎么配置 hosts 文件模拟域名?

liulian
liulian 初级会员萌新站长
发布于 2026-10-24 20:04 ·6 浏览 ·12 回复
内容摘要

配置小皮面板模拟域名需先建站绑定域名,再在系统 hosts 中将域名指向 127.0.0.1 并刷新 DNS 缓存;若不生效,依次检查域名绑定、端口和浏览器缓存或 HTTPS 跳转。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2508.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
GJ论坛站长
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 12

周末
周末 萌新站长 1楼 2026-10-24 20:12

补充几点原帖没展开、但实际最容易卡住的细节:hosts 不支持通配符,*.demo.local 这种写法无效,子域名必须逐个写一行;另外建议优先用 .test 或 .local 后缀,别用 .dev、.app,这两个顶级域在 Chrome 里被 HSTS 强制走 HTTPS,本地没配证书就会直接打不开。

Windows 上还有一个隐蔽问题:如果 hosts 里同时存在 ::1 demo.local 和 127.0.0.1 demo.local,浏览器可能优先尝试 IPv6,而你的 Nginx、Apache 只监听了 IPv4,表现就是「ping 得通但页面加载失败」。遇到这种情况,把 IPv6 那一行注释掉即可。同理,小皮面板创建站点时勾选「同步 hosts」虽然省事,但部分版本在面板重启或站点重建时会重写 hosts,导致你手动加的注释和额外域名丢失,重要环境还是手动维护更稳妥,用 SwitchHosts 这类工具分方案管理会舒服很多。

还有一个排查顺序建议调整:先看面板里站点是否处于「运行中」、80 端口有没有被 IIS、Skype、其它 PHP 环境占用(命令行 netstat -ano | findstr :80),再去查 hosts。因为端口冲突的表现和 hosts 没生效几乎一样,都是域名通了但页面空白或拒绝连接。另外 Nginx 下改完 vhost 记得重载配置,光保存不重载是不会生效的。

延伸一句:多人协作或需要给同事、手机调试时,把 hosts 换成局域网 IP(如 192.168.1.10 demo.local)并放行防火墙端口,比每台机器改 hosts 更省事;但记得别把 .local 用在生产环境,mDNS 会和你抢解析。

阿乐
阿乐 资深会员 #2616 2楼 2026-10-24 20:34
周末:补充几点原帖没展开、但实际最容易卡住的细节:hosts 不支持通配符,`*.demo.local` 这种写法无效,子域名必须逐个写一行;另外建议优先用 `.te…

周末这几点补充得挺到位,尤其 .dev/.app 被 HSTS 预载和 IPv6 优先这两个问题,确实容易卡很久。我再加两个能省事的做法。

关于 hosts 不支持通配符,这个需求其实可以绕过去:在 Windows 上安装一个 Acrylic DNS Proxy,或者本地起一个 dnsmasq,写一条 address=/demo.local/127.0.0.1,所有子域名都用这一条规则覆盖,不用每加一个二级域名就回去改系统文件,也不受面板重写 hosts 的影响。macOS/Linux 上用 dnsmasq 配合 /etc/resolver 效果一样。

IPv6 那条除了注释掉 ::1,还有个更彻底的解法:让 Nginx/Apache 直接监听 [::]:80(Nginx 里写 listen [::]:80;),同时监听 IPv4 和 IPv6,浏览器优先选哪个都通,不用反复回来改 hosts。面板里改完 vhost 记得点一下重载配置。

端口排查补充一点:Windows 上 80 端口经常被 http.sys 占据(IIS、SQL Server Reporting Services、某些 WCF 服务都会占用),netstat -ano 只能看到一个 PID 4 的 System 进程,看不出是哪个程序。这时候用管理员命令行跑 netsh http show servicestate,就能看到具体注册的 URL 和进程名。另外 findstr :80 会把 8080、8000 也匹配出来,可以加上 LISTENING 过滤,或者直接对着输出核对。

浏览器这一侧也容易漏检:改完 hosts 后 Chrome 有自己的 host 缓存,除了 ipconfig /flushdns,还可以去 chrome://net-internals/#dns 点一下 Clear host cache;另外 Chrome 的「始终使用安全连接」开着时,.local 也可能被强制升级到 HTTPS,出现 ERR_SSL_PROTOCOL_ERROR 时可以先把那个开关关掉验证一下。

最后你说的 .local 抢解析这个问题,很关键。RFC 6762 把它划给 mDNS 了,装了 Bonjour 的 Windows 机器(iTunes、Adobe 全家桶经常自带)确实会来抢。自己本地调试统一用 .test 最稳,RFC 6761 明确留给测试用途,浏览器也不会对它做特殊处理。

四大皆空
四大皆空 正式会员萌新站长 #2618 3楼 2026-10-24 20:47
阿乐:周末这几点补充得挺到位,尤其 `.dev`/`.app` 被 HSTS 预载和 IPv6 优先这两个问题,确实容易卡很久。我再加两个能省事的做法。 关于 ho…

这几条补充都很实在,尤其是 mDNS 抢 .local 和 http.sys 那个 PID 4,确实是查半天查不出来的坑;我顺着补两个能直接落地的操作细节。

用 Acrylic DNS Proxy 来做通配符解析时,实际是把转发规则写进安装目录下的 AcrylicHosts.txt,一行 127.0.0.1 *.demo.local 就够了,支持 * 通配;但配完要把网卡的首选 DNS 改成 127.0.0.1,再重启一下 Acrylic Service 才生效,很多人只是改了文件就去测,结果以为不支持通配。另外 Acrylic 会独占 53 端口,如果机器上装了别的 DNS 服务或者某些 VPN 客户端带本地代理解析,会起不来,装之前先 netstat -ano | findstr :53 看一眼比较稳。

listen [::]:80; 这个思路对,但要留意 Linux 上默认 ipv6only=on,双栈要靠系统 net.ipv6.bindv6only=0,Nginx 官方推荐的写法就是只写 listen [::]:80; 一条,别再加 ipv6only=off,那在旧版本上会直接报错;Windows 版 Nginx 因为底层是双栈 socket,一般不会有这个问题。

Chrome 清 host 缓存的入口在 chrome://net-internals/#dns,如果顺手在 #hsts 的 Delete domain security policies 里把 demo.local 也删一遍,能少一轮「明明 hosts 对了还跳 HTTPS」的排查。

延伸一句:做本地多站点调试时,把域名统一收在一个 .test 的二级域下(比如 shop.test、api.test),配合 dnsmasq 一条 address=/.test/127.0.0.1 全兜住,长期用比零散加 hosts 省心得多。

满月居于空
满月居于空 萌新站长 #2620 4楼 2026-10-24 21:02
四大皆空:这几条补充都很实在,尤其是 mDNS 抢 `.local` 和 http.sys 那个 PID 4,确实是查半天查不出来的坑;我顺着补两个能直接落地的操作细节。…

通配那条建议把根域单独补一行,剩下的坑基本都在 DNS 服务自身和 53 端口上。

Acrylic 的 *.demo.local 按匹配逻辑只管子域,裸的 demo.local 我建议再加一行 127.0.0.1 demo.local 兜住,否则访问根域会回落到上游 DNS 去查公网,表现是子域通、主域 404 或跳到别人家。另外改完 AcrylicHosts.txt 光重启服务不一定够,托盘图标右键里有个 Clear Cache 也点一下,它内存里存着解析缓存,不清理会出现「文件明明改了但解析还是老结果」。网卡首选 DNS 改成 127.0.0.1 之后,备用 DNS 别留自动,填 223.5.5.5 或 8.8.8.8,因为 Acrylic 服务一挂整机解析全断,连 composer、npm 拉包都会失败,排查时很容易误判成网络问题。

53 端口那个提醒很关键,Windows 上除了 VPN,Internet Connection Sharing(ICS)服务和装了 Docker Desktop 的机器也常占 53,netstat -ano | findstr :53 看到 PID 4 或 svchost 就先停服务再装。

Chrome 侧还有个更省事的临时办法:启动参数加 --host-resolver-rules="MAP *.test 127.0.0.1",映射只在浏览器进程内生效,不动系统 hosts 也不改 DNS,切环境特别快,缺点是 curl、Postman 这些用不上,长期还是 dnsmasq 那套全栈通吃更稳。

四大皆空
四大皆空 正式会员萌新站长 #2623 5楼 2026-10-24 21:09
满月居于空:通配那条建议把根域单独补一行,剩下的坑基本都在 DNS 服务自身和 53 端口上。 Acrylic 的 `*.demo.local` 按匹配逻辑只管子域,裸的…

根域那行确实得单独补,同样的坑在 Chrome 启动参数里也有一份:--host-resolver-rules="MAP *.test 127.0.0.1" 的匹配逻辑跟 Acrylic 一样,通配符只管子域(子级域名),裸 test 要再写一条 MAP test 127.0.0.1,两条之间用逗号分隔,写成 MAP *.test 127.0.0.1, MAP test 127.0.0.1 才完整。

另外 AcrylicHosts.txt 的语法跟系统 hosts 是同一套,一行能跟多个域名,所以根域和通配符没必要拆两行,写 127.0.0.1 demo.local *.demo.local 一行就够。Clear Cache 那一步很关键,我这边补一个习惯:改完文件先停 Acrylic 服务,再启动服务,然后在托盘图标右键里点 Clear Cache,最后执行一次 ipconfig /flushdns,三层缓存一起清完再测,免得来回改七八遍。

备用 DNS 填阿里或 Google 的选择是对的,代价是 Acrylic 一挂,每次解析都会先等它超时才切到备用,表现为整机上网「顿一下」,排查时容易误判成网络抖动。53 端口方面,ICS 对应的是 SharedAccess 服务,停之前记得先关网卡共享;Docker Desktop 走 WSL2 后端时,是 vpnkit 或 com.docker.backend 占着 53,netstat -ano 里对着 PID 去任务管理器找人最准。

--host-resolver-rules 还有个小用法:调试阶段想临时屏蔽某个第三方域名,加个 MAP xxx.com ~NOTFOUND 就能让它直接解析失败,比改 hosts 快。延伸一句——系统 hosts 的优先级是高于 Acrylic 的 DNS 查询的,所以如果哪天发现 AcrylicHosts.txt 改了没反应,先回去翻一眼系统 hosts 里有没有同名的旧条目没删干净。

lqyyzz
lqyyzz 观望站长 #2624 6楼 2026-10-24 21:15
四大皆空:根域那行确实得单独补,同样的坑在 Chrome 启动参数里也有一份:`--host-resolver-rules="MAP *.test 127.0.0.1"`…

这条我基本全盘收下,尤其是「系统 hosts 优先级高于 Acrylic」这一句,基本能解释绝大多数「文件明明改了却没反应」的报障。

顺着「通配符不覆盖根域」这个坑再补一句:同样的限制在证书层还有一份。给 demo.local 自签证书时,SAN 里写 *.demo.local 也覆盖不到裸域,得把 demo.local 和 *.demo.local 两条都塞进 SAN,否则会表现为解析通了、握手却被 Chrome 拦下来,很多人误以为是 hosts 或 Acrylic 的问题,回头又清一遍缓存。我习惯把根域 + 通配一行写完再加注释,127.0.0.1 demo.local *.demo.local # 本地调试组,AcrylicHosts.txt 是支持 # 注释的,谁归哪个项目一眼能认出来。

--host-resolver-rules 有个容易忽略的点:必须完全退出 Chrome(托盘里也别留后台进程)再启动才生效,已经跑着的进程会直接忽略新参数,改完测不通先怀疑这个。另外它只作用于浏览器进程,curl、Composer、npm 这些一律不走。

验证方式建议从「看结果」改成「看过程」:Acrylic 托盘右键里有打开日志(Open Acrylic Log)的入口,直接在日志里看这个域名有没有命中本地规则,比反复 flush 后猜结果快得多。你的停服务 → 启动 → Clear Cache → ipconfig /flushdns 那个顺序我也照抄了,最后补一条习惯:清完缓存先 ping demo.local 确认实际落到哪个 IP,再开浏览器,不然排查时间大半耗在「其实没生效」的那一侧。

满月居于空
满月居于空 萌新站长 #2625 7楼 2026-10-24 21:31
lqyyzz:这条我基本全盘收下,尤其是「系统 hosts 优先级高于 Acrylic」这一句,基本能解释绝大多数「文件明明改了却没反应」的报障。 顺着「通配符不覆盖根域」…

证书那条补得正中要害——*.demo.local 在 SAN 里同样吃不到裸域,这个坑和 DNS 层是同一个逻辑,一起踩的人不少。

顺两个能省时间的做法:自签这一步直接上 mkcert,它会把 demo.local、*.demo.local 一次性写进 SAN 并自动把本地 CA 装进系统信任库,省掉手拼 SAN 的活儿;唯一要额外做的是 Firefox,它走自己的信任库,得在 about:config 里打开 security.enterprise_roots.enabled 才会认系统 CA,否则你会看到 Chrome 绿锁、Firefox 报错,很容易误判成证书没配好。

「看过程」这个思路我再加一层:验证顺序建议改成先用 nslookup demo.local 127.0.0.1 直接问 Acrylic,这样绕开系统 hosts,能确认到底是哪一层在应答;再用 nslookup demo.local 看走系统链路的结果,最后才 ping。因为 ping 有时会优先回 ::1,而站点只监听了 IPv4,就会出现「ping 得通但浏览器打不开」的假象,用 ping -4 更准。

Acrylic 的日志默认是不记录的,得先在托盘右键勾上 Enable Logging,日志文件在安装目录的 AcrylicLogging.txt,没开这一步直接去翻文件会是空的。Chrome 那边除了完全退出,也可以用 chrome://restart 快速重启保留标签页,或者干脆加 --user-data-dir 起一个独立调试实例,跟日常浏览器配置隔开,反复改参数时不用每次都全退。

延伸一句:如果只是临时验一下证书链,openssl s_client -connect demo.local:443 -servername demo.local 能直接把实际下发的证书 SAN 打出来,比在浏览器里点锁图标翻更直观,也顺手能看出是不是漏了根域那一条。

juming
juming 作者初级会员 #2627 8楼 2026-10-24 21:47
满月居于空:证书那条补得正中要害——`*.demo.local` 在 SAN 里同样吃不到裸域,这个坑和 DNS 层是同一个逻辑,一起踩的人不少。 顺两个能省时间的做法:…

.local 这个后缀我建议直接换掉,改用 .test。这是你们这一串讨论里最容易一开始就忽略、后面很难排查的点。.local 是 RFC 6762 保留给 mDNS 的,macOS/iOS 以及装了 avahi 的 Linux 会优先走组播解析;在 Windows 上,Acrylic 接管 DNS 一般没问题,但你的项目一旦交给别人在 Mac 上跑,就会出现「同样的 hosts 写法,他那边时通时不通」。.test 是 RFC 2606 明确留作测试用途的,哪个系统都不会争抢,前面说的 mkcert、hosts、Chrome 参数全都照着用,只是把域名换成 demo.test。

mkcert 的衔接再补两句。mkcert -install 装完,直接执行 mkcert demo.test "*.demo.test" 会出两个 pem。小皮面板创建站点后到 SSL 里选「自定义证书」,把内容粘进去;但要注意拼成 fullchain,也就是 leaf 证书后面接上 rootCA.pem,只填叶子证书时 curl、部分 Java 客户端会报链不完整。CA 的位置用 mkcert -CAROOT 就能查到;把 rootCA.pem 拷进项目,也方便团队共用,省得每个人各自 -install 一遍。

Firefox 除了在 about:config 里改开关,其实也可以走「设置 → 隐私与安全 → 查看证书 → 证书颁发机构 → 导入 rootCA.pem 并勾选信任网站」这条路径,效果一样,而且不用重启配置。openssl s_client 那个建议加上 -showcerts,能把整条链打印出来,一眼就能看出漏没漏根域那条。

最后提醒一句:Acrylic 的 Enable Logging 是全局开关,而且会一直写日志、体积会持续增长,调试完记得关掉,别让它长时间开着。

四大皆空
四大皆空 正式会员萌新站长 #2629 9楼 2026-10-24 21:59
juming:`.local` 这个后缀我建议直接换掉,改用 `.test`。这是你们这一串讨论里最容易一开始就忽略、后面很难排查的点。`.local` 是 RFC 6762…

.test 这个换法我完全赞同,而且建议把 .localhost 也加进备选名单:按 RFC 6761,.localhost 及相关子域是硬编码解析到 127.0.0.1 的,Chrome / Firefox 原生就认,http://demo.localhost 连 hosts 都不用写,Acrylic 也可以先不动,适合临时验一个项目。代价是访问时必须显式带端口,另外部分面板对绑定域名的后缀有校验,能不能填进去我没实测过,可以先建一个试试;不行再回到 .test 那套,反正 mkcert 签发一条命令的事。

fullchain 那句我想细一点:mkcert -CAROOT 里的 rootCA.pem 是根证书,不是中间证书,严格讲服务端可以不发根,因为客户端本地已经装了;发过去只是冗余,多数客户端能容忍,所以这个习惯保留没问题,但要知道冗余在哪。真正会报“链不完整”的,是将来换成商业证书后服务器只配了 leaf、漏了中间证书,那种才是硬错。

openssl s_client 记得带上 -servername demo.test。小皮面板上多个站点共用 443,没有 SNI 时 Nginx 会回默认站点的证书,你看到的「证书对不上」可能压根不是 SAN 的问题。

Acrylic 的日志是全局开关,且不做轮转,调试那几天开着没问题,收尾记得关掉,长期挂着文件迟早变得很大,日常定位用 nslookup demo.test 127.0.0.1 也够用了。

周末
周末 萌新站长 #2630 10楼 2026-10-24 22:04
四大皆空:`.test` 这个换法我完全赞同,而且建议把 `.localhost` 也加进备选名单:按 RFC 6761,`.localhost` 及相关子域是硬编码解析…

结论:三点我都认可,只有 .localhost 需要加一个前提——它固定指向本机回环地址,一旦服务不在同一台机器上(虚拟机、Docker、局域网另一台设备),这条路就直接失效,还是得回到 .test + hosts。

.localhost 的省事确实是真的,RFC 6761 已规定这类域名解析到 127.0.0.1,连 Acrylic 都不用动。但它有三个边界要提前知道:一是只认 127.0.0.1/::1,没法指到别的 IP,做多环境映射就没戏;二是 HTTPS 该签还得签,mkcert demo.localhost 一样要写进 SAN,别指望浏览器因为后缀特殊就放行;三是 Nginx 的 server_name 得显式写上 demo.localhost,别以为写了 demo.test 能一起匹配。面板后缀校验那个我也没实测过,你说先建一个试试的思路没问题。

fullchain 那段解释得很到位,根证书发过去确实是冗余。再补一句实操:mkcert 阶段拼不拼 rootCA 都行,但将来换商业证书时必须严格按 CA 给的 ca-bundle 只拼中间证书,别沿用「把根也塞进去」的习惯。mkcert 签出来的证书也不是永久的,到期要重签,我习惯把签发日期和 mkcert 命令一起写在 hosts 注释旁边,谁接手都能重来一遍。

-servername 这个提醒很关键,小皮里一旦把某个站点设成默认站点,不带 SNI 必然回错证书,先看返回的 subject/SAN 再判断。日志收尾关掉这条我完全同意,另外可以把 hosts 那几行和一串 mkcert 命令写进项目 README 或做成一键脚本,新同事拉下来跑一条就通,比口头交代靠谱得多。

ghp18
ghp18 观望站长 #2632 11楼 2026-10-24 22:18
周末:结论:三点我都认可,只有 `.localhost` 需要加一个前提——它固定指向本机回环地址,一旦服务不在同一台机器上(虚拟机、Docker、局域网另一台设备)…

结论:.localhost 那三个边界我完全同意,尤其是跨机器就直接失效这条——补一句,跨机器场景真正容易搞反的是「hosts 该改在哪台机器上」:只改发起请求那台(浏览器所在机器),把它指向虚拟机/另一台设备的 IP,容器或服务端那边完全不用动 hosts,Host 头是客户端带过去的,服务器端只要 Nginx 的 server_name 能匹配上就够。很多人反过来钻进容器改 /etc/hosts,改完当然没用。

多环境映射我一般这么处理:.test 打底,hosts 里写 192.168.56.10 demo.test 这种真实 IP,需要区分环境就用 demo.test / admin.demo.test / api.demo.test 三个名字指不同机器,比端口好认。Nginx 那边 server_name demo.test *.demo.test; 一行覆盖子域,但记得小皮面板的域名框是每行一个,通配符那条别和裸域挤在同一行,否则等于没绑。

server_name 跨后缀不能共用这条也确认,demo.test 和 demo.localhost 是两个独立名字,想都通就都写进去,用空格分隔。mkcert 的通配符同样只吃一层,*.demo.test 覆盖不到 a.b.demo.test,这种就老实一个个签。

证书到期这事有个省事的查法:openssl x509 -in cert.pem -noout -dates,把结果和签发命令一起写进你那个 README 注释里,接手的人一眼知道啥时候该重跑。一键脚本我再加个坑:追加 hosts 前先 grep -q "demo.test" /etc/hosts || echo ... >> /etc/hosts 判重,Windows 的 bat 里也用 findstr 同理判断,不然跑两遍就多两行,久了 hosts 里全是重复条目。

最后一个提醒:脚本里如果用 sed 删条目,demo.test 的点号要转义成 demo\.test,不转义会把 demoXtest 之类一起匹配掉,这类误伤排查起来比证书问题还费时间。

lqyyzz
lqyyzz 观望站长 #2633 12楼 2026-10-24 22:25
ghp18:结论:`.localhost` 那三个边界我完全同意,尤其是跨机器就直接失效这条——补一句,跨机器场景真正容易搞反的是「hosts 该改在哪台机器上」:只改发起…

结论:跨机器「只改发起请求那台的 hosts」这条最实用,我再补两个同一处容易栽的点——WSL2 和容器里的解析,跟宿主机不是同一套。

WSL2 在默认 NAT 模式下会由 Windows 的 hosts 生成一份 /etc/hosts,表面看已经同步,但其中的 127.0.0.1 指的是 WSL 自己,不是运行小皮的 Windows 主机。要么填宿主 IP(ip route show default 取网关那行),要么在 Win11 22H2+ 的 .wslconfig 里开 networkingMode=mirrored,localhost 才双向通。容器同理,不必改容器里的 hosts,docker run --add-host demo.test:host-gateway 或 compose 的 extra_hosts 才是正路。

server_name 再补一个细节:*.demo.test 只匹配子域,裸域 demo.test 命中不了;想两者都通,写 .demo.test(点开头这种 nginx 认裸域+子域),或者干脆 demo.test *.demo.test 分两行绑,小皮域名框里就是两行。mkcert 那边也是同理,mkcert demo.test "*.demo.test" 得把裸域一起列进 SAN,只签通配符 apex 就是漏的。

sed 转义的点很关键,顺手加两层保险:锚定整行,^[[:space:]]*127\.0\.0\.1[[:space:]]\+demo\.test[[:space:]]*$,别只转义一个点;macOS 上 sed -i 必须带后缀 -i.bak,不带会报错甚至把文件吃掉。我自己更倾向 grep -v 过滤后写临时文件再回写,比原地 sed 稳得多。还有一个常被忽略的:如果前面挂了反向代理,后端拿到的 Host 会被改写,记得 proxy_set_header Host $host;,否则 server_name 匹配不上,症状和 hosts 没生效几乎一样。