Pull to refresh

Трансформация и перевод на другие языки web-сайтов на лету при помощи Nginx

Reading time 5 min
Views 9.4K




В моем первом посте я описал применение 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, парсер ломается на коде:
://
Оставлю блок без подсветки, чтобы не вносить лишних ошибок в конфиг.
Tags:
Hubs:
+48
Comments 9
Comments Comments 9

Articles