WordPress 相对路径配置(HTTPS、反向代理)

最近将以前用WordPress建的网站进行迁移,发现其中很多链接因为绝对路径的原因都失效了,所以就想了些办法,将其中的链接改为相对路径,并且顺手解决了过程中遇到的一些问题。

问题原因

问题的原因其实很简单,就是因为WordPress里使用的都是绝对路径,这些路径都是保存在数据库的,如果IP或者域名发生了变化,就会造成原来链接的失效。着急的读者可以直接看完整解决方案

解决办法

查了网上的资料,发现我遇到的情况还是比较复杂的:

  • 服务器的IP地址发生了变化;
  • 服务器增加了HTTPS访问;
  • 服务器的内外地址都不是默认端口(80、443)。

所以各种解决方案也都试了一下,最后算是比较圆满的解决了,简单记录一下。

修改wp-config.php

wp-config.php的最后加上以下语句:

1
2
3
4
$home = ‘http://’.$_SERVER['HTTP_HOST'];
$siteurl = ‘http://’.$_SERVER['HTTP_HOST'];
define(‘WP_HOME’, $home);
define(‘WP_SITEURL’, $siteurl);

这种修改的方法,其实并不真正改为“相对路径”,而是通过判断域名,将域名付给homesiteurl两个全局变量,这样访问路径会随访问域名改变,很适合网站迁移时使用。

类似地,还有一种基本相同的修改方法:在wp-config.phprequire_once ABSPATH . 'wp-settings.php';语句之前添加以下代码:

1
2
3
4
5
6
$home = 'http://'.$_SERVER['HTTP_HOST'].'/';
$siteurl = 'http://'.$_SERVER['HTTP_HOST'].'/';
$conturl = 'http://'.$_SERVER['HTTP_HOST'].'/wp-content';
define('WP_CONTENT_URL', $conturl);
define('WP_HOME', $home);
define('WP_SITEURL', $siteurl);

我用了下面这一段代码,确实可以解决一部分内容的访问,主要是wp-content目录下的内容可以正常访问。

安装WordPress插件

对相对路径的需求可以说不在少数,所以也就有热心的开发者开发了相应的插件,查了一下还是有挺多的,我使用的是Make Paths Relative这一款,使用截图如下:

image-20220127212440103

如果对PHP或者WordPress不是很了解的话,我推荐使用这个方法,当然如果考虑到安全性,还要看一下插件的说明,是否适合生产环境使用。

使用插件对settings的影响

最后,我也选择使用插件来修改相对路径,但是也发现了一个很有意思的错误:如果在settings保存时,WordPress Address(URL)Site Address(URL),也会根据插件中的Site Address截取相对路径,如果两者相同,那么保存到数据库wp_optionshomesiteurl就会变成空字符串,就会导致数据库错误而无法启动。这个时候就必须要把wp_optionshomesiteurl的值改回来才可以。

image-20220129171144026

image-20220129171630517

出现这个问题的原因当然是由于插件造成的,在这个问题得到修复之前,为了避免这个问题,在修改General Settings的时候应该先停用Make Paths Relative

配置HTTPS访问

我在内网部署WordPress服务,只提供HTTP服务,通过反向代理提供外网的HTTPS访问。

根据Word Press的官方说明,如果是以上情景,应当在wp-config.php进行如下配置:

1
2
3
4
5
6
define('FORCE_SSL_ADMIN', true);
// in some setups HTTP_X_FORWARDED_PROTO might contain
// a comma-separated list e.g. http,https
// so check for https existence
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
$_SERVER['HTTPS']='on';

注意:以上这段代码同样要加在require_once(ABSPATH . 'wp-settings.php');之前

但是,实际上加了这一段代码以后,我反而不能通过HTTPS访问管理页面了,而是会直接重定向为以HTTPS协议访问内网服务地址。

之所以出现这样的问题,是因为上面修改相对路径造成的,更准确地说,是WP_HOME被硬编码为内网地址,而内网地址只能以HTTP的方式提供服务,所以就不可能通过HTTPS访问了。因此,为了配置HTTPS访问,还是使用插件设置相对路径为好。

反向代理的HOST设置

在使用Nginx提供HTTPS反向代理的时候,如果WordPress内部有重定向或者跳转,就有可能跳转到内网的地址,跳转的地址其实是由$_SERVER['HOST']决定的,所以可以采取的解决办法有两个:

  1. 在内网的HOST中添加DNS记录,以域名而不是IP地址访问服务;
  2. 反向代理转发的时候,通过X-Forwarded-Host向WordPress服务传递域名信息。

image-20220129181328484

我采用的是第2种方法,需要注意的是,要在Nginx的配置文件和wp-config.php文件中进行修改,具体的修改方法详见完整解决方案

管理页面CSS与JS丢失

在配置好HTTPS访问之后,网站的内容正常,但是管理页面仍然可能出问题:wp-admin/load-scripts.phpload-styles.php的URL是HTTP协议,也就无法被加载。

Javascript错误

