【问题标题】:Wordpress Permalinks return 404 when using NGINX as a reverse proxy to apache使用 NGINX 作为 apache 的反向代理时,Wordpress 永久链接返回 404
【发布时间】:2018-11-06 09:02:16
【问题描述】:

我正在尝试让 NGINX 反向代理并为在 Apache 上运行的 WordPress 站点提供 SSL 终止,端口为 8086。我希望 NGINX 处理静态文件,并且只代理对 Apache 的 PHP 请求。

我已经成功地使用标准链接使其工作。 (即https://example.com/?post=274 工作正常)

当我启用任何类型的永久链接时,主页会加载,wp-admin 也会加载,但https://example.com/what-we-do/ 失败。

查看 NGINX 日志,我明白了

2018/05/23 09:36:40 [error] 7472#0: *1 "/var/www/example.com/live_site/what-we-do/index.php" is not found (2: No such file or directory), client: xxx.xxx.xxx.xxx, server: example.com, request: "GET /what-we-do/ HTTP/2.0", host: "example.com", referrer: "https://example.com/?post=274"

所以 NGINX 试图寻找 /permalink/index.php 作为静态路径/文件,而不是传递给 apache。关于如何让它发挥作用的任何想法?

我的 NGINX 配置如下:

upstream example_apache {
    ip_hash;
    server 127.0.0.1:8086;
}

server {
# HTTP/HTTPS Server Block
# General Config
    listen                      [::]:80;
    listen                      80;
    listen                      [::]:443 http2 ssl;
    listen                      443 http2 ssl;
    server_name                 example.com
                                www.example.com;

    root                        /var/www/example.com/live_site;
    access_log                  /var/log/nginx/access-example.com.log main;
    error_log                   /var/log/nginx/error-example.com.log;
    index                       index.php;

#SSL Cert Configuration
# Check SSL config at https://www.ssllabs.com/ssltest/
    ssl_prefer_server_ciphers   on;
    ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers                 "ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH DHE-RSA-CHACHA20-POLY1305 EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4 !SEED !CAMELLIA";
    ssl_session_cache           shared:SSL:100m;
    ssl_session_timeout         180m;
    ssl_dhparam                 /var/www/certs/dh4096.pem;

    ssl_certificate             /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.secp384r1.cer;
    ssl_certificate_key         /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.secp384r1.key;
    ssl_certificate             /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.rsa4096.cer;
    ssl_certificate_key         /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.rsa4096.key;

# Enable HSTS #Deploy in stages to prevent extended loss to site.
    add_header                  Strict-Transport-Security "max-age=300; includeSubdomains;"; #300s-5min TTL Testing
    #add_header                 Strict-Transport-Security "max-age=604800; includeSubdomains;"; #1week TTL Testing
    #add_header                 Strict-Transport-Security "max-age=2592000; includeSubdomains;"; #1month TTL Testing
    #add_header                 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; #10886400s-126days Min for Preload
    #add_header                 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; #63072000s-2years Production Value

# OCSP Configuration
    ssl_trusted_certificate     /var/www/certs/lets_encrypt/web01.example.com/web01.example.com.fullchain.secp384r1.cer;
    ssl_stapling                on;
    ssl_stapling_verify         on;
    resolver                    8.8.4.4 8.8.8.8 valid=300s;
    resolver_timeout            10s;

# LetEncrypt webroot alias
    location /.well-known/acme-challenge/ {
        alias /var/www/le_root/.well-known/acme-challenge/;
    }
# www to non-www rewrite
# Redirect to the correct place, if needed
    set $https_redirect 0;
    if ($server_port = 80) { set $https_redirect 1; }
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) {
        return 301 https://example.com$request_uri;
    }

# Wordpress entry point
    location / {
        #Try                    file dir    index.php else 404
        try_files               $uri $uri/ /index.php?$args =404;

        #All Files except for *.php
        location ~ .+(?<!\.php)$ {
            location ~ ^[^.]+\.[^.]+$ {
                expires         max;
                add_header      Cache-Control public;
                break;
            }
        }

        #Only *.php files
        location ~ \.php$ {
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    Host                $host;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header    X-Forwarded-Proto   $scheme;
            proxy_pass_header                       Set-Cookie;

            proxy_set_header    SSL_PROTOCOL        $ssl_protocol;
            proxy_set_header    SSL_CLIENT_CERT     $ssl_client_cert;
            proxy_set_header    SSL_CLIENT_VERIFY   $ssl_client_verify;
            proxy_set_header    SSL_SERVER_S_DN     $ssl_client_s_dn;

            proxy_pass                              http://example_apache;
        }
    }
}

