以每年 99 元的低价用了两年阿里云服务器后,其性能瓶颈愈发明显:仅运行 WordPress 尚可,稍加负载便会卡死,漫长的重启过程更是令人煎熬。面对即将到来的高额续费,我选择将 WordPress 迁移至本地 Windows 主机,以发挥个人电脑的计算优势。云服务器则降级为纯粹的流量转发节点,通过 Nginx 和 FRP 对外提供服务。这种架构最大的好处是灵活性:未来更换云服务商,只需在新服务器上配置 Nginx 和 frps 即可,彻底告别了以往复杂且高风险的网站与数据库迁移工作。
优势:
- localhost访问速度
- 运用本地windows的高性能CPU计算资源、大容量存储、GPU需求
- 数据掌握在自己手里,不用受云服务商的监控
- 非常适合作为开发或测试环境,可以直接在本地开发,并通过公网进行预览和测试,无需频繁部署到云服务器。
缺点:
- 同时受限于云服务器的带宽和本地windows的上行流量,访问速度打折。除了带宽限制,数据包在 用户 -> 云 -> 本地 -> 云 -> 用户 之间往返,必然引入额外的网络延迟,对于交互性要求高的操作体验会有影响。
- 增加了故障点。云服务器、本地 Windows 主机、本地网络、frp 服务本身,任何一个环节出问题都会导致网站不可访问。
- 对本地网络的稳定性和公网 IP(如果是动态 IP 可能需要 DDNS)有依赖。
关键点
- Nginx的作用:在云服务器上处理HTTPS(TLS/SSL卸载)并将解密后的HTTP请求转发给frps。
- frps与frpc:frps(服务端)运行在云服务器上,frpc(客户端)运行在内网(或本地)机器上。frpc主动连接frps,建立一个稳定的隧道。
- 数据流:外部请求 -> Nginx -> frps -> frpc -> Apache -> WordPress,响应则反向流回。
流程
- 用户在浏览器输入域名。
- 浏览器向DNS服务器查询域名对应的IP地址。
- DNS服务器返回云服务器的公网IP地址。
- 浏览器向云服务器IP的80/443端口发起HTTP/HTTPS请求。
- 云服务器上的Nginx监听80/443端口,接收请求。如果是HTTPS(443),Nginx处理TLS握手并解密。
- Nginx根据配置,将HTTP请求反向代理到同台云服务器上监听xxxx端口的frps服务。
- frps通过预先由frpc建立的隧道,将请求转发给内网的frpc客户端。(frpc是主动连接到frps并保持连接的,请求是通过这个连接传输,而不是每次请求都重新握手)。
- frpc客户端接收到请求,根据配置将其转发给本机(localhost)上监听yyyy端口的Apache服务。
- Apache接收请求,调用PHP处理(通常通过mod_php或PHP-FPM),执行WordPress程序。
- WordPress处理请求并生成响应数据。
- 响应数据逐级返回:WordPress -> Apache -> frpc -> frps (通过隧道) -> Nginx -> 浏览器。
- Nginx将响应数据(如果是HTTPS)加密后发送给浏览器。
- 浏览器接收并渲染数据。
sequenceDiagram participant User as 用户/浏览器 participant DNS as DNS服务器 participant Nginx as 云服务器Nginx(公网IP:80/443) participant frps as 云服务器frps(监听xxxx) participant frpc as 内网frpc客户端 participant Apache as 内网Apache(监听yyyy) participant WP as 内网WordPress Note right of frps: frpc预先连接frps建立隧道 User->>DNS: 查询域名 A 的 IP 地址 DNS-->>User: 返回 云服务器公网IP User->>Nginx: 1. 发起HTTPS请求 (访问域名A) Nginx->>Nginx: 2. TLS解密 Nginx->>frps: 3. 反向代理HTTP请求 (转发到localhost:xxxx) frps->>frpc: 4. 通过隧道转发请求 frpc->>Apache: 5. 转发请求到localhost:yyyy Apache->>WP: 6. 调用WordPress处理 WP-->>Apache: 7. WordPress返回响应 Apache-->>frpc: 8. Apache返回响应 frpc-->>frps: 9. 通过隧道返回响应 frps-->>Nginx: 10. frps返回响应 Nginx->>Nginx: 11. TLS加密 Nginx-->>User: 12. 返回HTTPS响应 User->>User: 渲染页面
核心代码
Nginx反向代理设置
#PROXY-START/
# 这个最好通过宝塔面板在前端操作,以免自己改代码和宝塔产生冲突
#PROXY-START/
location ^~ /
{
proxy_pass http://127.0.0.1:xxxx; # Frps服务器的监听端口
proxy_set_header Host $host; # 传递客户端(浏览器)请求的名字
proxy_set_header X-Forwarded-Host $host; # 传递客户端(浏览器)请求的标准主机名
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递客户端ip和代理的ip
# --- 关键修改:添加/确保正确的协议和端口头 ---
proxy_set_header X-Forwarded-Proto $scheme; # 传递协议
proxy_set_header X-Forwarded-Port $server_port; # 传递监听端口
# --- 关键修改结束 ---
# proxy_set_header REMOTE-HOST $remote_addr; # 这个头通常不是必需的
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; # 修改为 "upgrade" 以支持 WebSocket
proxy_http_version 1.1;
proxy_redirect off; # wordpress让关闭重定向
# --- 移除/注释掉宝塔自动添加的缓存和静态文件判断逻辑 ---
# add_header X-Cache $upstream_cache_status;
# set $static_fileqalaflpo 0;
# if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
# {
# set $static_fileqalaflpo 1;
# expires 1m;
# }
# if ( $static_fileqalaflpo = 0 )
# {
# add_header Cache-Control no-cache;
# }
# --- 结束移除/注释 ---
}
#PROXY-END/
proxy.conf以下是wordpress官方文档的推荐配置(适用于反向代理):
location / {
proxy_pass http://your_host_name:your_port;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme; //这个告诉frps服务端协议是https还是http
proxy_redirect off; //这个很重要,关闭nginx本身对于域名的重定向,以免跟wordpress的重定向规则冲突
}
JavaScript但是要注意:
proxy_set_header X-Forwarded-Host $host; # 传递客户端(浏览器)请求的标准主机名
上面这一行要注意尽量是 $host,而非$server_name,因为在前面的nginx.conf中很可能配置了多个server_name,这时候如果用proxy_set_header X-Forwarded-Host传递的默认是第一个,如果你刚好跟浏览器输入的域名不一样(比如是ip地址),就会导致一些静态资源到时候以https://ip地址/xxx的形式请求。
frp内网穿透
这里我遇到一个大坑啊,按理说,上面通过proxy_set_header X-Forwarded-Proto $scheme已经将协议(http or https)传递给了frps,frps应该原样传递给frpc,我的SSL证书是部署在nginx所在的云服务器的,nginx解析https内容后,以http的方式给frps,进而我本地应该让wordpress通过传递来的 $scheme的值调整内部url处理方式全部https(即便接收到的数据实际上是来自http的)但是实测下来,frpc接收到的X-Forwarded-Proto却是http。排查了好久好久,在github的讨论区找到一个issue,终于发现是新版会自动把https转成http,于是回退到0.51.3才解决问题。
bindPort = zzzz # 需要跟frpc设置保持一致
vhostHTTPPort = xxxx # 跟Nginx设置保持一致
auth.token = "your_secret_token" # 必须加,网络安全大于天
transport.tls.force = true # 强制TLS加密
frps.iniserverAddr = "xx.xxx.xxx.x" # 公网ip地址
serverPort = zzzz # 需要跟frps设置保持一致
auth.token = "your_secret_token" # 添加认证token,需要与服务器端配置相同
[[proxies]]
name = "web"
type = "http" # 证书是在云服务器而非本地,frps和frpc之间通过http通信
localPort = 80 # 确认Apache监听一致的端口
customDomains = ["your_domain.com"]
[transport]
proxyURL = "socks5://127.0.0.1:1080" # 可选,如果Localhost开启了代理,可以通过这个控制是否走代理
frpc.iniwordpress配置
wordpress的矛盾点在于,实际接收到的都是已经经过云服务器nginx解析后的http数据,却自以为是https(因为访客从浏览器输入https://domain.com访问),引起mixed content错误。我的做法是,就保持后台siteurl和home的值为”http://localhost”,这样的好处是,本机直接访问localhost一点问题都没有,它不走frpc的流量,充分发挥localhost的便捷优势。而从https域名访问时,在wp-config.php加几行额外判断:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS'] = 'on';
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
define('WP_HOME', 'https://' . $_SERVER['HTTP_HOST']);
define('WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST']);
define('FORCE_SSL_ADMIN', true);
}
/* That's all, stop editing! Happy publishing. */
wp-config.php以上代码的意思是,如果frpc接收到的HTTP_X_FORWARDED_PROTO协议是https(即从浏览器输入域名访问的情况),就强制让wordpress把内部链接头全部替换成https,同时根据frpc接收到的HTTP_HOST(即域名)修改home和siteurl的值为https://域名,从而让所有浏览器请求的资源都以https://域名/xxxxxx.xx开头,不会出现mixed content错误。(友情提示,如果不解决https和http绕来绕去的关系,不仅是出现mixed content,还可能因为wordpress内部的url检查导致某些页面,如首页或后台首页,陷入301/302重定向循环),我开始找了一堆插件希望能解决这个问题,后来发现还是上面的代码最直观和一劳永逸。
按惯例,致敬伟大的AI老师!
PS. 后来某次wordpress版本更新以后,以上流程出了一点点问题:“输入fanyiming.life/wp-admin会自动跳转localhost的登录页面(导致无法远程访问),但是其他页面的跳转都是正常的,不会被重定向到localhost。”
Gemini老师给出的解决方案如下,已采纳:
您好!您遇到的这个问题非常典型,是反向代理(特别是您这种 Nginx -> FRP -> 本地服务器 的多层代理)部署 WordPress 时常见的一个痛点。
您提供的文档非常详尽,对整个架构的理解也很到位。问题的原因基本可以锁定在 WordPress 本身处理后台登录和重定向的机制上。
问题根源分析
简单来说,问题出在 WordPress 的
wp-login.php
和后台区域/wp-admin/
有自己独立的、更严格的重定向和 URL 判断逻辑。
- 数据库中的 “权威” 地址:您在 WordPress 后台设置的 “站点地址 (URL)” 和 “WordPress 地址 (URL)” 是
http://localhost
。这对 WordPress 来说,是它身份的“最终权威”。- 前台页面的“欺骗”成功:对于网站前台页面(如文章、页面),您在
wp-config.php
中添加的代码成功地“欺骗”了 WordPress。当请求通过fanyiming.life
访问时,HTTP_X_FORWARDED_PROTO
和HTTP_X_FORWARDED_HOST
这两个 Header 让 WordPress 临时认为自己的地址是https://fanyiming.life
,并正确地生成了页面内的链接,所以前台访问正常。- 后台登录的“叛逆”:当您访问
fanyiming.life/wp-admin
时,WordPress 会触发登录验证流程。这个流程中的某些核心函数(例如wp_login_url()
或其他内部重定向函数)可能没有完全遵循wp-config.php
中define
的WP_SITEURL
,而是直接或间接地读取了数据库中那个“权威”的http://localhost
地址,然后生成了一个指向http://localhost/wp-login.php?...
的重定向指令(HTTP 302 Found)。您的浏览器收到这个指令后,就乖乖地跳转到了localhost
的登录页。总结: 您的
wp-config.php
配置对前台生效了,但后台的登录和管理区域因为其自身的安全和重定向机制,“识破”了这个“骗局”,回归了数据库里的本源地址http://localhost
。
解决方案
有两种解决方案,强烈推荐方案一,因为它是一劳永逸且最规范的做法。
方案一:【推荐】统一内外网访问地址,修改本地 hosts 文件
这是最稳定、最根本的解决方案。核心思想是让 WordPress 从始至终只认一个地址
https://fanyiming.life
,然后通过修改您本地电脑的hosts
文件来实现快速的本地访问。步骤 1:修改 WordPress 数据库中的地址
- 登录您的 WordPress 后台(现在可能需要先用方案二临时修复,或者直接在本地通过
http://localhost/wp-admin
登录)。- 进入 设置 -> 常规。
- 将 WordPress 地址 (URL) 和 站点地址 (URL) 全部修改为您的公网域名:
https://fanyiming.life
。- 保存更改。
步骤 2:修改本地 Windows 的 hosts 文件
这个文件的作用是在您的电脑上建立一个本地的 DNS 记录,让域名直接指向本地 IP。
- 用管理员权限打开记事本(Notepad)。
- 在记事本中,点击 文件 -> 打开,然后导航到
C:\Windows\System32\drivers\etc\
。- 在右下角文件类型选择“所有文件(*.*)”,然后打开
hosts
文件。- 在文件的末尾添加新的一行:TEXT
127.0.0.1 fanyiming.life
- 保存并关闭文件。
步骤 3:调整
wp-config.php
现在 WordPress 的“权威”地址已经是正确的公网地址了,
wp-config.php
里的define
就不再是必须的了。您可以将之前添加的define('WP_HOME', ...)
和define('WP_SITEURL', ...)
这两行删除或注释掉。但为了确保反向代理下的 HTTPS 能被正确识别,保留其他部分仍然是好习惯。简化后的
wp-config.php
判断逻辑可以这样:PHPif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } /* That's all, stop editing! Happy publishing. */
FORCE_SSL_ADMIN
也可以保留,因为它现在会正确地将 http 请求重定向到https://fanyiming.life/wp-admin
。这样做的好处:
彻底解决问题:所有由 URL 混乱导致的问题(包括后台重定向、AJAX 请求失败、插件兼容性问题等)都会消失
配置统一:WordPress 的配置变得非常干净,不再有两套地址的冲突。
内外兼得:
当您在本地电脑的浏览器访问
fanyiming.life
时,hosts
文件会让请求直接发送到127.0.0.1
,不经过云服务器和 FRP,实现您想要的本地极速访问和开发。当外部用户访问
fanyiming.life
时,他们通过公网 DNS 解析到您的云服务器,流程和原来一样,可以正常访问。一个小提示 (A Small Tip):
当您在本地通过
https://fanyiming.life
访问时,由于您的 SSL 证书部署在云服务器的 Nginx 上,而本地 Apache 服务器上没有这个证书,您的浏览器可能会提示“不安全”或“证书错误”。
- 对于开发测试:直接点击“高级” -> “继续前往”即可,这不影响功能。
- 如果想消除这个警告:您可以在本地也配置一个 SSL 证书(例如使用
mkcert
工具生成一个本地信任的自签名证书),但这会增加一些配置复杂度,通常没有必要。