这两个php的功能实际上WordPress为了减少对后台服务的请求,将页面所需要的CSS和JS文件分别合并成一个文件,这样就各自只需要一个请求。为了解决这个问题,也有两种解决办法:

  1. wp-includes文件夹里找到functions.php,在最后加入下面代码,更换JS/CSS路径为相对路径:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    add_filter('script_loader_src', 'agnostic_script_loader_src', 20,2);
    function agnostic_script_loader_src($src, $handle) {
    return preg_replace('/^(http|https):/', '', $src);
    }

    add_filter('style_loader_src', 'agnostic_style_loader_src', 20,2);
    function agnostic_style_loader_src($src, $handle) {
    return preg_replace('/^(http|https):/', '', $src);
    }
  2. 在网站根目录的wp-config.php文件中,添加以下这句代码即可:

    1
    define('CONCATENATE_SCRIPTS', false);

    这段代码的作用是禁止把CSS/JS文件进行合并。

对于以上两种方法,推荐使用方法2,一来方法2更加简单,二来方法1修改的文件可能会由于WordPress更新而被覆盖。所以能通过修改wp-config.php实现的,尽量不要修改其他源码

完整解决方案

最后,给出解决以上问题后的完整解决方案。假设我们的网站拓扑如下:

image-20220129204154228

需要设置的包括Nginx反向代理配置文件、WordPress的wp-config.php文件以及WordPress的后台管理设置,分别如下。

Nginx反向代理配置

文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

server {

listen 1234 ssl;
server_name www.example.com
ssl_certificate "/CERTS_DIR/www.example.com.pem";
ssl_certificate_key "/CERTS_DIR/www.example.com.key";
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# http 转https
# 参考:https://www.jianshu.com/p/5cb7e97ecbda
# 参考:https://qastack.cn/server/47876/handling-http-and-https-requests-using-a-single-port-with-nginx
error_page 497 301 =307 https://$host:$server_port$request_uri;


location / {
proxy_pass http://20.22.01.29:5678;
# $host equals $http_host, lowercase and without the port number (if present), except when HTTP_HOST is absent or is an empty value.
proxy_set_header Host $host:$server_port;
# 客户端IP
proxy_set_header X-Real-IP $remote_addr;
# 反向代理域名,这里即 www.example.com:1234
proxy_set_header X-Forwarded-Host $host:$server_port;
# X-Forwarded-For包含多个IP地址,每个值通过逗号+空格分开,最左边(client1)是最原始客户端的IP地址,中间如果有多层代理,每一层代理会将连接它的客户端IP追加在X-Forwarded-For右边。
# $proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 所用的协议,比如http或者是http
proxy_set_header X-Forwarded-Proto $scheme;
# 反向代理的端口好
proxy_set_header X-Forwarded-Port $server_port;
client_max_body_size 0;
# 参数off将在这个字段中禁止所有的proxy_redirect指令
proxy_redirect off;
}
}

wp-config.php文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// 根据$_SERVER['HTTP_X_FORWARDED_PROTO']判断反向代理过来的是否为https请求
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS']='on'; // 表示当前访问为https
}

// 判断是否访问请求经过代理
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; // 如果经过代理,需要修改主机地址
}

// 访问后台强制使用https
// FORCE_SSL_LOGIN was deprecated in Version 4.0. Please use FORCE_SSL_ADMIN.
// define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);

define('CONCATENATE_SCRIPTS', false );


//---------------------------在 require_once ABSPATH . 'wp-settings.php'; 之前------------------------

WordPress后台配置

设置WordPress AddressSite Address为反向代理服务地址(HTTPS协议)。

image-20220129171144026

Tips

  1. wp-config.php配置详解;

  2. WordPress在浏览器的console输出信息

    简要写法举例:

    1
    echo '<script>console.log("'.$_SERVER['HTTP_HOST'].'");</script>';

结论

我不会世界上最好的语言——PHP,之前也没用过互联网上最流行的内容管理系统——WordPress,数据恢复、网站迁移、相对URL、HTTPS、反向代理、插件Bug……算是基本折腾好了。感觉收获不少,简单做个记录。

参考资料:

  1. https://www.its404.com/article/qq_39339179/120841435
  2. http://www.ddbq.net/2021/01/wordpress使用frp内网穿透后样式丢失问题解决/
  3. https://www.seoo.net/maint/613.html
  4. https://stackoverflow.com/questions/32588692/how-does-concatenate-scripts-work-on-wp-config/32589922
  5. https://zhuanlan.zhihu.com/p/376040113
  6. Issue with SSL when using nginx reverse proxy | WordPress.org
  7. Nginx反向代理中使用proxy_redirect重定向url - 散尽浮华 - 博客园 (cnblogs.com)
  8. https://help.dreamhost.com/hc/en-us/articles/214693268-WordPress-wp-config-php-overview
  9. https://core.trac.wordpress.org/ticket/17048
  10. https://code.tutsplus.com/tutorials/50-filters-of-wordpress-filters-41-50--cms-21299
  11. https://wordpress.org/support/article/administration-over-ssl/
  12. https://wordpress.stackexchange.com/questions/250240/setting-serverhttps-on-prevents-access-to-wp-admin
  13. https://segmentfault.com/a/1190000023353059