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

Как заставить существующий кэширующий прокси Nginx использовать другой прокси для обхода брандмауэра?

У меня вопрос об использовании Nginx в качестве прокси за другим прокси. (Немного сбивает с толку.)

Я хочу настроить Nginx, чтобы он действовал как кеширующий прокси-сервер для зеркала npm. Вот ссылка: http://eng.yammer.com/a-private-npm-cache/

На моем локальном компьютере, который не ограничен брандмауэром, нормально работает следующая конфигурация:

proxy_cache_path /var/cache/npm/data levels=1:2 keys_zone=npm:20m max_size=1000m
inactive=365d;
proxy_temp_path /var/cache/npm/tmp;

server {
   listen 80;
   server_name classen.abc.lan;
   location / {
      proxy_pass http://registry.npmjs.org/;
      proxy_cache npm;
      proxy_cache_valid 200 302 365d;
      proxy_cache_valid 404 1m;
      sub_filter 'registry.npmjs.org' 'classen.abc.lan';
      sub_filter_once off;
      sub_filter_types application/json;
   }
}

Теперь я хочу применить его к серверу, который находится за дополнительным брандмауэром. В журналах я могу подтвердить, что он получает доступ к правильному IP-адресу восходящего потока, но запрос не выполняется из-за внутреннего брандмауэра.

У нас есть один внутренний прокси, который я могу использовать для обхода межсетевого экрана, например:

$ curl http://registry.npmjs.org
curl: (7) couldn't connect to host
$ http_proxy=http://proxy.abc.lan:1234/ curl http://registry.npmjs.org
... succeeds ...

Этот трюк не работает с Nginx, поскольку он игнорирует http_proxy переменная окружения. Прочитав документацию, я все еще не мог понять, как изменить конфигурацию, чтобы он мог использовать прокси внутри.

Можно ли совместить оба решения? Важно, чтобы кеширование по-прежнему работало, в противном случае вы можете просто использовать внешнее зеркало registry.npmjs.org напрямую.

Возможно, Nginx должен использовать внутренний прокси (proxy.abc.lan) как proxy_pass, но тогда как внутренний прокси узнает, что запрос должен быть отправлен на внешнее зеркало npm (http://registry.npmjs.org)?

Обновление ответа Лукаса

Я попробовал решение Лукаса:

rewrite ^(.*)$ "http://registry.npmjs.org$1" break;
proxy_pass http://proxy.abc.lan:1234;

Журналы показывают, что URL-адрес перезаписывается, но это приводит к перенаправлению (запускается curl classen.abc.lan/test-url):

2014/03/24 11:31:16 [notice] 13827#0: *2 rewritten redirect: "http://registry.npmjs.org/test-url", client: 172.18.40.33, server: classen.abc.lan, request: "GET /test-url HTTP/1.1", host: "classen.abc.lan"

Результатом вызова curl не является ожидаемая строка JSON от http://registry.npmjs.org но html-страница, созданная Nginx:

$ curl classen.abc.lan/test-url
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.4.7</center>
</body>
</html>

Проблема с решением Лукаса заключается в HttpRewriteModule , который автоматически превращает все, что содержит http (s) в начале, в 302.

Если вместо этого вы выполните переписывание в два этапа - второй «обрыв» - он должен работать. например

rewrite ^(.*)$ "://registry.npmjs.org$1";
rewrite ^(.*)$ "http$1" break;
proxy_pass http://proxy.abc.lan:1234;

Я подозреваю, что есть способ сделать это лучше, но, похоже, он работает.

Я думаю, что это может быть проще, чем любой из приведенных выше примеров. Они используют rewrite, чтобы переписать URL-адрес, я думаю, вы можете использовать proxy_pass, но передать URL-адрес прокси-серверу, установив параметр заголовка хоста в то место, куда вы хотите перейти. например

http {

  upstream corporate_proxy  {
      server web-proxy.mycorp.com:8080;
  }

server {
   listen 80;
   server_name classen.abc.lan;
   location / {
      proxy_pass_header on;
      proxy_set_header Host "registry.npmjs.org";
      proxy_pass http://corporate_proxy;
      proxy_cache npm;
      proxy_cache_valid 200 302 365d;
      proxy_cache_valid 404 1m;
      sub_filter 'registry.npmjs.org' 'classen.abc.lan';
      sub_filter_once off;
      sub_filter_types application/json;
   }
}

RFC 2616, раздел 5.1.2 состояния

Форма absoluteURI НЕОБХОДИМА, когда запрос делается к прокси.
[...]
Пример строки запроса:

  GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1

Итак, что вы должны сделать, это передать запрос прокси с этими измененными директивами:

rewrite ^(.*)$ "http://registry.npmjs.org$1" break;
proxy_pass http://proxy.abc.lan:1234;

В соответствии с документы nginx, с помощью rewrite ... break; заставит nginx использовать переписанный URI (теперь абсолютный URI, как того требует протокол) вместо того, чтобы пытаться построить его из proxy_pass директива.