
В моем первом посте я описал применение Apache Traffic Server в качестве кеширующего reverse-proxy. В отзывах меня спрашивали почему не nginx? Поскольку в ATS все равно не нашлось удобного способа трансформировать контент сайта, то я решил изучить возможности Nginx. Для решения задачи пришлось углубится в дебри документации, и вот что получилось…
Как и в прошлый раз мы будем трансформировать сайт example.com в example.ru. Не буду рассказывать о настройке и установке Nginx (об этом много статей), а лучше расскажу о конкретных полезных настройках.
Глобальная конфигурация — nginx.conf
worker_processes 4;
# Поставьте тут столько процессов, сколько у в системе ядер
# cat /proc/cpuinfo | grep processor | wc - даст ответ
http {
resolver 127.0.0.1;
# Это очень важная строчка. Без нее никак не удавалось запустить работу reverse proxy. Вместо 127.0.0.1 напишите адрес DNS сервера вашего провайдера. Беда в том, что эта настройка ставится глобально, а все примеры по настройке в мануалах и статьях приводятся для локейшинов. Ошибку отлавливаем по слову resolver в логах. Настройте DNS сразу и потратьте спасенное время на полезные дела!
include options.conf;
include mime.types;
# Мы переводим сайт на английском языке, у которого, по-умолчанию, кодировка iso-8859-1. Писать будем по-русски и, чтобы не страдать перекодировками, выберем UTF-8.
charset utf-8;
override_charset on;
source_charset iso-8859-1;
charset_map iso-8859-1 utf-8 { }
# Команда charset_map - волшебная, без нее ничего не заработает! Предложенный в документации вариант charset_map iso-8859-1 _ { } у меня не заработал.
# Настраиваем проксирование всех запросов. Зачем? А чтоб было в хозяйстве!
proxy_cache_path /usr/local/nginx/proxy_temp/ levels=1:2 keys_zone=cache-zone:10m inactive=10m max_size=1000M;
# Настраиваем сохранение сайта
proxy_store_access user:rw group:rw all:r;
# Разница между proxy_caсhe и proxy_store в том что первое создает оптимизированный служебный кэш, а второе создает точную локальную копию удаленного сайта. Такая копия станет незаменимой вещью в процессе дальнейшего ручного перевода сайта.
# Опускаем остальные конфигурационные команды и …
include example.conf;
}
Настройка виртуального сервера — example.conf
server {
listen 80;
server_name example.ru;
access_log logs/example.ru.access.log main;
error_log logs/example.ru.error.log;
index index.html;
root /usr/local/nginx/html/example.ru;
# Ничего необычного за исключением:
rewrite ^/(/broken_page.*) http://www.example.com/$1 permanent;
# Это полезное правило позволяет “починить” линки, которые были сломаны проксификатором Nginx работающим в режиме reverse-proxy. Мы теряем возможность перевода сломанных страниц, так как отсылаем пользователя на оригинальный сайт, но зато освобождаемся от ошибки 404. Так лучше. В моих тестах Nginx ломал Pop-up окно с роликом на флеше.
# Переходим к самому интересному!
# Создаем локейшин /img/ Название локейшина должно совпадать с URI хранилища картинок оригинального сайта. Пояснения ниже.
location ^~ /img/ {
# Где же локальное хранилище? Ах вот где, прямо у нас под боком!
root /usr/local/nginx/html/example.ru;
# Пишем волшебство!
try_files $uri $uri/ @static;
}
# Смысл этой замечательно команды в том, что при запросе пользователя она проверяет есть ли в локальной копии сайта файл с указанными именем и если есть, то отдает файл, а если нет, то передает работу в @static, в котором живет прокси сервер. Таким элегантным способом мы можем накапливать картинки (страницы) с оригинального сайта, и, если нужно, по одной штуке переводить их на русский язык в редакторе. Весь процесс не создает ошибок, абсолютно прозрачен для пользователя и максимально удобен для переводчика-дизайнера.
# Доделаем нашу статику:
location @static {
proxy_pass http://super-cdn.com$uri;
# Стоит заметить что в годно сделанном сайте, есть 1-2 отдельных домена хранящие статические файлы. В нашем случае полный путь к ним оказался таким: http://super-cdn.com/img
proxy_store /usr/local/nginx/html/${uri};
expires max;
# expires max - Это чрезвычайно важная команда, которая превращает обычный кэш в постоянно хранилище файлов. Однажды попав картинка остается в хранилище пока вы не удалите ее руками или не перезапишите ее русифицированной версией. Как только картинка перезаписывается, она мгновенно выдается всем новым запросам. Все кэши ( на сервере, у юзера) во всех местах обновляются как надо если перезапустить nginx -s reload. За этой завораживающей процедурой можно наблюдать прямо в консоли firebug после рефреша страницы в браузере. Это действительно уникальная возможность Nginx.
# Отдельный лог не повредит при отладке!
access_log logs/2.access.log;
error_log logs/2.error.log debug;
}
# Теперь опишем корневую директорию нашего сервера.
location / {
include example-transform.conf;
# Включаем реверс прокси
proxy_pass http://www.example.com;
# Всякоразные настройки
proxy_redirect off;
proxy_cache cache-zone; # Не забыли про описание пула в самом начале?
proxy_cache_min_uses 2;
proxy_cache_valid 200 1h;
# Если хотим чтобы владелец оригинального ресурса мог видеть наши посещения добавляем:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Мы помним, что картинки оригинального сайта находятся по адресу:
http://super-cdn.com/img
Однако запустив вышеописанную конфигурацию мы видим, что Nginx оставил все ссылки вида
=http://super-cdn.com/img/*не проксифицированными. Понятно, что это из-за отличия домена. Так же понятно, что в такой ситуации никакой возможности подсунуть переведенные картинки у нас нет, потому как пользователь забирает их напрямую с CDN минуя нас. Значит требуется магия трансформации!
Открываем example-transform.conf
sub_filter 'http://super-cdn.com/img/’ 'http://example.ru/img/' ;
sub_filter_once off;
По умолчанию модуль трансформации не откомпилирован! Нужен параметр:
./configure --with-http_sub_module
Компилируем, перзапускаем… Бинго!!! Фанфары!!!
Все работает, все летает, картинки можно подменять на ходу.
Мы радостно добавляем первое правило замены содержимого страницы и … узнаем шокирующую информацию о том, что модуль http_sub_module позволяет выполнить всего одну замену!
О Игорь Сысоев, почему ты скрыл этот чудовищный факт в страничке документации!
sysoev.ru/nginx/docs/http/ngx_http_sub_module.html
Ах если бы мы знали про такой финал в самом начале! Но… Стоп! Эмоции в сторону, потому что русские и китайцы — братья навек! Простой китайский паренек Weibin Yao уже решил нашу проблему и создал модуль substitutions4nginx, который доступен по адресу
code.google.com/p/substitutions4nginx
Устанавливаем модуль по инструкции, открываем наш конфигурацию трансформации и смело пишем:
subs_filter 'http://super-cdn.com/img/’ 'http://example.ru/img/' g;
subs_filter '<title[^>]*>(.*?)</title>' '<title>НЛО прилетело сюда и подчинило этот сайт своей воле. Аминь!</title>' oir;
Вместо послесловия
1. Конфиг писался из рабочего, но по понятным причинам не проверялся вживую. Если возникнут сложности постараюсь помочь.
2. Nginx работает в нестандартном малоисследованном режиме. Появляется вот такой баг.
3. Модуль substitutions4nginx не обкатан, один баг нашелся сразу и был быстро исправлен. Видимо нужна толпа тестеров.
4. В Apache Traffic Server и в Nginx я нашел одинаковый баг. При котором теги с линками типа a href содержащие перенос строки не прокисифцируются. Подозреваю что проблема тянется из библиотеки PCRE.
З.Ы. Кто подскажет почему во втором блоке не работает подсветка source lang=«bash», тому плюшку!
З.З.Ы. Проблему с подсветкой определил yeah, парсер ломается на коде:
://Оставлю блок без подсветки, чтобы не вносить лишних ошибок в конфиг.