Debian.pro

Блог для пользователей и администраторов Debian


Nginx custom header/footer. Отладка сайтов на лету. Переменные nginx прямо на странице.

Вообще у меня забавная жизнь. Когда я что-то узнаю — в течении недели, максимум месяца мне это обязательно пригодится.
Так и в этот раз. Сидел я на праздниках в белфасте. Ну а по морде моей сразу видно кем я работаю. В общем завязался у нас разговор с неким странным человеком. Он говорил, что apache никогда не умрет. Ну и слышу я такую тираду: «nginx не умеет htaccess (хрен бы с ним), nginx не умеет CGI (чувак, я устал, я не хочу рассказывать как из cgi сделать fastcgi), nginx не умеет <тут что-то ещё, о чем мне было в лень растолковывать>, nginx не умеет кастомные хедеры для страницы автоиндекса!». Вот тут мне пришлось сказать ему «такстопблиа. вполне себе умеет. Аж двумя способами».

Первый способ FancyIndex. Я с ним поковырялся. Он у меня собрался с текущей стабильной версией nginx’a:
./configure --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-debug --with-http_addition_module --with-http_geoip_module --with-http_gzip_static_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --add-module=ngx-fancyindex
(сам модуль лежал в каталоге ./ngx-fancyindex)
Эта штука неимоверна крута. Она умеет прикручивать даже css к автоиндексу. Вот только есть с ней большая проблема. Пострелял siege’м — родной автоиндекс без затыков держит около 200rps (без затыков — это время всех ответов в пределах 50 мс). А убить я его так и не смог — памяти не хватило на запуски siege. FancyIndex же после 30rps уходил в совсем уж торможение — странички генерировались по 2-3 секунды. За 50 мс он вышел на 10rps, кажется. В общем, на 2хE5440 это совсем плохо. Не бог весть какие процессоры, но и так тормозить не должен (черт, даже WP быстрее бегал =) ). Надеюсь, этот модуль допилят и он лишится детских болячек.

Ну а на самом деле в nginx есть отличная вещь — модуль http-echo. Он умеет выводить почти любой текст на странице перед контентом и после контента средствами самого nginx. Можно рисовать простенький html. Да, чтобы получилось красиво — нужно постараться, но тем не менее =)

Собственно, начнем. Эксперементировать будем прямо с location / (то есть будем выводить на все страницы).

Выведем в футере и хедере простой текст:
...
location / {

echo_before_body i am nginx!;

autoindex on;
root /var/www;

echo_after_body i am cool!;

}
...

В данном случае у нас есть автоиндекс каталога /var/www и всех его подстраниц. Перед страницей автоиндекса нам напишут «i am nginx!», после — «i am cool!».
Можно спокойно использовать html теги. То есть можно использовать всё, что интерпретируется браузером как html код. Джастфофан я втыкал тег <video> — оно работало =)

В общем усложним задачу. Напишем болдом, по центру, да ещё и добавим строку с <H1>:
...
location / {

echo_before_body "

<H1>Hello</H1>
<b><center>i am nginx!</center></b>

";

autoindex on;
root /var/www;

echo_after_body"

<b><center>I am cool!</center></b>

";

}
...

Зачем кавычки. Просто так удобнее. Если вы нечаянно напишете туда ;, то конфиг не поломается =)
То есть синтаксис выглядит так:
echo_before_body text;
или так:
echo_before_body «text»;

Кавычку внутри text нужно экранировать — \"

Вооот. А теперь сделаем адский хардкор. Сходим на http://mirror.yandex.ru и попробуем воспроизвести тоже самое =) Ну примерно. Совсем так же у меня не получилось, к сожалению. Нагло копипастим с морды миррора код и поехали:
...

echo_before_body "

<head>
<style type=\"text/css\">
a, a:active {text-decoration: none; color: blue;}
a:visited {color: #48468F;}
a:hover, a:focus {text-decoration: underline; color: red;}
body {background-color: #F5F5F5;}
h2 {margin-bottom: 12px;}
table {margin-left: 12px;}
th, td { font: 90% monospace; text-align: left;}
th { font-weight: bold; padding-right: 14px; padding-bottom: 3px;}
td {padding-right: 14px;}
td.s, th.s {text-align: right;}
div.list { background-color: white; border-top: 1px solid #646464; border-bottom: 1px solid #646464; padding-top: 10px; padding-bottom: 14px;}
div.foot { font: 90% monospace; color: #787878; padding-top: 4px;}
</style>
</head>
<body>
<pre class=\"header\">Welcome to Yandex Linux mirror (allotter.yandex.net), hosted at Yandex, Russian Federation. Contacts: opensource@yandex-team.ru Intel(R) Xeon(R) CPU E5345 x 8, Mem. 16G, Disks 23T, Bandwidth 1 Gbps. We support http, ftp and rsync protocols. </pre>

";

...

Ну ок, получился говнокод (говно-html-код? лолвут?), но тем не менее оно работает =) Можно юзать div’ы. Можно подключать CSS с диска (только будьте осторожны, оно все же какие-никакие, но ресурсы кушает). Короче, развлекайтесь =)

Вот. Ну и напоследок вкусняшка. Согласитесь, иногда возникает необходимость смотреть, какие значения принимают переменные. Некоторые выводят их в лог. А если это нужно разработчику, а доступ к логам ему давать не хочется (ну ладно, можно дать доступ по http, но тот ещё геморрой). А что мешает нам их выводить прямо на странице) ? Да ничего =)) Делаем это так:
...

echo_before_body "

$http_host <br>$remote_addr <br> $request<br>$http_referer<br>$var10<br>var30<br>

";

...

Конечно же, не в продакшне =) Ну и пусть разработчик таращится сам в свои переменные. А вы дальше играйте в $game_name.

Есть директива echo_sleep. Я не понял на кой черт она нужна. У меня при её использовании получается очень странная штука — при запросе на соответствующую страницу запрос висит n секунд, после чего скачивается текстовый файл в котором вместо контента страницы надпись (none). Ну и добавляется то, что написано в echo =)

Вообще там адский ад в этом модуле. Он большой и страшный )
Но по теме поста я написал всё.


Комментарии (6):

  1. Читал в RSS, подумал, откуда бы на хабре взяться такой клевой статье, открываю полную версию, чтобы добавить в избранное — а тут твой сайт:)
    Думаю, можно делать более красивые вещи, используя переменные (хотя, конечно html код в льбом месте конфига уже не очень красиво — лучше уж читать какой-нибудь header.html и footer.html).

  2. Вот тут как раз сказывается особенности nginx’a — он не умеет динамически искать файлы в каталогах. Именно поэтому нет и никогда не будет поддержки htaccess.
    Искать header и footer — накладно по ресурсам. К тому же не стоит забывать, что данный способ работает для любой страницы (а не только для автоиндексов).

    Насчет некрасиво — я складываю все эти штуки в отдельные файлики, а в конфиги сайта просто делаю include.

  3. Alex Gludo :

    Привет!
    Спасибо за статью — очень пригодилась.
    Но у меня вопрос — как сделать, чтобы echo_before_body и echo_after_body работали только для корня сайта?
    Крутил вертел location-ы, но так ничего и не вышло — все равно и в подкаталогах отображается и в файлы (robots.txt например) инклюидтся текст из echo_*.

  4. location = / {}
    location / {}
    разные вещи — читайте документацию.

  5. Alex Gludo :

    Спасибо! Нужный результат достигнут.
    location = / {} как то вообще из виду упустил. Невнимательность..))

  6. Та не за чт.

Написать комментарий