Назад | Перейти на главную страницу

Запросы, сделанные nginx 'proxy_pass, терпят неудачу, но они успешны, если выполнены вручную

Я проксирую блог WP, который находится за вторым экземпляром nginx (который отправляет запросы в PHP-FPM).

Если я сделаю запрос из браузера или из командной строки, например HTTPie, запрос будет успешным. Например.

$ http http://x.y.z.w/test-page/
HTTP/1.1 200 OK
...

Однако при использовании proxy_pass экземпляр nginx на моем компьютере возвращает 404. После проверки журналов nginx блога WP я вижу следующее:

<my-ip> - - [05/Nov/2019:09:53:37 +0000] "GET /test-page/ HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
<my-ip> - - [05/Nov/2019:09:53:43 +0000] "GET /test-page/ HTTP/1.1" 200 21317 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"

Как вообще возможно, что все выглядит одинаково, но сервер сначала возвращает 404, а затем 200? Должна быть разница. Я также проверил заголовки, которые отправляет HTTPie. Ничего необычного:

GET /test-page/ HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: x.y.z.w
User-Agent: HTTPie/0.9.9

Вот минимальная конфигурация nginx для этого теста:

events {
    worker_connections                 5000;
    multi_accept                       on;
    use                                epoll;
}

http {
    log_format                          timed_combined '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time';

    access_log                           /var/log/nginx/access.log timed_combined;
    error_log                            /var/log/nginx/error.log warn;

    resolver                             1.1.1.1 8.8.8.8 8.8.4.4 valid=60s;
    resolver_timeout                     15s;

    index                                index.html;

    upstream front-wp {
        server x.y.z.w:80;
    }

    server {
        listen 80;

        location /wp-content/ {
            proxy_pass http://front-wp;
            proxy_http_version 1.1;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location = /test-page/ {
            proxy_pass http://front-wp;
            proxy_http_version 1.1;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

Эта проблема действительно сводит меня с ума.

Вероятно, что сервер на x.y.z.w использует виртуальный хостинг на основе имен, и два запроса обрабатываются разными виртуальными хостами.

URL http://x.y.z.w/test-page/ устанавливает значение заголовка Host равным x.y.z.w который используется для выбора одного из виртуальных хостов.

Запрос через обратный прокси устанавливает значение заголовка Host равным $host который используется для выбора другого виртуального хоста (возможно, хоста по умолчанию, если значение Host неизвестно).

Чтобы подтвердить это, попробуйте:

proxy_set_header Host "x.y.z.w";

что должно сделать два запроса достаточно похожими, чтобы их мог обрабатывать один и тот же виртуальный хост.

Вам нужно будет посмотреть конфигурацию сервера на x.y.z.w если требуется другое поведение.