Nginx 리버스 프록시 및 WordPress

Nginx 리버스 프록시 및 WordPress

모든 것이 잘 작동하지만 확장 프로그램 페이지에 있는 동안 WordPress에 문제가 발생합니다.

문제는 플러그인 아이콘이 표시되지 않고 설치하려는 플러그인의 플러그인 아이콘을 클릭하면 빈 창이 열리고 계속 로드된다는 것입니다. 하지만 "설치" 버튼을 클릭하면 플러그인이 문제 없이 설치됩니다.

이 이미지를 보고 무슨 일이 일어나는지 확인할 수 있습니다.

워드프레스 발행

구성은 다음과 같습니다.

구성

웹서버 구성은 다음과 같습니다.

프론트엔드 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);
}

이 문제는 광택제와 관련된 것이 아니라 백엔드와 관련이 있다고 생각합니다. 왜냐하면 이 구성(광택 없음/백엔드 없음)으로 테스트할 때 모든 것이 문제 없이 작동하기 때문입니다.

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_passVarnish 블록 내부의 지시문은 요청 locationupstream(내부 호스트) 네트워크의 서버로 전달합니다. 이는 더 이상 Nginx 서버에 있지 않고 Varnish 서버에 있으며 네트워크의 포트 9000에서 수신 대기하고 있음을 의미합니다. 이제 a를 정의 Content-Security-Policy하고 자신의 네트워크에 대한 액세스를 허용하지 않으면 서버가 다음과 같이 잠길 수 있습니다.과잉보호하는 부모.

서버가 전달하는 모든 것을 맹목적으로 신뢰하는 대신,CSP는 Content-Security-Policy HTTP 헤더를 정의합니다.이를 통해 신뢰할 수 있는 콘텐츠 소스의 화이트리스트를 생성하고 해당 소스의 리소스만 실행하거나 렌더링하도록 브라우저에 지시할 수 있습니다. 공격자가 스크립트를 주입할 구멍을 찾아낸다고 해도 해당 스크립트는 화이트리스트와 일치하지 않으므로 실행되지 않습니다.

우리는 유효한 코드를 제공할 것을 신뢰 apis.google.com하고 우리 자신도 그렇게 할 것이라고 신뢰하므로 스크립트가 두 소스 중 하나에서 올 때만 실행되도록 허용하는 정책을 정의해 보겠습니다.

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

… 짐작하셨겠지만 은 script-src특정 페이지에 대한 스크립트 관련 권한 집합을 제어하는 ​​지시어입니다. 우리는 'self'하나의 유효한 스크립트 소스와 다른 소스를 지정했습니다 https://apis.google.com. 브라우저는 apis.google.com현재 페이지 원본뿐만 아니라 HTTPS를 통해 JavaScript를 성실하게 다운로드하고 실행합니다.

견적 출처:HTML5Rocks

관련 정보