Подкаталог обратного прокси-сервера Nginx переписывает для sourcegraph

Я пытаюсь, чтобы сервер исходного графа обслуживался в подкаталоге моего домена с использованием обратного прокси-сервера для добавления сертификата SSL.

Цель состоит в том, чтобы http://example.org/source обслуживал сервер sourcegraph.

Мои переписанные и обратные прокси выглядят так:

  location /source {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Scheme $scheme;

    rewrite ^/source/?(.*) /$1 break;
    proxy_pass http://localhost:8108;
  }

У меня проблема в том, что после вызова http://example.org/source меня перенаправляют на http://example.org/sign-in?returnTo=%2F

Есть ли способ переписать ответ sourcegraph в правильный подкаталог?

Кроме того, где я могу отладить директиву rewrite? Я хотел бы следить за изменениями, которые он делает, чтобы понять это лучше.

-- Редактировать:

Я знаю, что мой подход, вероятно, неправильно с использованием перезаписи, и я пытаюсь модуль sub_filter прямо сейчас.

Я захватил ответ sourcegraph с помощью tcpdump и проанализировал с помощью wireshark, поэтому я нахожусь на:

GET /sourcegraph/ HTTP/1.0
Host: 127.0.0.1:8108
Connection: close
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://example.org/
Accept-Encoding: gzip, deflate, br
Accept-Language: de,en-US;q=0.9,en;q=0.8
Cookie: sidebar_collapsed=false; 

HTTP/1.0 302 Found
Cache-Control: no-cache, max-age=0
Content-Type: text/html; charset=utf-8
Location: /sign-in?returnTo=%2Fsourcegraph%2F
Strict-Transport-Security: max-age=31536000
Vary: Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Trace: #tracer-not-enabled
X-Xss-Protection: 1; mode=block
Date: Sat, 07 Jul 2018 13:59:06 GMT
Content-Length: 58

<a href="/sign-in?returnTo=%2Fsourcegraph%2F">Found</a>.

1 ответ

Использование перезаписи здесь приводит к дополнительным издержкам обработки и совершенно не требуется.

proxy_pass работает так:

proxy_pass к голому URL, т.е. вообще ничего после домена /ip/ порта и полного клиентского запроса uri добавляется в конец и передается прокси.

Добавьте что угодно, даже косую черту proxy_pass и все, что вы добавляете, заменяет ту часть URI запроса клиента, которая соответствует URI этого блока местоположения.

так что если вы хотите потерять исходную часть вашего клиентского запроса, она должна выглядеть так:

location /source/ {
    proxy_pass http://localhost:8108/;
    .....
}

Теперь запросы будут проксироваться так:

example.com/source/ -> localhost:8108/

example.com/source/files/file.txt -> localhost:8108/files/file.txt

Важно отметить, что Nginx не просто /source/ из запроса, он заменяет весь мой proxy_pass Ури, это не так ясно, когда это просто косая черта, поэтому лучше проиллюстрировать, если мы изменим proxy_pass к этому:

proxy_pass http://localhost:8108/graph/; тогда запросы теперь обрабатываются так:

example.com/source/ -> localhost:8108/graph/

example.com/source/files/file.txt -> localhost:8108/graph/files/file.txt

Если вам интересно, что haooens, если кто-то просит example.com/source это работает, если вы не установили merge_slashes директива off, так как Nginx добавит завершающие / к прокси-запросам.

Если у вас есть Nginx перед другим веб-сервером, работающим на порту 8108, и обслуживающий его контент proxy_pass всего из подкаталога, например /subdir, тогда у вас может возникнуть проблема, связанная с тем, что служба на порту 8108 обслуживает HTML-страницу, которая включает ресурсы, вызывает собственные API-интерфейсы и т. д. на основе абсолютных URL-адресов. Эти вызовы будут опускать/subdir префикс, поэтому они не будут перенаправлены на службу на порт 8108 с помощью nginx.

Одно из решений - заставить веб-сервер на порту 8108 обслуживать HTML, который включает базовый атрибут href, например

<head>
  <base href="https://example.com/subdir">
</head>

который сообщает клиенту, что все ссылки относятся к этому пути (см. https://www.w3schools.com/tags/att_base_href.asp)

Иногда это не вариант - возможно, вы просто запускаете веб-сервер, предоставляемый внешним образом докера, или, может быть, вы просто не видите причину, по которой вам нужно вмешиваться в службу, которая отлично работает как автономная. Решение, которое требует изменений только в nginx впереди, - это использоватьReferer заголовок, чтобы определить, был ли запрос инициирован ресурсом, расположенным в /subdir. Если это так, вы можете переписать запрос с префиксом/subdir а затем перенаправить клиента в это место:

location / {
    if ($http_referer = "https://example.com/subdir/") {
        rewrite ^/(.*) https://example.com/subdir/$1 redirect;
    }

    ...
}

location /subdir/ {
    proxy_pass http://localhost:8108/;
}

Или что-то вроде этого, если вы предпочитаете регулярное выражение, позволяющее опускать имя хоста:

if ($http_referer ~ "^https?://[^/]+/subdir/") {
    rewrite ^/(.*) https://$http_host/subdir/$1 redirect;
}
Другие вопросы по тегам