【问题标题】:How to proxy NGINX, Varnish, and PHP-FPM over SSL如何通过 SSL 代理 NGINX、Varnish 和 PHP-FPM
【发布时间】:2017-09-27 07:01:34
【问题描述】:

试图弄清楚如何使用 NGINX 和 PHP-FPM 托管 WordPress 网站,但还要添加 Varnish 进行缓存;更糟糕的是,通过 SSL 提供此功能。

我曾与 NGINX、Varnish 和 Gunicorn 合作过一个 SSL Django 站点,我认为这可能是相似的。我之前也设置过 Varnish、Apache 和 WordPress。但到目前为止,我的日志一无所获。


下面是目前的工作原理(NGINX 和 FPM):

NGINX 端口 80 转发到 443(也将 www 转发到非 www)。

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com
    return 301 https://example.com$request_uri;
}

NGINX 端口 443 传递给 PHP-FPM 监听端口 9000

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    access_log /var/log/nginx-access.log;
    error_log /var/log/nginx-error.log;

    server_name example.com;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

所以我添加清漆

我已经在端口 6081(默认)上设置了 Varnish,并将其指向 8080 作为后端。

然后我为 NGINX 添加另一个端口以代理到 FPM(像以前一样)

然后我为 NGINX 添加了这个配置来处理端口 8080,因为它太小了,所以在此处完整发布(注意!这部分似乎是问题):

server {
    listen 127.0.0.1:8080;

    access_log /var/log/nginx-access.log;
    error_log /var/log/php-fpm-error.log;

    root /var/www/example.com;

    index index.php;
    port_in_redirect off;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }
}

然后我将 NGINX 的 SSL 部分更改为 proxy_pass 到 Varnish(就像我在其他项目中所做的那样):

upstream varnish_server {
    server 127.0.0.1:6081 fail_timeout=0;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    # etc. 

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header 'Access-Control-Allow-Origin' '*';

        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header HTTPS "on";
        proxy_pass http://varnish_server;
        break;
    }
}

我收到的错误:

varnishlog 是这样说的:

   11 ReqStart     c 127.0.0.1 39742 1007025263
   11 RxRequest    c GET
   11 RxURL        c /
   11 RxProtocol   c HTTP/1.0
   11 RxHeader     c X-Forwarded-For: 12.34.567.890
   11 RxHeader     c Host: example.com
   11 RxHeader     c Access-Control-Allow-Origin: *
   11 RxHeader     c X-Forwarded-Host: example.com
   11 RxHeader     c X-Real-IP: 12.34.567.890
   11 RxHeader     c X-Forwarded-Proto: https
   11 RxHeader     c HTTPS: on
   11 VCL_call     c pass pass
   11 FetchError   c no backend connection
   11 VCL_call     c error deliver
   11 VCL_call     c deliver deliver
   11 TxProtocol   c HTTP/1.1
   11 TxStatus     c 503
   11 TxResponse   c Service Unavailable
   11 TxHeader     c Server: Varnish

nginx-error.log 是这样说的:

[error] 7532#0: *1 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 12.34.567.890, server: example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:6081/", host: "example.com"

从视觉上看,网站挂起大约一两分钟,超时;看不到任何其他错误。

另外,请注意,我按照WordPress Codex 中的建议将其添加到 wp-config.php:

if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
       $_SERVER['HTTPS']='on';

对此的任何帮助将不胜感激! :D

更新

按要求清漆 default.vcl;不过,它实际上与 tutslpus 教程相同(here):

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 60s;
    .max_connections = 500;
}

acl purge {
    "127.0.0.1";
    "localhost";
}

