Пользователь
0,0
рейтинг
13 ноября 2012 в 22:10

Администрирование → Проксируем и спасаем tutorial

1 ноября мир изменился и больше никогда не будет таким же как прежде. В российском интернете появилась цензура — общеизвестный уже список запрещенных сайтов. Для одних это важнейшая политическая тема, для других повод изучить технологии шифрования и защиты анонимности, для третьих просто очередной странный закон, который приходится исполнять на бегу. Мы же поговорим о технологическом аспекте.

В данном пособии мы узнаем как быстро и просто сделать рабочее зеркало любого сайта, что позволяет сменить IP и назначить любое доменное имя. Мы даже попробуем спрятать домен в url, после чего можно сохранить локально полную копию сайта. Все упражнения можно сделать на любом виртуальном сервере — лично я использую хостинг Хетцнер и OS Debian. И конечно мы будем использовать лучший веб-сервер всех времен и народов — NGINX!

К этому абзацу пытливый читатель уже приобрел и настроил какой нибудь выделенный сервер или просто запустил Linux на старом компьютере под столом, а так же запустил Nginx последней версии со страничкой «Save me now».


Перед началом работы необходимо скомпилировать nginx c модулем ngx_http_substitutions_filter_module, прежнее название — substitutions4nginx.

Дальнейшая конфигурация будет показана на примере сайта www.6pm.com. Это сайт популярного онлайн магазина, торгующего товарами с хорошими скидками. Он отличается категорическим нежеланием давать доступ покупателям из России. Ну чем не оскал цензуры капитализма?

У нас уже есть работающий Nginx, который занимается полезными делом — крутит сайт на системе Livestreet о преимуществах зарубежного шоппинга. Чтобы поднять зеркало 6pm прописываем DNS запись с именем 6pm.pokupki-usa.ru который адресует на IP сервера. Как вы понимаете, выбор имени для суб-домена совершенно произволен. Это имя будет устанавливаться в поле HOST при каждом обращении к нашему новому ресурсу, благодаря чему на Nginx можно будет запустить виртуальный хостинг.

В корневой секции конфигурации nginx прописываем upstream — имя сайта-донора, так будем его называть в дальнейшем. В стандартных гайдах сайт обычно называется back-end, а reverse-proxy называется front-end.