由于这个问题甚至没有涉及代理通行证部分,而且似乎与 NGINX 严格相关(我可以说),因此以下内容不适用。但是有人会想知道,或者它可能会帮助其他在这个问题上绊倒的人也了解 apache 配置方面。

我的 apache 有一个 .htaccess 文件,其中包含:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

我的 wp-config.php 有:

// If WordPress is behind reverse proxy
// which proxies https to http
if ( (!empty( $_SERVER['HTTP_X_FORWARDED_HOST'])) ||
 (!empty( $_SERVER['HTTP_X_FORWARDED_FOR'])) ) {

$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];

$_SERVER['HTTPS'] = 'on';
}

我的 apache 配置有:

<VirtualHost *:8086>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/example.com/live_site
ServerName  example.com
ServerAlias www.example.com


ErrorLog ${APACHE_LOG_DIR}/example.com.error.log
CustomLog ${APACHE_LOG_DIR}/example.com.access.log combined

Alias "/.well-known/acme-challenge/" "/var/www/le_root/.well-known/acme-challenge/"

<Directory />
    Options FollowSymLinks
    AllowOverride None
</Directory>
<Directory /var/www/example.com/live_site>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
</Directory>

</VirtualHost>

我还应该注意,当我直接连接到 Apache 时,我可以正确看到所有页面的永久链接。 (即http://127.0.0.1:8086/what-we-do/ 工作正常)

NGINX 版本 1.13.9
Apache 2.4.33 mpm_prefork
PHP 版本 7.1

任何想法或帮助让 NGINX 正确代理到 apache 的永久链接将不胜感激!

【问题讨论】:

  • 很遗憾没有人知道这里需要做什么。我多次遇到这个问题,这让我想知道反向代理 Wordpress 的好处是否值得。想知道如果我使用 Varnish 而不是 NGINX 是否会遇到同样的问题。

标签: php wordpress apache nginx nginx-reverse-proxy


【解决方案1】:

启用或检查是否使用此命令启用了 mod_rewrite

sudo a2enmod 重写

【讨论】:

  • 就像我说的,当我访问由 apache 提供服务的站点时,永久链接会起作用。只有当 nginx 代理时,它们才没有正确传递。如果我要删除 nginx 代理并让 apache 直接服务,那么该站点 100% 已经可以工作了。
【解决方案2】:

当我使用 NGINX 将我的 Prod 环境迁移到 Docker 时,我收到了同样的错误,但我没有为 Apache 进行反向代理。不过,我的错误是一样的。

原因是我必须更改 wp_options 以匹配我的新本地端口和 URL。

SELECT * FROM wp_options WHERE option_name='siteurl' OR option_name='home'; 将显示您的 WordPress 配置尝试导航到的当前 URL。但是由于您已经创建了一个代理并且现在您的 WordPress 站点位于不同的端口或 URL 后面,您可能需要更改这些值。

当您执行该命令时,您将收到您的站点用作前缀的两个 URL 的列表。如果它显示代理的 URL,这可能不起作用。

然后我修改了 URL 以匹配新后端 URL + 端口的位置。在您的情况下,您可能必须更改它以匹配代理后面的端口和 url,而不是代理本身的 URL。

在我的wp-config.php 中修改这些值不起作用。例如

 define('WP_HOME','http://local.www.greenhousetreatment.com:8080');
 define('WP_SITEURL','http://local.www.greenhousetreatment.com:8080');

这对我不起作用。

我必须在 SQL 中手动使用上述命令,然后更新这些值以匹配网站的 PORT 和 URL。通常在反向代理中,您将输入代理 URL,然后它将访问您的服务 IP 和端口。您的服务 IP 和 PORT 完成了它需要做的事情,因为它根本不关心代理。它甚至不知道代理。

您确定您的wp_options 与实际服务 URL 和 PORT 匹配,而不是代理 URL?

我希望这能带来一些启示。

【讨论】:

  • 我只是想在这里跟进,这没有帮助。问题是在 wordpress 参与之前,正如你在上面看到的,NGINX 试图在错误的位置寻找 index.php。我猜我可能不得不在 NGINX 中加入一些复杂的重写规则。我最终放弃了这个,因为正确配置需要很长时间。我让 NGINX 直接为 wordpress 提供服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-25
  • 2015-02-20
  • 1970-01-01
  • 2014-06-16
  • 1970-01-01
  • 2017-07-01
  • 1970-01-01
相关资源
最近更新 更多