sub vcl_recv {
    set req.grace = 2m;

    # Set X-Forwarded-For header for logging in nginx
    remove req.http.X-Forwarded-For;
    set    req.http.X-Forwarded-For = client.ip;

    # Remove has_js and CloudFlare/Google Analytics __* cookies and statcounter is_unique
    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js|is_unique)=[^;]*", "");
    # Remove a ";" prefix, if present.
    set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");

    # Either the admin pages or the login
    if (req.url ~ "/wp-(login|admin|cron)") {
        # Don't cache, pass to backend
        return (pass);
    }

    # Remove the wp-settings-1 cookie
    set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");

    # Remove the wp-settings-time-1 cookie
    set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");

    # Remove the wp test cookie
    set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");

    # Static content unique to the theme can be cached (so no user uploaded images)
    # The reason I don't take the wp-content/uploads is because of cache size on bigger blogs
    # that would fill up with all those files getting pushed into cache
    if (req.url ~ "wp-content/themes/" && req.url ~ "\.(css|js|png|gif|jp(e)?g)") {
        unset req.http.cookie;
    }

    # Even if no cookies are present, I don't want my "uploads" to be cached due to their potential size
    if (req.url ~ "/wp-content/uploads/") {
        return (pass);
    }

    # any pages with captchas need to be excluded
    if (req.url ~ "^/contact/" || req.url ~ "^/links/domains-for-sale/") {
        return(pass);
    }

    # Check the cookies for wordpress-specific items
    if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
        # A wordpress specific cookie has been set
        return (pass);
    }

    # allow PURGE from localhost
    if (req.request == "PURGE") {
        if (!client.ip ~ purge) {
                error 405 "Not allowed.";
        }
        return (lookup);
    }

    # Force lookup if the request is a no-cache request from the client
    if (req.http.Cache-Control ~ "no-cache") {
        return (pass);
    }

    # Try a cache-lookup
    return (lookup);

}

sub vcl_deliver {
    if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
    # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
    # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
    # So take hits with a grain of salt
    set resp.http.X-Cache-Hits = obj.hits;
}

sub vcl_fetch {
    # set obj.grace = 5m;
    set beresp.grace = 2m;

    if (req.url !~ "wp-admin|wp-login|product|cart|checkout|my-account|/?remove_item=") {
        unset beresp.http.set-cookie;
    }
}

和 netstat,按要求:

root@server:/# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      13454/memcached 
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      21420/nginx     
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      21420/nginx     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      3583/sshd       
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      3778/master     
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      21420/nginx     
tcp        0      0 0.0.0.0:6081            0.0.0.0:*               LISTEN      29149/varnishd  
tcp        0      0 127.0.0.1:6082          0.0.0.0:*               LISTEN      29148/varnishd  
tcp6       0      0 :::3306                 :::*                    LISTEN      3643/mysqld     
tcp6       0      0 :::80                   :::*                    LISTEN      21420/nginx     
tcp6       0      0 :::22                   :::*                    LISTEN      3583/sshd       
tcp6       0      0 ::1:25                  :::*                    LISTEN      3778/master     
tcp6       0      0 :::443                  :::*                    LISTEN      21420/nginx     
tcp6       0      0 :::6081                 :::*                    LISTEN      29149/varnishd  
tcp6       0      0 ::1:6082                :::*                    LISTEN      29148/varnishd

【问题讨论】:

  • 请发布您的 Varnish 配置,this guide 可能会帮助您。请参阅最后的 HTTPS 部分。
  • 您看到的错误消息表明 nginx 根本无法连接到 varnish。你能检查清漆是否在线并且正在运行?如果是这样,请粘贴配置,并输出“netstat -tnlp”
  • 已更新。回复晚了非常抱歉。我应该说,我看到的错误消息是 Varnish 错误,这意味着 NGINX 实际上是在连接。在我看来,问题是代理回 NGINX,然后是 PHP-FPM。另请注意,我已更改为 PHP-FPM 使用 sock 文件而不是端口 9000(为什么 netstat 不显示 9000)

标签: php wordpress ssl nginx varnish


【解决方案1】:

下面的配置对我有用

  1. 在端口 80 上设置 Varnish 并将其指向 8080 作为后端。
  2. 设置 Nginx 监听 2 个端口:8080 和 443

端口 8080 :当您配置处理网络请求时

    server {
    listen 127.0.0.1:8080;

    access_log /var/log/nginx-access.log;
    error_log /var/log/php-fpm-error.log;

    root /var/www/example.com;

    index index.php;
    port_in_redirect off;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }}

端口 443:proxy_pass 到清漆

    server {
        listen 443 ssl;
        server_name  example.com;
        ssl_certificate /path/to/fullchain.pem;
        ssl_certificate_key /path/to/privkey.pem;

        location / {
            proxy_pass  http://127.0.0.1:80;
    
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header Host $host;
        }
    }

该配置如下:

this image archive

【讨论】:

  • 对,所以这是一个很好的起点,但假设我不希望端口 80 上的流量,我想强制所有流量到端口 443:我应该能够使用 nginx 做到这一点:端口 80 转发到端口 443,然后,当您声明代理传递到指向端口 8080 的清漆(我想留在 6081)时,应该像您所说的那样工作。但是,由于某种原因,它没有传递给 php-fpm。
  • 表示您希望客户端(客户)通过端口 443 访问您的应用程序(Web)的端口
猜你喜欢
  • 1970-01-01
  • 2019-04-01
  • 2015-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多