Nginx リバース プロキシと WordPress

Nginx リバース プロキシと WordPress

すべて正常に動作していますが、拡張機能ページにいるときに WordPress で問題が発生します。

問題は、プラグイン アイコンが表示されず、インストールしたいプラグインのアイコンをクリックすると、空のウィンドウが開き、永遠に読み込みが続くことです。ただし、「インストール」ボタンをクリックすると、プラグインは問題なくインストールされます。

この画像を見れば何が起こるか分かります

問題Wordpress

設定は次のとおりです:

設定

Web サーバーの構成は次のとおりです。

フロントエンド Nginx

server {
        listen 443 ssl;

            # SSL 
            ssl on;
            ssl_certificate /etc/ssl/nginx/nginx.crt;
            ssl_certificate_key /etc/ssl/nginx/nginx.key;
            ssl_session_cache shared:SSL:40m;
            ssl_session_timeout 10m;
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
            ssl_prefer_server_ciphers on;

        server_name domaine.tld;

        # Proxy Pass to Varnish and  Add headers to recognize SSL
        location / {
            proxy_pass  http://127.0.0.1:80;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header X-Secure on;
        }
}

バックエンド Nginx

server {
        listen 8000;

        server_name domaine.tld;
        root /var/www/domaine;
        index index.php;

        # Custom Error Page
        error_page  404 403 /page_error/404.html;
        # Log
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        location / {
            try_files $uri $uri/ /index.php?$args;
                    auth_basic "Restricted";
                auth_basic_user_file /etc/nginx/.htpasswd;
        }

            # PHP-FPM
            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;
                    fastcgi_param  HTTPS              on;
            }
}

ワニスデフォルト

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

ワニス VCL 4.0

backend default {
    .host = "127.0.0.1";
    .port = "8000";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
    .max_connections = 800;
}

# Only allow purging from specific IPs
acl purge {
    "localhost";
    "127.0.0.1";
}

# This function is used when a request is send by a HTTP client (Browser) 
sub vcl_recv {

    # Redirect to https
    if ( (req.http.host ~ "^(?i)www.domaine.tld" || req.http.host ~ "^(?i)domaine.tld") && req.http.X-Forwarded-Proto !~ "(?i)https") {
                return (synth(750, ""));
        }

    # Normalize the header, remove the port (in case you're testing this on various TCP ports)
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # Allow purging from ACL
    if (req.method == "PURGE") {
        # If not allowed then a error 405 is returned
        if (!client.ip ~ purge) {
            return(synth(405, "This IP is not allowed to send PURGE requests."));
        }   
        # If allowed, do a cache_lookup -> vlc_hit() or vlc_miss()
        return (purge);
    }

    # Post requests will not be cached
    if (req.http.Authorization || req.method == "POST") {
        return (pass);
    }

    # Did not cache .ht* file
    if ( req.url ~ ".*htaccess.*" ) {
        return(pass);
    }

    if ( req.url ~ ".*htpasswd.*" ) {
        return(pass);
    }

    # Don't cache phpmyadmin
    if ( req.url ~ "/nothingtodo" ) {
        return(pass);
    }

    # --- Wordpress specific configuration

    # Did not cache the RSS feed
    if (req.url ~ "/feed") {
        return (pass);
    }

    # Don't cache 404 error 
    if (req.url ~ "^/404") {
        return (pass);
    }

    # Blitz hack
        if (req.url ~ "/mu-.*") {
                return (pass);
        }


    # Did not cache the admin and login pages
    if (req.url ~ "/wp-(login|admin)") {
        return (pass);
    }

     # Do not cache the WooCommerce pages
     ### REMOVE IT IF YOU DO NOT USE WOOCOMMERCE ###
    if (req.url ~ "/(cart|my-account|checkout|addons|/?add-to-cart=)") {
            return (pass);
        }

    # First remove the Google Analytics added parameters, useless for our backend
    if(req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
        set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        set req.url = regsub(req.url, "\?$", "");
    }

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

    # Remove any Google Analytics based cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");

    # Remove the Quant Capital cookies (added by some plugin, all __qca)
    set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");

    # 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=[^;]+(; )?", "");

    # remove cookies for comments cookie to make caching better.
    set req.http.cookie = regsub(req.http.cookie, "dcd9527364a17bb2ae97db0ead3110ed=[^;]+(; )?", "");

    # remove ?ver=xxxxx strings from urls so css and js files are cached.
    set req.url = regsub(req.url, "\?ver=.*$", "");
    # Remove "replytocom" from requests to make caching better.
    set req.url = regsub(req.url, "\?replytocom=.*$", "");
    # Strip hash, server doesn't need it.
    set req.url = regsub(req.url, "\#.*$", "");
    # Strip trailing ?
    set req.url = regsub(req.url, "\?$", "");

    # Are there cookies left with only spaces or that are empty?
    if (req.http.cookie ~ "^ *$") {
            unset req.http.cookie;
    }

    # Drop any cookies sent to Wordpress.
    if (!(req.url ~ "wp-(login|admin)")) {
                       unset req.http.cookie;
        }

    # Cache the following files extensions 
    if (req.url ~ "\.(css|js|png|gif|jp(e)?g|swf|ico)") {
        unset req.http.cookie;
    }

    # Normalize Accept-Encoding header and compression
    # https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
    if (req.http.Accept-Encoding) {
        # Do no compress compressed files...
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
                unset req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
                set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate") {
                set req.http.Accept-Encoding = "deflate";
        } else {
            unset req.http.Accept-Encoding;
        }
    }

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

    # --- End of Wordpress specific configuration

    # No cache for big video files
    if (req.url ~ "\.(avi|mp4)") {
        return (pass);
    } 

    # Did not cache HTTP authentication and HTTP Cookie
    if (req.http.Authorization || req.http.Cookie) {
        # Not cacheable by default
        return (pass);
    }

    # Cache all others requests
    return (hash);
}