http {
    ...
    upstream 6pm { server www.6pm.com; }


Дальше нужно создать секцию server, вот как она выглядит

    server {
        listen          80;
        server_name     6pm.pokupki-usa.ru;
        limit_conn  gulag 64;

        access_log   /var/log/nginx/6pm.access.log;
        error_log    /var/log/nginx/6pm.error.log;

        location / {
            root /var/www/6pm;
            try_files $uri @static;
        }
        location @static {

            include '6pm.conf';
            proxy_cookie_domain 6pm.com 6pm.pokupki-usa.ru;

            proxy_set_header Accept-Encoding "";
            proxy_set_header      Host     www.6pm.com;
            proxy_pass http://6pm;

            proxy_redirect http://www.6pm.com http://6pm.pokupki-usa.ru;
            proxy_redirect https://secure-www.6pm.com https://6pm.pokupki-usa.ru;
        }
    }



Стандартные директивы listen и server определяют имя виртуального хоста, при обращении к которому будет срабатывать секция server. Файлы логов лучше сделать отдельными.

Объявляем корневой локейшин, указываем путь до его хранилища — root /var/www/6pm; затем используем try_files. Это очень важная директива nginx, которая позволяет организовать локальное хранилище для загруженных файлов. Директива сначала проверяет нет ли файла с именем $uri и если не находит его — переходит в именованный локейшин @ static
$uri — переменная nginx, которая содержит путь из HTTP запроса

Префикс “@” задаёт именованный location. Такой location не используется при обычной обработке запросов, а предназначен только для перенаправления в него запросов. Такие location’ы не могут быть вложенными и не могут содержать вложенные location’ы


В нашем случае конструкция используется только для подмены файла robots.txt, чтобы запретить индексацию содержимого сайта. Однако таким образом делается зеркалирование и кеширование в nginx.

include '6pm.conf' — логика модуля substitutions.

proxy_cookie_domain — новая функция, которая появилась в nginx версии 1.1.15, без этой директивы приходилось делать так. Больше не нужно ломать голову, прописываете одну строчку и куки просто начинают работать.

proxy_set_header Accept-Encoding ""; — очень важная команда, которая заставляет сайт донор отдавать вам контент не в сжатом виде, иначе модуль substitutions не сможет выполнить замены.

proxy_set_header Host — еще одна важная команда, которая в запросе к сайту донору выставляет правильное поле HOST. Без нее будет подставляться имя нашего прокси сервера и запрос будет ошибочным.
proxy_pass — прямая адресация не работает в именованном локейшине, именно поэтому мы прописали адрес сайта донора в директиве upstream.
proxy_redirect — многие сайты используют редиректы для своих нужд, каждый редирект нужно отловить и перехватить здесь, иначе запрос и клиент уйдет за пределы нашего уютного доменчика.

Теперь посмотрим содержимое 6pm.conf. Я не случайно вынес логику трансформации в отдельный файл. В нем можно разместить без какой либо потери производительности тысячи правил замены и сотни килобайт фильтров. В нашем случае мы хотим лишь завершить процесс проксирования, поэтому файл содержит всего 5 строк:

Меняем коды google analytics:
subs_filter 'UA-8814898-13' 'UA-28370154-3' gi;
subs_filter "'.6pm.com']," "'6pm.pokupki-usa.ru']," gi; 

Уверяю, что это самая безобидная шалость из возможных. У нас появится статистика посещений, а у сайта донора эти визиты — исчезнут.

Меняем все прямые ссылки на новые.
subs_filter "www.6pm.com" "6pm.pokupki-usa.ru" gi;
subs_filter "6pm.com" "6pm.pokupki-usa.ru" gi;


Как правило, в нормальных сайтах все картинки лежат на CDN сетях, которые не утруждают себя проверкой источника запросов, поэтому достаточно замены ссылок только основного домена. В нашем случае 6pm выпендрился и разместил часть картинок на доменах, которые отказывают посетителям из России. К счастью, модуль замены поддерживает регулярные выражения и не составляет никакого труда написать общее правило для группы ссылок. В нашем случае обошлось даже без regexp, просто поменяли два символа в домене. Получилось так:

subs_filter "http://a..zassets.com" "http://l3.zassets.com" gi;


Единственное, но очень серьезное ограничение модуля замены — он работает только с одной строкой. Это ограничение заложено архитектурно, поскольку модуль работает на этапе, когда страница загружена частично (chunked transfer encoding) и нет никакой возможности выполнить полнотекстовый regexp.

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

Итак, мы перекинули сайт на новый IP адрес и новый домен. Это было простой задачей. Можно ли запроксировать сайт не в новый домен, а в поддиректорию существующего? Это сделать можно, но возникают сложности. Для начала вспомним какие бывают html ссылки:
  1. Абсолютные ссылки вида «www.example.com/some/path»
  2. Ссылки относительно корня сайта вида "/some/path"
  3. Относительные ссылки вида «some/path»


С п.1 все просто — мы заменяем все ссылки на новый путь с поддиректорией
С п.3 так же просто — мы ничего не трогаем и все работает само если не использовался атрибут base href. Если этот атрибут используется, что бывает крайне редко в современных сайтах, то достаточно его заменить и все будет работать.

Настоящая сложность возникает с п.2. из-за того что мы должны изменить кучу ссылок вида /... на /subdomain/.... Если сделать это в лоб, то сайт скорее всего полностью перестанет работать, ибо такая замена сломает множество конструкций использующих слеш, что испортит почти все скрипты javascript.

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

Вернемся к нашему пациенту:

        location /6pm {
            root /var/www/6pm;
            try_files $uri @6pm-static;
            access_log   /var/log/nginx/6pm.access.log;
        }
        location @6pm-static {
            include '6pm2.conf';
            proxy_cookie_domain 6pm.com pokupki-usa.ru;
            proxy_cookie_path / /6pm/;

            rewrite ^/6pm/(.*) /$1 break;

            proxy_set_header Accept-Encoding "";
            proxy_set_header      Host     www.6pm.com;
            proxy_pass http://6pm;

            proxy_redirect http://www.6pm.com http://pokupki-usa.ru/6pm;
            proxy_redirect http://www.6pm.com/login http://pokupki-usa.ru/6pm;
            proxy_redirect https://secure-www.6pm.com https://pokupki-usa.ru/6pm;


Конфигурация сервера претерпела некоторые изменения.

Во-первых, вся логика перенесена из директивы sever напрямую в location. Нетрудно догадаться, что мы решили создать директорию /6pm в которую будем выводить проксируемый сайт.

proxy_cookie_path / /6pm/ — переносим куки из корня сайта в поддиректорию. Это делать не обязательно, но в случае если проксируемых сайтов окажется много, их куки могут пересечься и затереть друг друга.

rewrite ^/6pm/(.*) /$1 break; — эта магия вырезает из клиентского запроса поддиректорию, которую мы добавили, в результате директива proxy_pass отправляет на сервер-донор корректное значение.

Чуть сложнее стало ловить редиректы. Теперь все ссылки на корень нужно перебросить на /6pm.

Посмотрим на логику трансформации:

subs_filter_types text/css text/javascript;

# Fix direct links
subs_filter "http://6pm.com" "http://pokupki-usa.ru/6pm" gi;
subs_filter "http://www.6pm.com" "http://pokupki-usa.ru/6pm" gi;

# Fix absolute links
subs_filter 'src="/' 'src="/6pm/' gi;
subs_filter 'href="/' 'href="/6pm/' gi;
subs_filter 'action="/' 'href="/6pm/' gi;

# Fix some js
subs_filter "\"/le.cgi" "\"/6pm/le.cgi" gi;
subs_filter "\"/track.cgi" "\"/6pm/track.cgi" gi;
subs_filter "\"/onload.cgi" "\"/6pm/onload.cgi" gi;
subs_filter "\"/karakoram" "\"/6pm/karakoram" gi;
subs_filter "/tealeaf/tealeaf.cgi" "/6pm/tealeaf/tealeaf.cgi" gi;

# Css and js path
subs_filter "script\('/" "script('/6pm/" gi;
subs_filter "url\(/" "url(/6pm/" gi;

subs_filter 'UA-8814898-13' 'UA-28370154-3' gi;
subs_filter "'.6pm.com']," "'pokupki-usa.ru/6pm']," gi;

subs_filter "http://a..zassets.com" "http://l3.zassets.com" gi;


Во-первых, мы включили фильтрацию файлов css и javascript (парсинг html включен по-умолчанию)
Во-вторых, начинаем аккуратно находить и заменять разные типы ссылок относительно корня. Нам попался средней сложности сайт, в котором часть скриптов содержат такие пути.

В итоге получилось так: http://pokupki-usa.ru/6pm/

К сожалению, мне не удалось до конца написать фильтр для случая поддиректории. Я не дошел до преобразования динамических запросов скриптов корзины с покупками, хотя не сомневаюсь что это решаемо. Просто моих знаний в Javascript не достаточно чтобы выполнить необходимую отладку, буду рад советам как запустить корзину покупок, которая сейчас в упомянутом примере не работает.

В любом случае, это, возможно, первый гайд, в котором описан метод проксирования в поддиректорию.
@Begetan
карма
173,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

Комментарии (25)

  • +5
    Месяц Большого Брата и борьбы за свободу в интернете объявляется открытой!
    • +3
      Астрологи объявили месяц Большого Брата — прирост зеркал сайтов увеличился.
      • +1
        Месяц? Какие вы все оптимисты…
        • +2
          Вы что не играли в Heroes of Might & Magic III?
          • 0
            это наверное ньюфаг просто :)
          • 0
            Именно III? :)
            • 0
              Раньше и позже не играл толком. Очень много времени оставил именно в III.
              Если был не прав, то поправьте.
          • 0
            Играл и в первый, и во второй, и в Kings Bounty, и вашу аналогию прекрасно понял, моё высказывание, как можно понять, если немного задуматься, относится уже к оригинальной теме (про Большого Брата).
  • +5
    Зачетный способ… если маховик будет и дальше раскручиваться, то не за горами и специализированное ПО (чтобы все автоматически, не вдаваясь в детали). Кстати, в свете последних событий вспомнились программки типа: Teleport Pro, HTTrack Website Copier и прочие, еще с модемной эпохи. Сдается мне, что в РФ они будут скоро вновь актуальны.
    • +4
      то не за горами и специализированное ПО (чтобы все автоматически, не вдаваясь в детали)
      

      — вы уже подтолкнули на реализацию этой идеи — ждем релизов ) представляю эдакий бандл: ProxySaver v1.0 (Powered by Hetzner) по цене от 6 евро :-) Даешь SaaS? :-)

      отличная статья
      полезные приемы настройки nginx, да и тематика, что называется, «на злобу дня»
  • –2
    И еще: не поймите меня не правильно, но сейчас будут срать кирпичами возмущаться по поводу рекламы хостинга Хетцнер и магазина 6pm.
  • +5
    Пиринговые сети имеют следующую особенность: чем больше пользователей online, тем быстрее она работает. Судя по всему, Tor скоро летать будет.

    * намек на то, что зеркала в торе нужно делать.
  • +2
    На просто банить все ip адреса принадлежащих гос.органам.Они не смогут просто попасть в наш интернет.
    • 0
      Главное что бы они не обиделись за это и не за банили ваш ip.
      • 0
        Как они забанят? Если не увидят что там находиться?
        • 0
          Вы сомневаетесь в их способностях?
          Если захотят то найдут способ и зайти и к чему придраться…
    • 0
      А у Вас списочек есть?
      • –1
        Ну наверное это ip гос. провайдеров
    • 0
      Это кстати, не такая уж глупая идея. В том же Nginx есть модуль geoip и вообще достаточно просто подключить внешнюю базу данных чтобы фильтровать нежелательные запросы.

      Эту, внешнюю БД можно формировать краудсорсингом заинтересованных лиц.
  • 0
    Ну что вы за человек, только хотел сделать на этом бизнес, а вы всем рассказали :)
    • 0
      А как одно другому мешает?
      • 0
        Нет, не мешает. Но сейчас все будут знать, как это можно сделать.
        И я больше с иронией говорил.
        • 0
          > И я больше с иронией говорил.
          Я тоже.
  • 0
    Гайд не первый habrahabr.ru/post/114845/.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.