WordPress 架设在反向代理 reserve-proxy 后面而且使用HTTPS的时候, 常常会碰到这两个问题。 一个是进入后台登录页面的时候出现 too many redirects, 造成无法登录。 而另一个则是在前台CSS也显示不正确, 因为有 mixed content.
其实在两年前我就碰到过这样的问题, 只是当时谷歌搜索解决了一下问题, 对问题如何引起的并没有关注。 以下是两年前发的贴子。
我今天帮朋友架设一个新的wordpress 网站的时候, 又碰到了这个同样的问题, 可悲的是, 我对自己以前如何解决这个问题完全没有记忆, 甚至没有找到上面这个帖子。 又折腾了大半天。
所以今天就来好好的分析一下问题的所在, 完全理解了就不容易忘记。
首先这两个问题都只发生在有反向代理, 而且反向代理使用HTTPS, 而wordpress 本身不使用HTTPS的情况。
浏览器->反向代理(HTTPS)-> WordPress (HTTP).
我使用的反向代理是 Nginx-Proxy docker 版。
由于HTTP是不安全的协议, 而 wordpress 是有后台可以登录的, 所以我们一定要给 wordpress 启用HTTPS。 而最简单的办法莫过于用反向代理。 我们在服务器上运行两个服务, 一个是反向代理, 一个是WORDPRESS。 反向代理通常监听 80 和 443 两个端口, 而 wordpress 则监听一个内部端口, 如 8080.
我这里在后台设置的网址是HTTP的, 这里涉及到 HTTP Strict Transport Security (HSTS) 的问题, 这东西常常把问题搞得更加复杂难懂, 我呆会儿会讲到。
当我们的浏览器访问网站的时候, 其实请求是发送到反向代理上的, 这里可以使用 HTTP, 也可以使用 HTTPS. 然后, 反向代理收到请求后, 会把这个请求转发给 8080 端口, 这样, 请求就到了 WordPress 上。 WordPress再把内容回复给反向代理, 反向代理再回复给浏览器。 由于 wordpress 是运行在 内部的8080 端口上的是, 所以即使它用的是HTTP协议, 却也是安全的。
以上这种设置在跑HTTP的时候不会有问题。 但是, 跑HTTPS的时候, 问题就来了。 因为虽然我们浏览器发的HTTPS的请求, 但是反向代理发到Wordpress 的请求确是一个HTTP的请求。 这个时候, WordPress 并不知道反向代理的存在, 所以它以为有一个用户在通过HTTP请求页面, 这时候 WordPress 生成的网页里的CSS和Javascript 文件链接就全是HTTP的,而不是HTTPS的。 这个时候, 就会有 Mixed content 的问题。 因为我们请求的主页是HTTPS的, 但主页里的链接却全是 HTTP的。
以上就是为什么会有Mix Content 的问题。
理解了上面的情况, 再来理解 Too many redirects 也很容易了。 因为原因是一样的。 因为HTTP是不安全的, 所以我们在登录后台的时候就需要使用HTTPS, 这里有两种方法, 第一种, 把wordpress 设置里面的网址强制成 HTTPS开头的。 第二种, 在wordpress 的配置文件 wp-config.php 中加入以下这行
define(‘FORCE_SSL_ADMIN’, true);
这样, 再登录后面的时候, 我们就可以保证在HTTPS下运行了。 因为当你是HTTP的请求进来的时候, WordPress 会返回一个重定向的回复, 把请求引到HTTPS上。
但是, 如果你还记得上面我说的, 这个时候就有个大问题。 其实我们浏览器到服务器的请求本来就已经是HTTPS了, 这个时候, 是反向代理收到了请求, 然后反向代理转发请求到Wordpress 端口的时候用的却是HTTP, 于是Wordpress 返回重定向的网址, 要求浏览器重定向到HTTPS。 于是浏览器被重定向到了一个相同的地址, 可是反向代理又把HTTPS转成HTTP了, WordPress 又要求重定向, 于是就出现了死循环。 这就是为什么会有 too many redirects 的原因。
以上还不是最糟糕的,因为你会发现,一旦你设置的网址是HTTPS开头的, 不仅HTTPS不工作, 这时候连HTTP也不工作了。 所以你无论如何都登录不了后台, 也无法把网址改回来。因为你用HTTP访问的时候, WordPress 会把你重定向到HTTPS.
于是你只好千方百计的去数据库把网址改成HTTP, 比如说用 phpmyadmin.
可是你悲剧的发现,这并没有用, 你还是一直被重定向到HTTPS, 可是你明明已经改了数据库里的网址呀? 这就涉及到了 HSTS.
默认情况下, nginx-proxy 的HSTS是开启的,所以一但你用了HTTPS登录过网站后, 你再用HTTP登录的时候, 浏览器会自动把HTTP转成HTTPS. 这个时候唯一的方法就是进入浏览器的设置把你网址的HSTS记录删除。 否则你永远也无法使用HTTP来访问网站。 当然, 有时候你可以使用一个新的没有登录过HTTPS 浏览器或隐身模式来开网站。
使用 phpmyadmin 改为网址再清了HSTS后,你就可以用HTTP 访问网站了。 但是这绕了一圈又回到原点, 并没有解决HTTP 登录后台不安全的问题。 所以, 后面才是真正的解决方案。
首先, 我们在后台设置的网址应该用 HTTP,而不是HTTPS。
是否强制使用HTTPS, 我们可以通过设置反向代理来做到, 比如 Nginx-proxy 可以通过 HTTPS_METHOD 这个变量来决定是否强制HTTP或HTTPS, 或两者都可以。 而我是设置了两者都可以。
https://github.com/jwilder/nginx-proxy
如果设置了两者都可以, 我们如何保证用HTTPS后台登录呢? 这时候,我们可以在 wp-config.php 里加入以下这行
define('FORCE_SSL_ADMIN', true);
这样会强制在登录后台的时候会转到HTTPS, 不登录后台的话, 则HTTP或HTTPS都可以。
然后就是最重要的一步,
你要在wp-config.php 里面加入以下代码来识别浏览器的原协议是否HTTPS。
// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact // see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; }
或者你也可以试试官方给出的代码, 效果应该一样。
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) $_SERVER['HTTPS']='on';
这段代码假设你的反向代理有插入 X_FORWARDED 头, 至少 nginx-proxy 是有的。 如果你的反向代理没有, 你应该可以将这个功能打开。 如果不行, 建议你换个反向代理工具。
好了, 以上就是烦人的 HTTP WordPress behind HTTPS reverse proxy 的问题的解决方案。 顺便提一下, 这种情况不要去安装 WordPress 的HTTPS /SSL 插件, 它们并没有用。