sub vcl_pipe {
    # Note that only the first request to the backend will have
    # X-Forwarded-For set. If you use X-Forwarded-For and want to
    # have it set for all requests, make sure to have:
    # set bereq.http.connection = "close";
    # here. It is not set by default as it might break some broken web
    # applications, like IIS with NTLM authentication.
    #set bereq.http.Connection = "Close";
    return (pipe);
}

sub vcl_pass {
    return (fetch);
}

sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.Location = "https://www.paris-vendome.com" + req.url;
        return(deliver);
    }
}


# The data on which the hashing will take place
sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # hash cookies for requests that have them
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }

    # If the client supports compression, keep that in a different cache
        if (req.http.Accept-Encoding) {
            hash_data(req.http.Accept-Encoding);
    }

    return (lookup);
}

# This function is used when a request is sent by our backend (Nginx server)
sub vcl_backend_response {
    # Remove some headers we never want to see
    unset beresp.http.Server;
    unset beresp.http.X-Powered-By;

    # For static content strip all backend cookies
    if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g)|swf|ico") {
        unset beresp.http.cookie;
    }

    # Only allow cookies to be set if we're in admin area
    if (beresp.http.Set-Cookie && bereq.url !~ "^/wp-(login|admin)") {
            unset beresp.http.Set-Cookie;
        }

    # don't cache response to posted requests or those with basic auth
    if ( bereq.method == "POST" || bereq.http.Authorization ) {
            set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
        }

        # don't cache search results
    if ( bereq.url ~ "\?s=" ){
        set beresp.uncacheable = true;
                set beresp.ttl = 120s;
                return (deliver);
    }

    # only cache status ok
    if ( beresp.status != 200 ) {
        set beresp.uncacheable = true;
                set beresp.ttl = 120s;
                return (deliver);
    }

    # A TTL of 24h
    set beresp.ttl = 24h;
    # Define the default grace period to serve cached content
    set beresp.grace = 30s;

    return (deliver);
}

# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
    if (obj.hits > 0) { 
        set resp.http.X-Cache = "cached";
    } else {
        set resp.http.x-Cache = "uncached";
    }

    # Remove some headers: PHP version
    unset resp.http.X-Powered-By;

    # Remove some headers: Apache version & OS
    unset resp.http.Server;

    # Remove some headers: Varnish
    unset resp.http.Via;
    unset resp.http.X-Varnish;

    unset resp.http.Age;
    unset resp.http.Link;

    return (deliver);
}

sub vcl_hit {
    return (deliver);
}
sub vcl_miss {
    return (fetch);
}

sub vcl_init {
    return (ok);
}

sub vcl_fini {
    return (ok);
}

この設定 (varnish なし / バックエンドなし) でテストすると、すべて問題なく動作するため、問題は varnish ではなくバックエンドに関連していると思います。

server {
       listen         80;
       server_name    domaine.tld;
       return         301 https://www.domaine.tld$request_uri;
}


server{
    listen 443;
    ssl on;
    ssl_certificate /etc/ssl/nginx/nginx.crt;
    ssl_certificate_key /etc/ssl/nginx/nginx.key;
    ssl_session_timeout 10m;

    root /var/www/domaine;
    index index.htm index.html index.php;

    server_name domaine.tld;

    server_tokens off;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    error_page 404 403         /page_error/404.html;
    error_page 500 502 503 504 /page_error/50x.html;

    gzip on;
    etag off;


    location / {
        try_files $uri $uri/ =404;
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }

    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;
        fastcgi_param  HTTPS              on;
    }
}

何か見落としがあったり、もっと情報が欲しい場合は、遠慮なくご連絡ください。長い投稿で申し訳ありませんが、必死です。誰かが助けてくれることを願っています。よろしくお願いします

答え1

あなたのコメントに答えるには:

解決済み: 理由はわかりませんが、 の問題でしたadd_header Content-Security-Policy。http ブロックから削除したら、すべて正常に動作するようになりました。

ディレクティブproxy_pass(Varnishlocationブロック内)は、リクエストをupstream(内部ホスト)ネットワーク内のサーバーに渡します。つまり、Nginxサーバーではなく、ネットワークのポート9000でリッスンしているVarnishサーバーにいることになります。ここで を定義してContent-Security-Policy自分のネットワークへのアクセスを許可しないと、サーバーが過保護な親

サーバーが提供するものすべてを盲目的に信頼するのではなく、CSPはContent-Security-Policy HTTPヘッダーを定義しますこれにより、信頼できるコンテンツのソースのホワイトリストを作成し、それらのソースからのリソースのみを実行またはレンダリングするようにブラウザに指示できます。攻撃者がスクリプトを挿入するための穴を見つけたとしても、スクリプトはホワイトリストと一致しないため、実行されません。

有効なコードを配信することを信頼しておりapis.google.com、また、自分たち自身もそうすることを信頼しているので、スクリプトがこれら 2 つのソースのいずれかから来た場合にのみ実行を許可するポリシーを定義しましょう。

Content-Security-Policy: script-src 'self' https://apis.google.com

… おそらくご想像のとおり、これはscript-src特定のページのスクリプト関連の権限セットを制御するディレクティブです。 を'self'1 つの有効なスクリプト ソースとして指定し、もう 1 つを として指定しました。ブラウザは、現在のページのオリジンだけでなく、HTTPS 経由でもhttps://apis.google.comJavaScript をダウンロードして実行します。apis.google.com

引用元:HTML5ロック

関連情報