<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>www.rusinov.ie</title><link>https://www.rusinov.ie/</link><description></description><atom:link href="/ru/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>ru</language><copyright>Contents © 2026 &lt;a href="mailto:vladimir.rusinov@gmail.com"&gt;Vladimir Rusinov&lt;/a&gt; </copyright><lastBuildDate>Fri, 06 Feb 2026 07:19:27 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>7 наиболее распространенных ошибок при установке ограничений памяти Java</title><link>/ru/posts/2010/7-java-heap/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;div dir="ltr" style="text-align: left;"&gt;Оригинал: "&lt;a href="http://javahowto.blogspot.com/2006/06/6-common-errors-in-setting-java-heap.html"&gt;6 Common Errors in Setting Java Heap Size&lt;/a&gt;" (кажется, автор несколько ошибся в подсчетах)&lt;br&gt;Перевод: &lt;a href="http://greenmice.info/ru/node/143"&gt;Владимир Русинов&lt;/a&gt;&lt;br&gt;&lt;br&gt;Для установки размера кучи java (heap) используются две опции: -Xmx для установки максимального размера и -Xms для начального(минимального) размера. Вот наиболее часто встречающиеся ошибки их использования:&lt;br&gt;&lt;br&gt;1. &lt;b&gt;Отсутствие m, M, g или G в конце (регистр не имеет значения).&lt;/b&gt; Например:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx128 BigApp&lt;br&gt;java.lang.OutOfMemoryError: Java heap space&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Правильная команда должна быть такой: &lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx128m BigApp&lt;/pre&gt;. Строго говоря, -Xmx128 корректная настройка для очень маленьких приложений (например HelloWorld), но я думаю в большинстве случаев все-таки имелось в виду -Xmx128m.&lt;br&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;2. &lt;b&gt;Лишний пробел или использование =.&lt;/b&gt; Например:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx 128m BigApp&lt;br&gt;Invalid maximum heap size: -Xmx&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx=512m HelloWorld&lt;br&gt;Invalid maximum heap size: -Xmx=512m&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Правильная команда должна иметь вид &lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx128m BigApp&lt;/pre&gt;, без пробела или знака =. -X опции ведут себя отлично от -Dключ=значение опций, в которых используется =.&lt;br&gt;&lt;br&gt;3. &lt;b&gt;Установка только -Xms в значение большее чем максимальный размер кучи по умолчанию (64m).&lt;/b&gt; Похоже что минимальный размер кучи по умолчанию равен 0.&lt;br&gt;Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xms128m BigApp&lt;br&gt;Error occurred during initialization of VM&lt;br&gt;Incompatible initial and maximum heap sizes specified&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Корректная команда должна выглядеть так: &lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xms128m -Xmx128m BigApp&lt;/pre&gt;. Установить минимальный и максимальный размер равными - хорошая идея. В любом случае, минимальное значение не должно превышать максимальное.&lt;br&gt;&lt;br&gt;4. &lt;b&gt;Установка размера кучи большего чем объем доступной физической памяти.&lt;/b&gt; Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx2g BigApp&lt;br&gt;Error occurred during initialization of VM&lt;br&gt;Could not reserve enough space for object heap&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Устанавливайте размер кучи меньше чем размер физической памяти: &lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx1g BigApp&lt;/pre&gt;&lt;br&gt;5. &lt;b&gt;Использование mb в качестве единицы измерения, вместо m или M.&lt;/b&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xms256mb -Xmx256mb BigApp&lt;br&gt;Invalid initial heap size: -Xms256mb&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;6. &lt;b&gt;Установка размера кучи в большее значение, чем позволяет JVM.&lt;/b&gt; Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx256g BigApp&lt;br&gt;Invalid maximum heap size: -Xmx256g&lt;br&gt;The specified size exceeds the maximum representable size.&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Укажите размер поменьше: &lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx256m BigApp&lt;/pre&gt;&lt;br&gt;7. &lt;b&gt;Указание дробного чиста в качестве значения&lt;/b&gt;. Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx0.9g BigApp&lt;br&gt;Invalid maximum heap size: -Xmx0.9g&lt;br&gt;Could not create the Java virtual machine.&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Правильная команда должна выглядеть так:&lt;br&gt;&lt;pre class="brush: bash"&gt;java -Xmx928m BigApp&lt;/pre&gt;&lt;br&gt;&lt;b&gt;PS:&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи(heap) в Tomcat?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Остановите сервер Tomcat, установите переменную окружения CATALINA_OPTS, затем запустите Tomcat снова. Смотрите файлы tomcat-install/bin/catalina.sh или catalina.bat чтобы узнать как используется эта переменная окружения.&lt;br&gt;&lt;br&gt;Примеры:&lt;br&gt;&lt;pre class="brush: bash"&gt;set CATALINA_OPTS=-Xms512m -Xmx512m&lt;/pre&gt;(Windows, значение не в кавычках)&lt;br&gt;&lt;pre class="brush: bash"&gt;export CATALINA_OPTS="-Xms512m -Xmx512m"&lt;/pre&gt;(ksh/bash, значение в кавычках)&lt;br&gt;&lt;pre class="brush: bash"&gt;setenv CATALINA_OPTS "-Xms512m -Xmx512m"&lt;/pre&gt;(tcsh/csh, значение в кавычках)&lt;br&gt;&lt;br&gt;Просмотрев catalina.bat или catallina.sh, вы можете заметить что для установки JVM опций использутся CATALINA_OPTS, JAVA_OPTS или и то и другое. В чем же различие между CATALINA_OPTS и JAVA_OPTS? Имя CATALINA_OPTS специфично именно для Tomcat, а JAVA_OPTS может использоваться и в других java приложениях (например Jboss). Так как переменные окружения как правило устанавливаются глобально, Вы можете использовать это CATALINA_OPTS задания опций для Tomcat, и JAVA_OPTS - для опций других приложений.&lt;br&gt;Я предпочитаю использовать CATALINA_OPTS.&lt;br&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи в JBoss?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Остановите Jboss, отредактируйте значения в файле $JBOSS_HOME/bin/run.conf, запустите сервер. Вы можете изменить (или добавить если ее там нет) значение переменной JAVA_OPTS например на такое: &lt;code lang="bash"&gt;JAVA_OPTS="-server -Xms128m -Xmx128m"&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи в Eclipse?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Запускайте Eclispe с ключем "-vmargs &amp;lt;ваши опции&amp;gt;". Все опции после -vmargs будут интерпретированы как опции JVM.&lt;br&gt;Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;eclipse -vmargs -Xms64m -Xmx256m&lt;/pre&gt;&lt;br&gt;Это установит опции для Eclipse, но не для приложения которое Вы разрабатываете в eclipse. Для того чтобы поменять опции приложения, используйте Run As -&amp;gt; Open Run Dialog -&amp;gt; (x)=Arguments -&amp;gt; VM Arguments&lt;br&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи в NetBeans?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Закройте NetBeans, отредактируйте файл netbeans-install/etc/netbeans.conf. Пример:&lt;br&gt;&lt;pre class="brush: bash"&gt;netbeans_default_options="-J-Xms512m -J-Xmx512m -J-XX:PermSize=32m -J-XX:MaxPermSize=128m -J-Xverify:none&lt;/pre&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи в Apache Ant?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Установите переменную окружения ANT_OPTS. Примеры:&lt;br&gt;&lt;pre class="brush: bash"&gt;set ANT_OPTS=-Xms512m -Xmx512m&lt;/pre&gt;(Windows)&lt;br&gt;&lt;pre class="brush: bash"&gt;export ANT_OPTS="-Xms512m -Xmx512m"&lt;/pre&gt;(ksh/bash)&lt;br&gt;&lt;pre class="brush: bash"&gt;setenv ANT_OPTS "-Xms512m -Xmx512m"&lt;/pre&gt;(tcsh/csh)&lt;br&gt;&lt;br&gt;&lt;b&gt;Как установить размер кучи в JavaEE SDK/J2EE SDK/Glassfish/Sun Java System Application Server?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Остановите сервер приложений, откройте $GLASSFISH_HOME/domains/domain1/config/domain.xml, найдите там XML элемент с именем java-config -&amp;gt; jvm-options. Пример:&lt;br&gt;&lt;pre class="brush: xml"&gt;&lt;br&gt;  -Xmx512m&lt;br&gt;  -XX:NewRatio=2&lt;br&gt;  -XX:MaxPermSize=128m&lt;br&gt;  ...&lt;br&gt;&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Также вы можете изменять опции через веб-интерфейс администратора, обычно http://localhost:4848/, или https://localhost:4848/. Откройте Application Server в верхней части левой панели, затем на правой панели откройте JVM Settings -&amp;gt; JVM Options, и Вы увидите список текущих опций. Вы можете добавить новые или изменить существующие.&lt;br&gt;&lt;br&gt;Еще один способ - использование cli комманды. Смотрите справку:&lt;br&gt;&lt;pre class="brush: bash"&gt;./asadmin help create-jvm-options&lt;br&gt;./asadmin help delete-jvm-options&lt;br&gt;&lt;/pre&gt;&lt;/div&gt;</description><category>ant</category><category>eclipse</category><category>java</category><category>systems_engineering</category><category>translation</category><guid>/ru/posts/2010/7-java-heap/</guid><pubDate>Sat, 06 Feb 2010 20:59:00 GMT</pubDate></item><item><title>Определение размера swap использованого процессом</title><link>/ru/posts/2010/swap/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;p&gt;Стандартные консольные утилиты Linux не показывают количество памяти процесса выгруженой в подкачку (swapped out).&lt;br&gt;&lt;br&gt;Однако есть достаточно простой способ узнать это. Все что для нужно - взять идентификатор процесса (PID) и просмотреть файл smaps относящийся к этому процессу:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/proc/pid/smaps&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Swap
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Эта команда выдаст кучу строк, относящихся к разным сегментам памяти. Чтобы просуммировать все можно воспользоваться awk:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/proc/pid/smaps&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Swap&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{ SUM += $2 } END { print SUM }'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Выведенное число - размер использованого свопа в килобайтах.&lt;br&gt;&lt;br&gt;&lt;br&gt;// Оригинал: &lt;a href="http://linuxgazette.net/164/lg_tips.html"&gt;http://linuxgazette.net/164/lg_tips.html&lt;/a&gt;&lt;/p&gt;</description><category>linux</category><category>syseng</category><category>tips</category><guid>/ru/posts/2010/swap/</guid><pubDate>Sat, 09 Jan 2010 21:06:00 GMT</pubDate></item><item><title>Введение в nginx, часть 2: Другие возможности</title><link>/ru/posts/2009/nginx-2/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;p&gt;Данная статья была опубликована в электронном приложением к журналу "&lt;a href="http://www.samag.ru/"&gt;Системный администратор&lt;/a&gt;"- "&lt;a href="http://osa.samag.ru/"&gt;Open Source #042&lt;/a&gt;"&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog-ru.greenmice.info/2013/04/nginx-1.html"&gt;В первой части&lt;/a&gt; статьи я рассказал о базовых и наиболее часто применяемых возможностях nginx. Однако это малая часть того, что можно сделать с nginx. Во второй части своей статьи я расскажу о некоторых более продвинутых возможностях, которые используются в крупных и высоконагруженых проектах.&lt;br&gt;&lt;br&gt;&lt;/p&gt;&lt;h3&gt;Failover и балансировка&lt;/h3&gt;Крупные проекты редко состоят из одного сервера приложений. Часто их два или больше, и возникает задача балансировки клиентов по этим серверам, а также выполнения failover — необходимо чтобы выход из строя одного из серверов не был заметен для клиентов.&lt;br&gt;Простейший способ рещить эту задачу — dns round-robin, т.е. назначение доменному имени нескольких ip-адресов. Но это решение имеет ряд недостатков, и гораздо лучше выглядит решение балансировки запросов по бакендам на фронтенде nginx. В конфигурационном файле выглядит это примерно так:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;# объявляем upstream — список бакендов&lt;br&gt;upstream  backend  {&lt;br&gt;  # перечисляем dns-имена или ip-адреса серверов и их «вес»&lt;br&gt;  server   web1                 weight=5;&lt;br&gt;  server   1.2.3.4:8080         weight=5;&lt;br&gt;  # а так можно подключаться к бакенду через unix-сокет&lt;br&gt;  server   unix:/tmp/backend3   weight=1;&lt;br&gt;}&lt;br&gt;# конфигурация виртуального сервера&lt;br&gt;server {&lt;br&gt;  listen &amp;lt;...&amp;gt;;&lt;br&gt;  server_name myserver.com;&lt;br&gt;  # отправляем все запросы из локейшена / в апстрим&lt;br&gt;  location / {&lt;br&gt;    proxy_pass  http://backend;&lt;br&gt;  }&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Запросы, приходящие к nginx, распределяются по бакендам соответственно указаному весу. Кроме того, можно сделать так, чтобы запросы с одних и тех же IP-адресов отправлялись на одни и те же серверы (для этого в upstream нужно указать директиву ip_hash). Так можно решить проблему с сессиями, но все же лучше найти какой-нибудь способ их репликации или (что еще лучше) использовать &lt;a href="http://ru.wikipedia.org/wiki/REST"&gt;RESTful-подход&lt;/a&gt;.&lt;br&gt;В случае, если один из серверов откажется принимать соединения или соединение к нему отвалится по таймауту, он на некоторое время будет исключен из upstream.
&lt;h3 id="nginx"&gt;Оптимизация nginx&lt;/h3&gt;
&lt;h4 id="1"&gt;1. Увеличение количества и объема буферов&lt;/h4&gt;
&lt;p&gt;Для хранения принятых запросов и еще не отданных ответов nginx использует буферы в памяти, а если запрос или ответ не помещается в них, nginx записывает его во временный файл (и пишет при этом предупреждение в log-файл). Поэтому необходимо установить такие размеры, чтобы в большинстве случаев не требовалось обращаться к временному файлу, а с другой стороны — чтобы буферы не использовали слишком много памяти.&lt;br&gt;&lt;br&gt;Для этого используются следующие параметры:&lt;br&gt;&lt;b&gt;client_body_buffer_size&lt;/b&gt; (по умолчанию: 8k/16k — в зависимости от архитектуры) — задает размер буфера для чтения тела запроса клиента. Обычно стандартного значения хватает, его требуется повышать, только если ваше приложение устанавливает огромные cookies.&lt;br&gt;&lt;b&gt;proxy_buffer_size&lt;/b&gt; (по умолчанию: 4k/8k) — задает размер буфера, в который будет читаться первая часть ответа, получаемого от проксируемого сервера. В этой части ответа находится, как правило, небольшой заголовок ответа. Стандартного значения обычно хватает.&lt;br&gt;&lt;b&gt;proxy_buffers&lt;/b&gt; (по умолчанию: 8 4k/8k) — задает число и размер буферов для одного соединения, в которые будет читаться ответ, получаемый от проксируемого сервера. Установите этот параметр так, чтобы большинство ответов от бэкенда помещалось в буферы.&lt;br&gt;&lt;br&gt;&lt;/p&gt;&lt;h4&gt;2. Механизмы обработки соединений&lt;/h4&gt;&lt;br&gt;Есть одна тонкость, касающаяся механизма обработки соединений, а именно — способ получения информации о событиях на сокетах. Существуют следующие методы:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;select — стандартный метод. На большой нагрузке сильно нагружает процессор.&lt;/li&gt;&lt;li&gt;poll — стандартный метод. Также сильно нагружает процессор.&lt;/li&gt;&lt;li&gt;kqueue — эффективный метод, используемый в операционных системах FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 и Mac OS X. На 2-процессорных машинах под управлением Mac OS X использование kqueue может привести к kernel panic.&lt;/li&gt;&lt;li&gt;epoll — эффективный метод, используемый в Linux 2.6+. В некоторых старых дистрибутивах есть патчи для поддержки epoll ядром 2.4.&lt;/li&gt;&lt;li&gt;rtsig — real time signals, эффективный метод, используемый в Linux 2.2.19+. При больших количествах одновременных соединений (более 1024) с ним могут быть проблемы (их можно обойти, но на мой взгляд, лучше с этим не связываться).&lt;/li&gt;&lt;li&gt;/dev/poll — эффективный метод, используемый в Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ и Tru64 UNIX 5.1A+.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;При компиляции nginx автоматически выбирается максимально эффективный найденый метод, однако скрипту configure можно насильно указать какой метод использовать. Если вы решили сделать это, то лучше использовать такие методы:&lt;br&gt;Linux 2.6: epoll;&lt;br&gt;FreeBSD: kqueue;&lt;br&gt;Solaris, HP/UX и другие: /dev/poll;&lt;br&gt;Linux 2.4 и 2.2: rtsig, не рекомендуется при больших нагрузках.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h4&gt;&lt;br&gt;Включение gzip позволяет сжимать ответ, отправляемый клиенту, что положительно сказывается на удовлетворенности пользователя, но требует больше времени CPU. Gzip включается директивой gzip (on|off). Кроме того, стоит обратить на следующие важные директивы модуля gzip:&lt;br&gt;&lt;br&gt;&lt;b&gt;gzip_comp_level&lt;/b&gt; 1..9 — устанавливает уровень сжатия. Опытным путем выявлено, что оптимальные значения лежат в промежутке от 3 до 5, большие значения дают маленький выигрыш, но создают существенно большую нагрузку на процессор, меньшие — дают слишком маленький коэффициент сжатия.&lt;br&gt;&lt;b&gt;gzip_min_length&lt;/b&gt; (по умолчанию, 0) — минимальный размер ответа, который будет сжиматься. Имеет смысл поставить этот параметр в 1024, чтобы слишком малеьнике файлы не сжимались (т.к. эффективность этого будет мала).&lt;br&gt;&lt;b&gt;gzip_types&lt;/b&gt; mime-тип [mime-тип ...] - разрешает сжатие ответа методом gzip для указанных MIME-типов в дополнение к "text/html". "text/html" сжимается всегда. Имеет смысл добавить такие mime-типы как text/css, text/javascript и подобные. Разумеется, сжимать gif, jpg и прочие уже компрессированые форматы не имеет смысла.&lt;br&gt;&lt;br&gt;Кроме того, существует модуль gzip_static, который позволяет раздавать уже сжатые статические файлы. В конфирурационном файле это выглядит так:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;location /files/ {&lt;br&gt;  gzip on;&lt;br&gt;  gzip_min_length 1024;&lt;br&gt;  gzip_types text/css text/javascript;&lt;br&gt;  gzip_comp_level 5;&lt;br&gt;  gzip_static on;&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;При использовании такой конфигурации в случае запроса «/files/test.html» nginx будет проверять наличие «/files/test.html.gz», и, если этот файл существует и дата его последнего изменения больше, чем дата последнего изменения файла test.html, будет отдан уже сжатый файл, что сохранит ресурсы процессора, которые потребовались бы для сжатия оригинального файла.&lt;br&gt;&lt;br&gt;&lt;/h4&gt;&lt;h4&gt;Оптимизация приложений&lt;/h4&gt;&lt;br&gt;Существует очень полезный трюк, который позволяет указать разработчикам приложений, какие страницы нужно оптимизировать в первую очередь. Для этого потребуется в конфиге nginx указать новый формат лога:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;log_format  my_combined  '$remote_addr - $remote_user [$time_local] '&lt;br&gt;    '"$request" $status $body_bytes_sent '&lt;br&gt;    '"$http_referer" "$http_user_agent" '&lt;br&gt;    '$upstream_response_time "$host"'&lt;br&gt;&lt;br&gt;access_log /var/log/nginx/access_log my_combined;&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Переменная $upstream_response_time содержит время ответа бэкенда, поэтому в лог попадает время обработки каждого запроса бэкендом. Далее понадобятся два скрипта:&lt;br&gt;&lt;br&gt;1. /usr/local/bin/url_stats_report.sh:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;#!/bin/sh&lt;br&gt;&lt;br&gt;echo "=== Requests which took most of the time ===" &amp;gt; /tmp/report.txt&lt;br&gt;echo "overall time - number of requests - average time - url" &amp;gt;&amp;gt; /tmp/report.txt&lt;br&gt;&lt;br&gt;cat /var/log/nginx/*access.log | /usr/local/bin/url_stats.py &amp;gt;&amp;gt; /tmp/report.txt&lt;br&gt;cat /tmp/report.txt | mail -s "url performance report" root&lt;br&gt;&lt;/pre&gt;&lt;br&gt;2. /usr/local/bin/url_stats.py:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: python"&gt;#!/usr/bin/env python&lt;br&gt;&lt;br&gt;import sys&lt;br&gt;&lt;br&gt;urls = {}&lt;br&gt;&lt;br&gt;try:&lt;br&gt;    while 1:&lt;br&gt;        line = raw_input()&lt;br&gt;        line_arr = line.split(" ")&lt;br&gt;        try:&lt;br&gt;            host = line_arr[-1]&lt;br&gt;            host = host[1:]&lt;br&gt;            host = host[:-1]&lt;br&gt;            url = line_arr[6]&lt;br&gt;            t = float(line_arr[-2])&lt;br&gt;            #print host, url, t&lt;br&gt;&lt;br&gt;            try:&lt;br&gt;                urls[host + url] = (urls[host + url][0] + t, urls[host + url][1] + 1)&lt;br&gt;            except KeyError, e:&lt;br&gt;                urls[host + url] = (t, 1)&lt;br&gt;        except ValueError, e:&lt;br&gt;            pass&lt;br&gt;&lt;br&gt;&lt;br&gt;except EOFError, e:&lt;br&gt;   pass&lt;br&gt;&lt;br&gt;def sort_by_value(d):&lt;br&gt;    """ Returns the keys of dictionary d sorted by their values """&lt;br&gt;    items=d.items()&lt;br&gt;    backitems=[ [v[1],v[0]] for v in items]&lt;br&gt;    backitems.sort(reverse=True)&lt;br&gt;    return [backitems[i][1] for i in range(0,len(backitems))]&lt;br&gt;&lt;br&gt;if (len(sys.argv) &amp;gt; 1):&lt;br&gt;    f = open(sys.argv[1], 'r')&lt;br&gt;    for k in f.readlines():&lt;br&gt;        k = k.strip()&lt;br&gt;        try:&lt;br&gt;             print urls[k][0], urls[k][1], urls[k][0] / urls[k][1], k&lt;br&gt;        except:&lt;br&gt;             print 0, 0, k&lt;br&gt;else:&lt;br&gt;    i = 0&lt;br&gt;    for k in sort_by_value(urls):&lt;br&gt;        print urls[k][0], urls[k][1], urls[k][0] / urls[k][1],  k&lt;br&gt;        i += 1&lt;br&gt;        if i &amp;gt; 100: break&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Они не идеальны, но задачу выполняют: запуская /usr/local/bin/url_stats_report.sh (например, в postrotate утилиты logrotate), вы получаете наглядную картину, какие запросы занимают большую часть времени бэкенда.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Кеширование&lt;/h3&gt;Незадолго до выхода этой статьи, Игорь Сысоев выпустил версию nginx 0.7.44 с экспериментальной поддержкой кеширования. Из-за большого количества багов, за которкое время было выпущено несколько версий, и в настоящее время последняя версия — 0.7.50 уже достаточно хорошо (хотя и не идеально) работает с кешированием.&lt;br&gt;Однако это все еще экспериментальная функция, но я решил рассказать о ней, т.к. ее одень давно ждали многое администраторы, да и лично для меня она очень полезна.&lt;br&gt;Сейчас nginx умеет кешировать на диске ответы от http и fastcgi запросов на бакенды, указывать ключ для кеширования, учитывать заголовки "X-Accel-Expires", "Expires" и "Cache-Control" и вручную устанавливать максимальное время жизни объекта в кеше.&lt;br&gt;Обслуживанием кеша (очиста старых файлов, наблюдение за размером и т.п.) занимается специальный процесс cache manager. Положительной особенностью реализации является то, что при старте nginx cache manager начинает проверку кеша в фоне, благодаря чему nginx не делает то что называется «дает сквида», т.е. он не висит несколько минут проверяя кеш перед стартом.&lt;br&gt;Я намеренно не указываю пример конфигурации, т.к. во-первых директивы могут еще поменяться, а во-вторых нужно глубокое понимание механизма кеширования, что требует вдумчивого чтения документации (http://sysoev.ru/nginx/docs/http/ngx_http_proxy_module.html#proxy_cache) и архивов рассылки nginx-ru.&lt;br&gt;&lt;br&gt;&lt;h3&gt;За кадром&lt;/h3&gt;&lt;br&gt;В статье освещена лишь та часть возможностей nginx, которыми я пользуюсь чаще всего. За пределами рассказа остались такие вопросы, как поддержка SSI, работа с memcached, экспериментальный встроенный Perl и сторонние модули, реализующие дополнительную функциональность.</description><category>nginx</category><category>python</category><category>syseng</category><guid>/ru/posts/2009/nginx-2/</guid><pubDate>Sat, 23 May 2009 21:20:00 GMT</pubDate></item><item><title>Введение в nginx, часть 1</title><link>/ru/posts/2013/nginx-1/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;div dir="ltr" style="text-align: left;"&gt;Данная статья была опубликована в электронном приложением к журналу "&lt;a href="http://www.samag.ru/"&gt;Системный администратор&lt;/a&gt;"- "&lt;a href="http://osa.samag.ru/"&gt;Open Source #041 (27.03.2009)&lt;/a&gt;"&lt;br&gt;&lt;br&gt;&lt;h2&gt;Введение&lt;/h2&gt;&lt;br&gt;nginx (engine x) — это HTTP-сервер и IMAP/POP3 прокси-сервер для UNIX-подобных платформ (FreeBSD и GNU/Linux). Nginx начал разрабатываться Игорем Сысоевым, сотрудником компании &lt;a href="http://rambler.ru/"&gt;Рамблер&lt;/a&gt; весной 2002 года, а осенью 2004 года появился первый публично доступный релиз. Он, как и все последующие, распространяется под лицензией BSD.&lt;br&gt;На данный момент nginx работает на большом количестве высоконагруженных сайтов (среди них — &lt;a href="http://rambler.ru/"&gt;Рамблер&lt;/a&gt;, &lt;a href="http://yandex.ru/"&gt;Яндекс&lt;/a&gt;, &lt;a href="http://vkontakte.ru/"&gt;В Контакте&lt;/a&gt;,  &lt;a href="http://wordpress.com/"&gt;wordpress.com&lt;/a&gt;, &lt;a href="http://www.wrike.com/"&gt;Wrike&lt;/a&gt; и другие). Текущая версия, 0.6.x, рассматривается как стабильная с точки зрения надежности, а релизы из ветки 0.7 считаются нестабильными. При этом важно заметить, что функциональность некоторых модулей будет меняться, вследствие чего могут меняться и директивы, поэтому обратной совместимости в nginx до версии 1.0.0 не гарантируется.&lt;br&gt;&lt;br&gt;Чем же nginx так хорош и почему его так любят администраторы высоконагруженных проектов? Почему бы просто не использовать Apache?&lt;br&gt;&lt;br&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Почему Apache — плохо?&lt;/h2&gt;&lt;br&gt;Для начала нужно объяснить, как вообще работают сетевые серверы. Те, кто знаком с сетевым программированием, знают, что по сути существуют три модели работы сервера:&lt;br&gt;&lt;ol&gt;&lt;li&gt;Последовательная. Сервер открывает слушающий сокет и ждет, когда появится соединение (во время ожидания он находится в заблокированном состоянии). Когда приходит соединение, сервер обрабатывает его в том же контексте, закрывает соединение и снова ждет соединения. Очевидно, это далеко не самый лучший способ, особенно когда работа с клиентом ведется достаточно долго и подключений много. Кроме того, у последовательной модели есть еще много недостатков (например, невозможность использования нескольких процессоров), и в реальных условиях она практически не используется.&lt;/li&gt;&lt;li&gt;Многопроцессная (многопоточная). Сервер открывает слушающий сокет. Когда приходит соединение, он принимает его, после чего создает (или берет из пула заранее созданных) новый процесс или поток, который может сколь угодно долго работать с соединением, а по окончании работы завершиться или вернуться в пул. Главный поток тем временем готов принять новое соединение. Это наиболее популярная модель, потому что она относительно просто реализуется, позволяет выполнять сложные и долгие вычисления для каждого клиента и использовать все доступные процессоры. Пример ее использования — Web-сервер Apache. Однако у этого подхода есть и недостатки: при большом количестве одновременных подключений создается очень много потоков (или, что еще хуже, процессов), и операционная система тратит много ресурсов на переключения контекста. Особенно плохо, когда клиенты очень медленно принимают контент. Получаются сотни потоков или процессов, занятых только отправкой данных медленным клиентам, что создает дополнительную нагрузку на планировщик ОС, увеличивает число прерываний и потребляет достаточно много памяти.&lt;/li&gt;&lt;li&gt;Неблокируемые сокеты/конечный автомат. Сервер работает в рамках одного потока, но использует неблокируемые сокеты и механизм поллинга. Т.е. сервер на каждой итерации бесконечного цикла выбирает из всех сокетов тот, что готов для приема/отправки данных с помощью вызова select(). После того, как сокет выбран, сервер отправляет на него данные или читает их, но не ждет подтверждения, а переходит в начальное состояние и ждет события на другом сокете или же обрабатывает следующий, в котором событие произошло во время обработки предыдущего. Данная модель очень эффективно использует процессор и память, но достаточно сложна в реализации. Кроме того, в рамках этой модели обработка события на сокете должна происходить очень быстро — иначе в очереди будет скапливаться много событий, и в конце концов она переполнится. Именно по такой модели работает nginx. Кроме того, он позволяет запускать несколько рабочих процессов (так называемых workers), т.е. может использовать несколько процессоров.&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;Итак, представим следующую ситуацию: на HTTP-сервер с каналом в 1 Гбит/с подключается 200 клиентов с каналом по 256 Кбит/с:&lt;br&gt;&lt;br&gt;Что происходит в случае Apache? Создается 200 потоков/процессов, которые относительно быстро генерируют контент (это могут быть как динамические страницы, так и статические файлы, читаемые с диска), но медленно отдают его клиентам. Операционная система вынуждена справляться с кучей потоков и блокировок ввода/вывода.&lt;br&gt;Nginx в такой ситуации затрачивает на каждый коннект на порядок меньше ресурсов ОС и памяти. Однако тут выявляется ограничение сетевой модели nginx: он не может генерировать динамический контент внутри себя, т.к. это приведет к блокировкам внутри nginx. Естественно, решение есть: nginx умеет проксировать такие запросы (на генерирование контента) на любой другой веб-сервер (например, все тот же Apache) или на FastCGI-сервер.&lt;br&gt;&lt;br&gt;Рассмотрим механизм работы связки nginx в качестве «главного» сервера и Apache в качестве сервера для генерации динамического контента:&lt;br&gt;&lt;br&gt;Nginx принимает соединение от клиента и читает от него весь запрос. Тут следует отметить, что пока nginx не прочитал весь запрос, он не отдает его на «обработку». Из-за этого обычно «ломаются» практически все индикаторы прогресса закачки файлов — впрочем, существует возможность починить их с помощью стороннего модуля upload_progress (это потребует модификации приложения).&lt;br&gt;После того, как nginx прочитал весь ответ, он открывает соединение к Apache. Последний выполняет свою работу (генерирует динамический контент), после чего отдает свой ответ nginx, который его буферизует в памяти или временном файле. Тем временем, Apache освобождает ресурсы.&lt;br&gt;Далее nginx медленно отдает контент клиенту, тратя при этом на порядки меньше ресурсов, чем Apache.&lt;br&gt;&lt;br&gt;Такая схема называется фронтэнд + бэкенд (frontend + backend) и применяется очень часто.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Установка&lt;/h2&gt;&lt;br&gt;Т.к. nginx только начинает завоевывать популярность, имеются некоторые проблемы с бинарными пакетами, так что будьте готовы к тому, что его придется компилировать самостоятельно. С этим обычно не возникает проблем, надо лишь внимательно прочитать вывод команды &lt;code lang="bash"&gt;./configure --help&lt;/code&gt; и выбрать необходимые вам опции компиляции, например такие:&lt;br&gt;&lt;pre class="brush: bash"&gt;./configure \&lt;br&gt;    --prefix=/opt/nginx-0.6.x \ # префикс установки&lt;br&gt;    --conf-path=/etc/nginx/nginx.conf \ # расположение конфигурационного файла&lt;br&gt;    --pid-path=/var/run/nginx.pid \ # ... и pid-файла&lt;br&gt;    --user=nginx \ # имя пользователя под которым будет запускаться nginx&lt;br&gt;    --with-http_ssl_module --with-http_gzip_static_module  --with-http_stub_status_module \ # список нужных&lt;br&gt;    --without-http_ssi_module --without-http_userid_module --without-http_autoindex_module --without-http_geo_module --without-http_referer_module --without-http_memcached_module --without-http_limit_zone_module # ... и не нужных модулей&lt;br&gt;&lt;/pre&gt;&lt;br&gt;После конфигурирования стоит запустить стандартный &lt;code lang="bash"&gt;make &amp;amp;&amp;amp; make install&lt;/code&gt;, после чего можно пользоваться nginx.&lt;br&gt;Кроме того в Gentoo вы можете воспользоваться ebuild'ом из стандартного дерева портов; в RHEL/CentOS репозиторием epel (в нем расположени nginx 0.6.x) или srpm для версии 0.7, который можно скачать отсюда: &lt;a href="http://blogs.mail.ru/community/nginx"&gt;http://blogs.mail.ru/community/nginx&lt;/a&gt;; в Debian можно воспользоваться пакетом nginx из ветки unstable.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Конфигурационный файл&lt;/h2&gt;&lt;br&gt;Конфигурационный файл nginx очень удобен и интуитивно понятен. Называется он обычно nginx.conf и распологается в $prefix/conf/ если расположение не было переопределено при компиляции. Я люблю класть его в /etc/nginx/, также делают и разработчики всех пакетов упомянутых выше.&lt;br&gt;Структура конфигурационного файла такова:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;user nginx; # имя пользователя, с правами которого будет запускаться nginx&lt;br&gt;worker_processes 1; # количество рабочих процессов&lt;br&gt;events {&lt;br&gt;  &amp;lt;...&amp;gt; # в этом блоке указывается механизм поллинга который будет использоваться (см. ниже) и максимальное количество возможных подключений&lt;br&gt;}&lt;br&gt;&lt;br&gt;http {&lt;br&gt;  &amp;lt;глобальные директивы http-сервера, например настройки таймаутов и т.п.&amp;gt;;&lt;br&gt;  &amp;lt;почти все из них можно переопределить для отдельного виртуального хоста или локейшена&amp;gt;;&lt;br&gt; &lt;br&gt;  # описание серверов (это то что в apache называется VirtualHost)&lt;br&gt;  server {&lt;br&gt;    # адрес и имя сервера&lt;br&gt;    listen *:80;&lt;br&gt;    server_name aaa.bbb;&lt;br&gt;&lt;br&gt;    &amp;lt;Директивы сервера. Здесь обычно указывают расположение докуменов (root), редиректы и переопределяют глобальные настройки&amp;gt;;&lt;br&gt;    &lt;br&gt;    # а вот так можно определить location, для которого можно также переопределить практически все директивы указаные на более глобальных уровнях&lt;br&gt;    location /abcd/ {&lt;br&gt;      &amp;lt;директивы&amp;gt;;&lt;br&gt;    }&lt;br&gt;    # Кроме того, можно сделать location по регулярному выражению, например так:&lt;br&gt;    location ~ \.php$ {&lt;br&gt;       &amp;lt;директивы&amp;gt;;&lt;br&gt;    }&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  # другой сервер&lt;br&gt;  server {&lt;br&gt;    listen *:80;&lt;br&gt;    server_name ccc.bbb;&lt;br&gt;&lt;br&gt;    &amp;lt;директивы&amp;gt;&lt;br&gt;  }&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Обратите внимание на то, что каждая директива должна оканчиваться точкой с запятой.&lt;br&gt;Обратное проксирование и FastCGI&lt;br&gt;&lt;br&gt;Итак, выше мы рассмотрели преимущества схемы frontend + backend, разобрались с установкой, структурой и синтаксисом конфигурационного файла, рассмотрим тепеть как реализовать обратное проксирование в nginx.&lt;br&gt;&lt;br&gt;А очень просто! Например так:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;location / {&lt;br&gt;  proxy_pass http://1.2.3.4:8080;&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;В этом примере все запросы попадающие в location / будут проксироваться на сервер 1.2.3.4 порт 8080. Это может быть как apache, так и любой другой http-сервер.&lt;br&gt;&lt;br&gt;Однако тут есть несколько тонкостей, связанных с тем, что приложение будет считать, что, во-первых, все запросы приходят к нему с одного IP-адреса (что может быть расценено, например, как попытка DDoS-атаки или подбора пароля), а во-вторых, считать, что оно запущено на хосте 1.2.3.4 и порту 8080 (соответственно, генерировать неправильные редиректы и абсолютные ссылки). Чтобы избежать этих проблем без необходимости переписывания приложения, мне кажется удобной следующая конфигурация:&lt;br&gt;Nginx слушает внешний интерфейс на порту 80.&lt;br&gt;&lt;br&gt;Если бэкенд (допустим, Apache) расположен на том же хосте, что и nginx, то он «слушает» порт 80 на 127.0.0.1 или другом внутреннем IP-адресе.&lt;br&gt;&lt;br&gt;Конфигурация nginx в таком случае выглядит следующим образом:&lt;br&gt;&lt;pre class="brush: c"&gt;server {&lt;br&gt;  listen 4.3.2.1:80;&lt;br&gt;  # устанавливаем заголовок Host и X-Real-IP: к каждому запросу отправляемому на backend&lt;br&gt;  proxy_set_header X-Real-IP $remote_addr;&lt;br&gt;  proxy_set_header Host $host:$proxy_port; &lt;br&gt;# или «proxy_set_header Host $host;», если приложение будет дописывать :80 ко всем ссылкам&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Для того, чтобы приложение различало IP-адреса посетителей, нужно либо поставить модуль  mod_extract_forwarded (если оно исполняется сервером Apache), либо модифицировать приложение так, чтобы оно брало информацию о IP-адресе пользователя из HTTP-заголовка X-Real-IP.&lt;br&gt;&lt;br&gt;Другой вариант бэкенд — это использование &lt;a href="http://ru.wikipedia.org/wiki/FastCGI"&gt;FastCGI&lt;/a&gt;. В этом случае конфигурация nginx будет выглядеть примерно так:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;server {&lt;br&gt;  &amp;lt;...&amp;gt;&lt;br&gt;&lt;br&gt;# location, в который будут попадать запросы на php-скрипты&lt;br&gt;location ~ .php$ {&lt;br&gt;  fastcgi_pass   127.0.0.1:8888; # определяем адрес и порт fastcgi-сервера,&lt;br&gt;  fastcgi_index  index.php; # ...индексный файл&lt;br&gt;&lt;br&gt;  # и некоторые параметры, которые нужно передать серверу fastcgi, чтобы он понял какой скрипт и с какими параметрами выполнять:&lt;br&gt;  fastcgi_param  SCRIPT_FILENAME  /usr/www/html$fastcgi_script_name; # имя скрипта&lt;br&gt;  fastcgi_param  QUERY_STRING     $query_string; # строка запроса&lt;br&gt;  # и параметры запроса:&lt;br&gt;  fastcgi_param  REQUEST_METHOD   $request_method;&lt;br&gt;  fastcgi_param  CONTENT_TYPE     $content_type;&lt;br&gt;  fastcgi_param  CONTENT_LENGTH   $content_length;&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;# благодяря тому что локейшены с регулярными выражениями обладают большим «приоритетом», сюда будут попадать все не-php запросы.&lt;br&gt;&lt;pre class="brush: c"&gt;location / {&lt;br&gt;   root /var/www/html/&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;&lt;h2&gt;Статика&lt;/h2&gt;&lt;br&gt;Для того, чтобы меньше нагружать бэкенд, статические файлы лучше отдавать только через nginx — он, с этой задачей справляется лучше, т.к. на каждый запрос он тратит существенно меньше ресурсов (не надо порождать новый процесс, да процесс nginx'а как правило потребляет меньше памяти, а обслуживать может множество соединений).&lt;br&gt;&lt;br&gt;В конфигурационном файле это выглядит примерно так:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;server {&lt;br&gt;  listen       *:80;&lt;br&gt;  server_name  myserver.com;&lt;br&gt;&lt;br&gt;  location / {&lt;br&gt;    proxy_pass   http://127.0.0.1:80;&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  # предположим что все статичные файлы лежат в /files&lt;br&gt;  location /files/ {&lt;br&gt;    root /var/www/html/; # указываем путь на фс&lt;br&gt;    expires 14d; # добавляем заголовок Expires:&lt;br&gt;    error_page   404  =  @back; # а если файл не найден, отправляем его в именованный локейшн @back&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  # запросы из /files, для которых не было найдено файла отправляем на backend, а он может либо сгенерировать нужный файл, либо показать красивое сообщение об ошибке&lt;br&gt;  location @back {&lt;br&gt;    proxy_pass   http://127.0.0.1:80;&lt;br&gt;  }&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Если вся статика не помещена в какой-то определенный каталог, то воспользоваться регулярным выражением:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: c"&gt;location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js)$ {&lt;br&gt;  # аналогично тому что выше, только в этот location будут попадать все запросы оканчивающиеся на одно из указаных суффиксов&lt;br&gt;  root   /var/www/html/;&lt;br&gt;  error_page   404  =  @back;&lt;br&gt;}&lt;br&gt;&lt;/pre&gt;&lt;br&gt;К сожалению, в nginx не реализована асинхронная работа с файлами. Иными словами, nginx worker блокируется на операциях ввода-вывода. Так что если у вас очень много статических файлов и, в особенности, если они читаются с разных дисков, лучше увеличивать количество рабочих процессов (до числа, которое в 2—3 раза больше, чем суммарное число головок на диске). Это, конечно, ведет к увеличению нагрузки на ОС, но в целом производительность увеличивается. Для работы с типичным количеством статики (не очень большое количество сравнительно небольших файлов: CSS, JavaScript, изображения) вполне хватает одного-двух рабочих процессов.&lt;br&gt;&lt;br&gt;&lt;h2&gt;To be continued&lt;/h2&gt;&lt;br&gt;&lt;a href="http://greenmice.info/ru/node/116"&gt;Продолжение статьи уже можно прочитать&lt;/a&gt; на этом сайте или в "OpenSource" #042.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Ссылки&lt;/h2&gt;&lt;br&gt;Тут можно найти дополнительноую информацию о nginx:&lt;br&gt;&lt;br&gt;&lt;a href="http://sysoev.ru/nginx/"&gt;официальный сайт nginx&lt;/a&gt;&lt;br&gt;&lt;a href="http://sysoev.ru/"&gt;сайт Игоря Сысоева&lt;/a&gt;&lt;br&gt;&lt;a href="http://wiki.codemongers.com/"&gt;Nginx Wiki&lt;/a&gt;&lt;br&gt;&lt;a href="http://openhack.ru/nginx-patched"&gt;nginx с дополнительными сторонними модулями&lt;/a&gt;&lt;br&gt;&lt;a href="http://blogs.mail.ru/community/nginx"&gt;src.rpm для последних версий nginx&lt;/a&gt;&lt;br&gt;&lt;a href="http://sysoev.ru/nginx/links.html"&gt;еще несколько хороших ссылок&lt;/a&gt;&lt;br&gt;&lt;a href="http://sysoev.ru/nginx/docs/maillists.html"&gt;список рассылки nginx-ru&lt;/a&gt;&lt;/div&gt;</description><category>nginx</category><category>syseng</category><guid>/ru/posts/2013/nginx-1/</guid><pubDate>Fri, 24 Apr 2009 14:22:00 GMT</pubDate></item><item><title>Denyhosts - блокировка перебора паролей SSH</title><link>/ru/posts/2009/denyhosts-ssh/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;p&gt;&lt;a href="http://www.denyhosts.net"&gt;Denyhosts&lt;/a&gt; - полезная утилита для пресечения попыток подобрать пароль к ssh.&lt;/p&gt;
&lt;p&gt;Устанавливается без каких-либо проблем: &lt;code&gt;emerge -av denyhosts&lt;/code&gt; в Gentoo, для
других дистрибутивов пакеты также существуют и как правило находятся в основном
репозитории.&lt;/p&gt;
&lt;p&gt;Denyhosts работает следующим образом: он проверяет системный журнал и добавляет
в &lt;code&gt;/etc/hosts.deny&lt;/code&gt; IP адреса, с которых наблюдается много попыток неудачного
входа. Для того чтобы это работало, SSH должен быть собран с tcp_wrappers (что
всегда разумно и делается по умолчанию).&lt;/p&gt;
&lt;p&gt;У Denyhosts достаточно гибкие настройки, можно указать после скольких неудачных
попыток блокировать хост, на какой период это делать и т.п. Настойки по
умолчанию на мой взгляд чересчур суровы, поэтому имеет смысл отредактировать
файл /etc/denyhosts.conf, который весьма прост для понимания и имеет подробные
комментарии.&lt;/p&gt;
&lt;p&gt;Есть два способа запустить Denyhosts: в качестве демона или в качестве
cron-задания. Памяти он потребляет немного, поэтому проще первое:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;/etc/init.d/denyhosts&lt;span class="w"&gt; &lt;/span&gt;start
rc-upade&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;denyhosts&lt;span class="w"&gt; &lt;/span&gt;default
&lt;/pre&gt;&lt;/div&gt;</description><category>denyhosts</category><category>security</category><category>ssh</category><category>systems_engineering</category><guid>/ru/posts/2009/denyhosts-ssh/</guid><pubDate>Sun, 08 Mar 2009 14:16:00 GMT</pubDate></item><item><title>Оптимизация производительности Apache</title><link>/ru/posts/2009/apache/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;div dir="ltr" style="text-align: left;"&gt;&lt;h2&gt;Введение&lt;/h2&gt;&lt;br&gt;По данным Netcraft, Apache - самый популярный веб-сервер в интернет, он обслуживает множество серверов и сайтов. Часто возникает необходимость увеличить производительность веб-сервера. Наверное лучший способ это сделать - перейти к схеме frontend+backend, но это может потребовать достаточно серьезных изменений в приложении (например, у вас наверняка отвалятся всяческие индикаторы прогресса аплоада файлов).&lt;br&gt;&lt;br&gt;Другой способ - просто увеличить производительность сервера - поставить более быстрый процессор и больше памяти.&lt;br&gt;&lt;br&gt;Однако и первое и второе требует много времени и ресурсов, так что на первое время можно попробовать ускорить apache путем оптимизации его конфигурации. Существуют оптимизации, которые можно применить только при пересборке apache, другие же можно применять без перекомпиляции сервера.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Загружайте только необходимые модули&lt;/h2&gt;&lt;br&gt;Apache - модульная программа, бОльшая часть функций которой реализуется в модулях. При этом эти модули могут быть как вкомпилированы, так и собраны в виде DSO - динамических библиотеках. Большинство современных дистрибутивов поставляет apache с набором DSO, так что не нужные модули можно легко отключить без перекомпиляции.&lt;br&gt;&lt;br&gt;Запускайте apache только с необходимыми модулями, чтобы уменьшить потребление памяти. Если вы решили скомпилировать apache самостоятельно, то либо тщательно подходите к выбору списка модулей, которые вы включите, либо компилируйте их как DSO используя apxs в apache1 и apxs2 в apache2. Для того чтобы отключить ненужные DSO-модули, достаточно закомментировать лишние строчки LoadModule в httpd.conf. Apache со статически скомпилированными модулями будет потреблять чуть меньше памяти, однако вам придется каждый раз его перекомпилировать для изменения списка модулей.&lt;br&gt;&lt;br&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Выберете подходящий MPM&lt;/h2&gt;&lt;br&gt;В apache каждый запрос обрабатывается в своем процессе или потоке. При компиляции apache позволяет выбирать один из нескольким MPM (Multi-processing module), которые отвечают за прослушивание портов, прием запросов и раздачу этих запросов дочерним процессам или потокам, в которых эти запросы будут обработаны.&lt;br&gt;&lt;br&gt;Выбор MPM зависит от нескольких факторов, таких как наличие поддержки потоков в ОС, количества свободной памяти, а также требований стабильности и безопасности.&lt;br&gt;&lt;br&gt;Если безопасность очень важна, следует выбрать peruser MPM, пожертвовав производительностью.&lt;br&gt;&lt;br&gt;Если важна именно производительность, то выбор ограничивается двумя mpm: prefork и worker.&lt;br&gt;&lt;br&gt;Worker - поточный MPM, т.е. в нем каждый запрос обслуживается в отдельном потоке одного из дочерних процессов. Потоки - более легкие для ОС объекты, чем процессы, они более эффективно используют память и переключения контекста для них происходят быстрее. Однако, из-за того что каждый поток имеет доступ ко всей памяти процесса, worker mpm более подвержен сбоям: сбой одного потока может повлечь падение всего процесса, в котором находился этот поток (именно поэтому worker mpm запускает несколько дочерних процессов с несколькими потоками в каждом).&lt;br&gt;&lt;br&gt;Perfork - mpm использует несколько дочерних процессов, каждый дочерний процесс обрабатывает одно подключение. Из-за того что процесс - более тяжелая структура, он использует немного больше ресурсов, зато он менее подвержен сбоям - обработка каждого отдельного запроса не зависит от других процессов.&lt;br&gt;&lt;br&gt;К сожалению, для смены mpm требуется перекомпиляция apache. Тут проявляют свои достоинства source-based дистрибутивы: вы можете легко перекомпилировать apache и все зависимые от него пакеты, не превратив систему в свалку. Бинарные дистрибутивы выходят из этой ситуации по-разному. Например в RHEL в apache rpm находится сразу две версии apache - с worker и prefork mpm (prefork используется по умолчанию). Однако worker mpm не поддерживает php. Так что если вы хотите php и worker mpm вам придется компилировать его самостоятельно либо искать сторонние репозитории.&lt;br&gt;&lt;br&gt;&lt;h2&gt;DNS запросы&lt;/h2&gt;&lt;br&gt;Директива HostnameLookups включает reverse DNS запросы, так что в логи будут попадать dns-имена клиентов вместо ip-адресов. Разумеется, что это существенно замедляет обработку запроса, т.к. запрос не обрабатывается пока не будет получен ответ от DNS-сервера. Поэтому следите чтобы эта директива всегда была выключена (HostnameLookups Off), а если вам все-таки нужны dns-адреса, вы можете узнать их позже, прогнав лог в утилите logresolve (которая поставляется с apache).&lt;br&gt;&lt;br&gt;Кроме того, следите чтобы в директивах Allow from и Deny From использовались ip-адреса а не доменные имена. Иначе apache будет делать два dns запроса (обратный и прямой) чтобы убедиться что клиент-тот за кого себя выдает.&lt;br&gt;&lt;br&gt;&lt;h2&gt;AllowOverride&lt;/h2&gt;&lt;br&gt;Если директива AllowOverride не установлена в 'None', apache будет пытаться открыть .htaccess файлы в каждой директории которую он посещает и во всех директориях выше нее. Например:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: html"&gt;DocumentRoot /var/www/html&lt;br&gt;&amp;lt;Directory /var/www/html/&amp;gt;&lt;br&gt;  AllowOverride all&lt;br&gt;&amp;lt;/Directory&amp;gt;&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Если будет запрошен /index.html, apache попытается открыть (и интерпретировать) файлы  /.htaccess, /var/.htaccess, /var/www/.htaccess, и /var/www/html/.htaccess. Это увеличивает время обработки запроса. Так что, если вам нужен .htaccess только для одной директории, разрешайте его только для нее:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: html"&gt;DocumentRoot /var/www/html&lt;br&gt;&amp;lt;Directory /&amp;gt;&lt;br&gt;  AllowOverride None&lt;br&gt;&amp;lt;/Directory&amp;gt;&lt;br&gt;&amp;lt;Directory /var/www/html/&amp;gt;&lt;br&gt;  AllowOverride all&lt;br&gt;&amp;lt;/Directory&amp;gt;&lt;br&gt;&lt;/pre&gt;&lt;br&gt;&lt;h2&gt;FollowSymLinks и SymLinksIfOwnerMatch&lt;/h2&gt;&lt;br&gt;Если для директории включена опция FollowSymLinks, сервер будет следовать по символическим ссылкам в этой директории. Если для директории включена опция SymLinksIfOwnerMatch, apache будет следовать по символическим ссылкам только если владелец файла или директории, на которую указывает эта ссылка совпадает с владельцем указанной директории. Так что при включенной опции SymLinksIfOwnerMatch apache делает больше системных запросов.&lt;br&gt;&lt;br&gt;Кроме того, дополнительные системные запросы требуются когда FollowSymlinks НЕ УСТАНОВЛЕН. Т.о. наиболее оптимальная ситуация для производительности - когда опция FollowSymlinks включена.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Content Negotiatio&lt;/h2&gt;&lt;br&gt;Старайтесь избегать content negotiaion.&lt;br&gt;&lt;br&gt;&lt;h2&gt;MaxClients&lt;/h2&gt;&lt;br&gt;Директива MaxClients устанавливает максимальное количество параллельных запросов, которые будет поддерживать сервер. Apache не будет порождать больше процессов/потоков чем MaxClients. Значение MaxClient не долно быть слишком маленьким (иначе много клиентов останутся необслуженными), но и не стоит устанавливать слишком большое количество - лучше не обслужить часть клиентов чем исчерпать все ресурсы, залезть в своп и умереть под нагрузкой. Хорошим может быть значение MaxClients = количество памяти выделенное под веб-сервер / максимальный размер порожденного процесса или потока. Для статических файлов apache использует около 2-3 Мб на процесс, для динамики (php, cgi) - зависит от скрипта, но обычно около 16-32 Мб.&lt;br&gt;&lt;br&gt;Вы можете прикинуть примерный размер посмотрев на колонку rss в выводе `ps -ylC httpd --sort:rss`&lt;br&gt;&lt;br&gt;Если сервер уже обслуживает MaxClients запросов, новые запросы попадут в очередь, размер которой устанавливается с помощью директивы ListenBacklog.&lt;br&gt;&lt;br&gt;&lt;h2&gt;MinSpareServers, MaxSpareServers, и StartServers&lt;/h2&gt;&lt;br&gt;Т.к. создание потока, и особенно процесса - дорогая операция, apache создает их заранее. Директивы MaxSpareServers и MinSpareServers устанавливают как много процессов/потоков должны ожидать в готовности принять запрос (максимум и минимум). Если значение MinSpareServers слишком маленькое и неожиданно приходит много запросов, apache вынужден будет создавать много новых процессов/потоков, что создаст дополнительную нагрузку в этой стрессовой ситуации. С другой стороны, если MaxSpareServers слишком велико, apache будет сильно нагружать систему этими процессами, даже если количество клиентов минимально.&lt;br&gt;&lt;br&gt;Постарайтесь установить такие MinSpareServers и MaxSpareServers, чтобы apache не создавал более 4 процессов/потоков в секунду. Если он создаст более 4, в ErrorLog будет помещено сообщение об этом. Это - сигнал того что MinSpareServers слишком мало.&lt;br&gt;&lt;br&gt;&lt;h2&gt;MaxRequestsPerChild&lt;/h2&gt;&lt;br&gt;Директива MaxRequestsPerChild устанавливает сколько запросов может обработать один дочерний процесс/поток прежде чем он будет завершен. По умолчанию значение этой директивы установлено в 0, что означает что однажды созданный процесс/поток не будет завершен никогда (ну кроме случаев остановки сервера или краха этого процесса/потока). Рекомендую установить MaxRequestsPerChild равное какому-нибудь достаточно большому числу (несколько тысяч). Это не создаст излишней нагрузки, связаной с тем что apache будет вынужден создавать новые дочерние процессы, в то же время это поможет избавиться от проблем с утечкой памяти в дочерних процессах (что очень возможно например если вы используете нестабильную версию php).&lt;br&gt;&lt;br&gt;&lt;h2&gt;KeepAlive и KeepAliveTimeout&lt;/h2&gt;&lt;br&gt;KeepAlive позволяет делать несколько запросов в одном TCP-подключении. Это особенно полезно для html-страниц с большим количеством изображений. Если KeepAlive установлен в Off, то для самой страницы и для каждого изображения будет создано отдельное подключение (которое нужно будет обработать master-процессу), что плохо и для сервера и для клиента. Так что для подобных случаев рекомендуется устанавливать KeepAlive в On. Для других применений (например для download-сервера) KeepAlive может быть бесполезен и даже вреден, т.к. при включенном KeepAlive сервер закрывает соединение не сразу, а ждет KeepAliveTimeout секунд нового запроса. Для того чтобы процессы не висели слишком долго в бесполезном ожидании, устанавливайте KeepAliveTimeout достаточно малым, около 5-10 секунд обычно достаточно.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Сжатие&lt;/h2&gt;&lt;br&gt;HTTP-сжатие было определено в стандарте HTTP/1.1, и сейчас все современные клиентские программы и практически все сервера его поддерживают. Сервер может отдавать ответ в gzip или deflate, а клиентская программа незаметно для пользователя разжимает данные. Это уменьшает количество передаваемого трафика (до 75%), но конечно же повышает использование процессора.&lt;br&gt;Однако если ваш сервер посещает много клиентов с медленным подключение, сжатие может снизить нагрузку с вашего сервера из-за того что сервер сможет быстрее передать сжатый ответ и освободить ресурсы, занятые дочерним процессом. Особенно сильно этот эффект может быть заметен если у вас быстрый процессор, но мало памяти.&lt;br&gt;&lt;br&gt;Кеширование конфигурируется директивами модуля mod_deflate. Имейте в виду, что не следует устанавливать степень сжатия gzip более 4-5 - это потребует существенно большего времени CPU, а эффект будет достаточно невелик. Ну и разумеется не нужно пытаться сжать изображения в jpg, gif и png, музыку, видео файлы и все другие бинарные файлы, которые уже и так хорошо сжаты.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Кеширование на стороне клиента&lt;/h2&gt;&lt;br&gt;Не забывайте устанавливать Expires заголовки на статические файлы (см. модуль mod_expires). Если файл не изменяется, то его всегда следует попробовать закешировать на клиенте. Тогда у клиента будут быстрее загружаться страницы, а сервер освободится от лишних запросов.&lt;br&gt;&lt;br&gt;Оригинал: "Configuring Apache for Maximum Performance". Vishnu Ram V: http://linuxgazette.net/123/vishnu.html&lt;/div&gt;</description><category>apache</category><category>performance</category><category>syseng</category><guid>/ru/posts/2009/apache/</guid><pubDate>Tue, 10 Feb 2009 14:24:00 GMT</pubDate></item><item><title>запускать задачу раз в месяц в субботу</title><link>/ru/posts/2008/blog-post/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;p&gt;Часто необходимо запускать что-то (например полный бекап бд) раз в месяц, но в выходной, допустим в ночь с субботы на воскресенье.&lt;br&gt;&lt;br&gt;Это можно сделать в crontab следующим образом&lt;br&gt;&lt;br&gt;&lt;/p&gt;&lt;pre class="brush: bash"&gt;0 23 * * 6 [`date "+%d"` -lt 8] &amp;amp;&amp;amp; /path/to/script&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Это запустит скрипт в первую субботу месяца в 23:00.</description><category>cron</category><category>syseng</category><category>tips</category><guid>/ru/posts/2008/blog-post/</guid><pubDate>Wed, 03 Dec 2008 16:36:00 GMT</pubDate></item><item><title>Monit: простое средство мониторинга</title><link>/ru/posts/2008/monit/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;p&gt;Monit - достаточно простое, но одновременно удобное, достаточно мощное и надежное средство для мониторинга ваших серверов.&lt;br&gt;Monit умеет мониторить:&lt;br&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;процессы (наличие, количество потребляемых ресурсов)&lt;/li&gt;&lt;li&gt;файлы, директории и файловые системы на изменения (дата создания/изменения, изменения размера и контрольной суммы)&lt;/li&gt;&lt;li&gt;сетевые хосты (пинг и коннект на определенный порт по определенному протоколу)&lt;/li&gt;&lt;/ul&gt;При возникновении проблемы monit отправляет e-mail (шаблоны можно модифицировать) и может перезапустить сервис.&lt;br&gt;В monit встроен простенький веб-сервер, который позволяет посмотреть состояние объектов мониторинга, включить/выключить определенный объект.&lt;br&gt;Monit умеет перезапускать сервисы если они падают или не выполняется какое-то условие.&lt;br&gt;&lt;br&gt;Monit построен с идеей того что система мониторинга должна быть максимально надежной и простой. И это действительно выполняется: на monit можно положиться.
&lt;p&gt;Конечно из-за своей простоты monit не обладает тем количеством возможностей, которыми обладают Enterptise-системы мониторинга. Однако существует дополнение к monit под названием M/Monit, которое позволяет управлять несколькими серверами с monit из одного места. К сожалению, M/Monit распространяется под коммерческой лицензией и за деньги.&lt;br&gt;&lt;br&gt;Посмотрим что он умеет:&lt;br&gt;&lt;br&gt;Установка проста:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;emerge&lt;span class="w"&gt; &lt;/span&gt;-av&lt;span class="w"&gt; &lt;/span&gt;monit
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;После этого вам необходимо отредактировать файл &lt;code&gt;/etc/monitrc&lt;/code&gt;. Он достаточно хорошо документирован и там много примеров, вот еще несколько:&lt;br&gt;&lt;br&gt;/etc/monitrc&lt;br&gt;&lt;/p&gt;&lt;pre class="brush: bash"&gt;set daemon  120 # проверять объекты каждые 2 минуты&lt;br&gt;set logfile syslog facility log_daemon&lt;br&gt;&lt;br&gt;set mailserver localhost # тут для большей надежности можно указать несколько smtp-серверов&lt;br&gt;set eventqueue # задаем очередь сообщений - чтобы monit мог отправить алерт позже, если в данный момент почтовый сервер не доступен&lt;br&gt;    basedir /var/monit&lt;br&gt;    slots 10&lt;br&gt;set mail-format { from: monit@ myserver.com }&lt;br&gt;set alert admin1 admin2 # список получателей алертов&lt;br&gt;&lt;br&gt;# конфигурация встроенного http сервера&lt;br&gt;set httpd port 2812 and&lt;br&gt;    use address 0.0.0.0&lt;br&gt;    allow 1.2.3.4&lt;br&gt;    allow admin:password&lt;br&gt;&lt;br&gt;include /etc/monit.d/*&lt;br&gt;&lt;/pre&gt;&lt;br&gt;/etc/monit.d/system&lt;br&gt;&lt;pre class="brush: bash"&gt;# проверка общих ресурсов сервера&lt;br&gt;check system myserver&lt;br&gt;    if loadavg (1min) &amp;gt; 30 then alert&lt;br&gt;    if loadavg (5min) &amp;gt; 20 then alert&lt;br&gt;    if memory usage &amp;gt; 75% then alert&lt;br&gt;   if cpu usage (user) &amp;gt; 70% then alert&lt;br&gt;&lt;/pre&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;# проверка apache2:&lt;br&gt;check process apache with pidfile /var/run/apache2.pid&lt;br&gt;    start program = "/etc/init.d/apache2 start"&lt;br&gt;    stop program  = "/etc/init.d/apache2 stop"&lt;br&gt;    if totalmem &amp;gt; 500.0 MB for 5 cycles then restart&lt;br&gt;    if children &amp;gt; 250 then restart&lt;br&gt;    if loadavg(5min) greater than 30 for 8 cycles then stop&lt;br&gt;    if failed host myserver.com port 80 protocol http&lt;br&gt;       and request "/index.html"&lt;br&gt;       then restart&lt;br&gt;    if failed port 443 type tcpssl protocol http&lt;br&gt;       with timeout 15 seconds&lt;br&gt;       then restart&lt;br&gt;    if 3 restarts within 5 cycles then timeout&lt;br&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;# проверка свободного места на фс&lt;br&gt;check device data with path /dev/sdb1&lt;br&gt;    start program  = "/bin/mount /data"&lt;br&gt;    stop program  = "/bin/umount /data"&lt;br&gt;    if space usage &amp;gt; 80% for 5 times within 15 cycles then alert&lt;br&gt;    if inode usage &amp;gt; 80% then alert&lt;br&gt;    group server&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Ссылки:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://mmonit.com/monit/"&gt;Официальный сайт monit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://mmonit.com/"&gt;M/Monit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.lissyara.su/?id=1268"&gt;Установка monit на freebsd&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description><category>monit</category><category>monitoring</category><category>syseng</category><guid>/ru/posts/2008/monit/</guid><pubDate>Thu, 27 Nov 2008 17:15:00 GMT</pubDate></item><item><title>Настройка OpenVPN, VPN через http (https) прокси</title><link>/ru/posts/2008/openvpn-vpn-http-https/</link><dc:creator>Vladimir Rusinov</dc:creator><description>&lt;div dir="ltr" style="text-align: left;"&gt;В некоторых сетях единственным доступным сервисом является веб через прокси-сервер. Многие сервисы (ssh, почта, некоторые IM) не могут работать через прокси, но существуют способы пробросить vpn на какой-либо удаленных хост.&lt;br&gt;&lt;br&gt;Итак, после проведения некоторого исследования, выбор пал на openvpn. И вот как я его настраивал:&lt;br&gt;&lt;br&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;1: установка OpenVPN&lt;/h2&gt;&lt;br&gt;У меня было две машины: мой ноутбук (note) и домашний сервер vpn.mydomain.ru (который выполняет у меня функции интернет-шлюза, кешрующего прокси, тестового веб-сервера, файлохранилища, и многого чего другого).&lt;br&gt;&lt;br&gt;Установка и на том и на другом прошла очень легко (строго говоря, он у меня уже был установлен "на всякий случай"):&lt;br&gt;&lt;pre class="brush: bash"&gt;emerge -av1 openvpn&lt;br&gt;&lt;/pre&gt;Отмечу полезный USE-флаг: examples. Он включает установку примеров конфигурационных файлов, которыми можно воспользоваться как основой для написания своих.&lt;br&gt;&lt;br&gt;&lt;h2&gt;2: конфигурация сервера&lt;/h2&gt;&lt;br&gt;Первое что нужно сделать, это сгенерировать все необходимые ключи, это можно сделать с помощью скриптов, входящих в комплект openvpn:&lt;br&gt;&lt;br&gt;&lt;pre class="brush: bash"&gt;cd /usr/share/openvpn/easy-rsa/&lt;br&gt;&lt;br&gt;# инициализация&lt;br&gt;. ./vars&lt;br&gt;./clean-all&lt;br&gt;&lt;br&gt;# эта команда создает Certificate Authority, выполняется интерактивно (т.е. вам нужно будет&lt;br&gt;#ответить на несколько вопросов). Можно оставить все по умолчанию, изменив лишь данные о&lt;br&gt;#географическом положении.&lt;br&gt;# Единственный вопрос, на который следует обратить внимание - Common Name. Не так важно, что вы&lt;br&gt;#туда введте, но он должен быть установлен.&lt;br&gt;./build-ca&lt;br&gt;&lt;br&gt;# генерация пары ключей для сервера&lt;br&gt;./build-key-server server&lt;br&gt;&lt;br&gt;# генерация пары ключей для клиента&lt;br&gt;./build-key note&lt;br&gt;&lt;br&gt;# генерация Diffie Hellman:&lt;br&gt;./build-dh&lt;br&gt;&lt;/pre&gt;&lt;br&gt;После этого в поддиректории keys появятся все необходимые ключи.&lt;br&gt;Переместите их в какое-нибудь надежное и защищеное место.&lt;br&gt;Скопируйте файлы ca.crt и note.* на клиент.&lt;br&gt;&lt;br&gt;Строго говоря, можно было сгенерировать пару ключей на клиенте и передать на сервер публичный ключ для подписи. Но поскольку у меня был защищеный канал (ssh) между клиентом и сервером, я сгенерировал все в одном месте.&lt;br&gt;&lt;br&gt;Далее нужно написать конфигурационный файл для openvpn. У меня получилось так:&lt;br&gt;&lt;pre class="brush: bash"&gt;# биндимся к порту 443, т.к. это единственный порт, на который разрешено делать CONNECT на том прокси-сервере&lt;br&gt;#port 1194&lt;br&gt;port 443&lt;br&gt;&lt;br&gt;# TCP or UDP server?&lt;br&gt;proto tcp&lt;br&gt;;proto udp&lt;br&gt;&lt;br&gt;dev tun&lt;br&gt;&lt;br&gt;# пути к файлам сертификатов&lt;br&gt;ca /etc/openvpn/keys/ca.crt&lt;br&gt;cert /etc/openvpn/keys/server.crt&lt;br&gt;key /etc/openvpn/keys/server.key  # This file should be kept secret&lt;br&gt;dh /etc/openvpn/keys/dh1024.pem&lt;br&gt;&lt;br&gt;# тут важно выбрать такую подсеть, которая не пересекалась бы ни с одной другой используемой вами&lt;br&gt;server 192.168.120.0 255.255.255.0&lt;br&gt;&lt;br&gt;ifconfig-pool-persist ipp.txt&lt;br&gt;&lt;br&gt;# так можно указывать клиенту, какие сети нужно маршритизировать через этот vpn&lt;br&gt;;push "route 192.168.1.0 255.255.255.0"&lt;br&gt;&lt;br&gt;# а так можно указать, что этот vpn следует сделать шлюзом по умолчанию (что нам и нужно)&lt;br&gt;push "redirect-gateway"&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;# Разрешаем клентам взаимодействовать друг с другом, по умолчанию отключено&lt;br&gt;client-to-client&lt;br&gt;&lt;br&gt;# The keepalive directive causes ping-like&lt;br&gt;# messages to be sent back and forth over&lt;br&gt;# the link so that each side knows when&lt;br&gt;# the other side has gone down.&lt;br&gt;# Ping every 10 seconds, assume that remote&lt;br&gt;# peer is down if no ping received during&lt;br&gt;# a 120 second time period.&lt;br&gt;keepalive 10 120&lt;br&gt;&lt;br&gt;# включаем компрессию&lt;br&gt;comp-lzo&lt;br&gt;&lt;br&gt;# так можно указать максимально количество клиентов&lt;br&gt;;max-clients 100&lt;br&gt;&lt;br&gt;# так можно заставить openvpn сбросить права&lt;br&gt;;user nobody&lt;br&gt;;group nobody&lt;br&gt;&lt;br&gt;# The persist options will try to avoid&lt;br&gt;# accessing certain resources on restart&lt;br&gt;# that may no longer be accessible because&lt;br&gt;# of the privilege downgrade.&lt;br&gt;persist-key&lt;br&gt;persist-tun&lt;br&gt;&lt;br&gt;# лог-фай&lt;br&gt;status openvpn-status.log&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Запуск сервера происходит командой openvpn /etc/openvpn/server.conf.&lt;br&gt;Перед запуском надо подгрузить модуль tun.&lt;br&gt;&lt;br&gt;&lt;h2&gt;3: Конфигурация клиента&lt;/h2&gt;&lt;br&gt;Вот конфигурационный файл:&lt;br&gt;&lt;pre class="brush: bash"&gt;client&lt;br&gt;&lt;br&gt;dev tun&lt;br&gt;&lt;br&gt;# указываем протокол и прокси&lt;br&gt;proto tcp&lt;br&gt;http-proxy proxy 3128&lt;br&gt;;http-proxy-retry # retry on connection failures&lt;br&gt;&lt;br&gt;# указываем адрес и порт удаленного сервера&lt;br&gt;remote vpn.mydomain.ru 443&lt;br&gt;&lt;br&gt;resolv-retry infinite&lt;br&gt;nobind&lt;br&gt;&lt;br&gt;# Downgrade privileges after initialization (non-Windows only)&lt;br&gt;;user nobody&lt;br&gt;;group nobody&lt;br&gt;&lt;br&gt;persist-key&lt;br&gt;persist-tun&lt;br&gt;&lt;br&gt;# пути к сертификатам и ключам&lt;br&gt;ca /etc/openvpn/keys/ca.crt&lt;br&gt;cert /etc/openvpn/keys/note.crt&lt;br&gt;key /etc/openvpn/keys/note.key&lt;br&gt;&lt;br&gt;# разрешаем компрессию&lt;br&gt;comp-lzo&lt;br&gt;&lt;/pre&gt;&lt;br&gt;После подгрузки модуля tun и запуска клиента, можно убедиться что интерфейс поднимается, и сервер пингуется.&lt;br&gt;Внимание: после поднятия vpn, openvpn перепишет шлюз по умолчнию, так что нужно заранее добавить статические маршруты (если таковых нету) к прокси-серверу и местной локальным ресурсам.&lt;br&gt;&lt;br&gt;Однако после поднятия vpn, внешние ресурсы все еще не будут работать. А все потому что нужно выполнить шаг&lt;br&gt;&lt;h2&gt;4: настройка NAT&lt;/h2&gt;&lt;br&gt;Во-первых, разрешаем серверу маршрутизировать пакеты. Для этого пишем в /etc/sysctl следующее:&lt;br&gt;&lt;pre class="brush: bash"&gt;net.ipv4.ip_forward = 1&lt;br&gt;net.ipv4.ip_dynaddr = 1&lt;br&gt;&lt;/pre&gt;После чего выполняем sysctl -a.&lt;br&gt;&lt;br&gt;Далее нужно средствами iptables настроить правила маскарадинга. Для этого удобно написать sh-скриптик, который в дальнейшем будет удобно пополнять и редактировать. У меня он имеет примерно такой вид (сокращено):&lt;br&gt;&lt;pre class="brush: bash"&gt;#!/bin/sh&lt;br&gt;&lt;br&gt;# маски используемых сетей&lt;br&gt;IP_LAN="192.168.1.1/24" # моя домашняя сеть&lt;br&gt;IP_PROVIDER="10.0.0.1/8" # локальная сеть провайдера&lt;br&gt;&lt;br&gt;# интерфейсы&lt;br&gt;IF_EXT="eth1" # сюда подключен Ethernet от провайдера&lt;br&gt;IF_LAN="eth0" # сюда подключена локальная сеть&lt;br&gt;IF_INET="ppp0" # сюда "подключен" интернет&lt;br&gt;IF_VPN="tun0" # это интерфейс нашего vpn&lt;br&gt;&lt;br&gt;IPT="iptables"&lt;br&gt;&lt;br&gt;# cleaning:&lt;br&gt;$IPT --flush&lt;br&gt;$IPT -t nat --flush&lt;br&gt;$IPT -t mangle --flush&lt;br&gt;$IPT -X&lt;br&gt;&lt;br&gt;# тут по желанию и степени паранои&lt;br&gt;$IPT -P INPUT ACCEPT&lt;br&gt;$IPT -P OUTPUT ACCEPT&lt;br&gt;$IPT -P FORWARD ACCEPT&lt;br&gt;&lt;br&gt;# allow loopback&lt;br&gt;$IPT -A INPUT -i lo -j ACCEPT&lt;br&gt;$IPT -A OUTPUT -o lo -j ACCEPT&lt;br&gt;&lt;br&gt;###&lt;br&gt;# local host:&lt;br&gt;&lt;br&gt;# allow outgoing connections:&lt;br&gt;$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;&lt;br&gt;# разрешаем подключения к vpn&lt;br&gt;$IPT -A INPUT -p tcp --dport 443 -j ACCEPT&lt;br&gt;&lt;br&gt;# разрешаем NAT из локальной сети и VPN:&lt;br&gt;$IPT -t nat -A POSTROUTING -o $IF_EXT -j MASQUERADE&lt;br&gt;$IPT -t nat -A POSTROUTING -o $IF_INET -j MASQUERADE&lt;br&gt;&lt;br&gt;$IPT -A FORWARD -i $IF_LAN -o $IF_EXT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_EXT -o $IF_LAN -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_LAN -o $IF_INET -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_INET -o $IF_LAN -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;&lt;br&gt;$IPT -A FORWARD -i $IF_VPN -o $IF_EXT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_EXT -o $IF_VPN -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_VPN -o $IF_INET -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;$IPT -A FORWARD -i $IF_INET -o $IF_VPN -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br&gt;&lt;/pre&gt;&lt;br&gt;После выполнения скрипта достаточно сделать &lt;code&gt;/etc/init.d/iptables save&lt;/code&gt; и добавить iptables в runlevel: &lt;code&gt;rc-update add iptables default&lt;/code&gt;&lt;/div&gt;</description><category>network</category><category>openvpn</category><category>proxy</category><category>vpn</category><guid>/ru/posts/2008/openvpn-vpn-http-https/</guid><pubDate>Thu, 09 Oct 2008 18:54:00 GMT</pubDate></item></channel></rss>