7 наиболее распространенных ошибок при установке ограничений памяти Java

Оригинал: "6 Common Errors in Setting Java Heap Size" (кажется, автор несколько ошибся в подсчетах)
Перевод: Владимир Русинов

Для установки размера кучи java (heap) используются две опции: -Xmx для установки максимального размера и -Xms для начального(минимального) размера. Вот наиболее часто встречающиеся ошибки их использования:

1. Отсутствие m, M, g или G в конце (регистр не имеет значения). Например:

java -Xmx128 BigApp
java.lang.OutOfMemoryError: Java heap space

Правильная команда должна быть такой:
java -Xmx128m BigApp
. Строго говоря, -Xmx128 корректная настройка для очень маленьких приложений (например HelloWorld), но я думаю в большинстве случаев все-таки имелось в виду -Xmx128m.


2. Лишний пробел или использование =. Например:

java -Xmx 128m BigApp
Invalid maximum heap size: -Xmx
Could not create the Java virtual machine.

java -Xmx=512m HelloWorld
Invalid maximum heap size: -Xmx=512m
Could not create the Java virtual machine.

Правильная команда должна иметь вид
java -Xmx128m BigApp
, без пробела или знака =. -X опции ведут себя отлично от -Dключ=значение опций, в которых используется =.

3. Установка только -Xms в значение большее чем максимальный размер кучи по умолчанию (64m). Похоже что минимальный размер кучи по умолчанию равен 0.
Пример:
java -Xms128m BigApp
Error occurred during initialization of VM
Incompatible initial and maximum heap sizes specified

Корректная команда должна выглядеть так:
java -Xms128m -Xmx128m BigApp
. Установить минимальный и максимальный размер равными - хорошая идея. В любом случае, минимальное значение не должно превышать максимальное.

4. Установка размера кучи большего чем объем доступной физической памяти. Пример:
java -Xmx2g BigApp
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

Устанавливайте размер кучи меньше чем размер физической памяти:
java -Xmx1g BigApp

5. Использование mb в качестве единицы измерения, вместо m или M.
java -Xms256mb -Xmx256mb BigApp
Invalid initial heap size: -Xms256mb
Could not create the Java virtual machine.

6. Установка размера кучи в большее значение, чем позволяет JVM. Пример:
java -Xmx256g BigApp
Invalid maximum heap size: -Xmx256g
The specified size exceeds the maximum representable size.
Could not create the Java virtual machine.

Укажите размер поменьше:
java -Xmx256m BigApp

7. Указание дробного чиста в качестве значения. Пример:
java -Xmx0.9g BigApp
Invalid maximum heap size: -Xmx0.9g
Could not create the Java virtual machine.

Правильная команда должна выглядеть так:
java -Xmx928m BigApp

PS:

Как установить размер кучи(heap) в Tomcat?

Остановите сервер Tomcat, установите переменную окружения CATALINA_OPTS, затем запустите Tomcat снова. Смотрите файлы tomcat-install/bin/catalina.sh или catalina.bat чтобы узнать как используется эта переменная окружения.

Примеры:
set CATALINA_OPTS=-Xms512m -Xmx512m
(Windows, значение не в кавычках)
export CATALINA_OPTS="-Xms512m -Xmx512m"
(ksh/bash, значение в кавычках)
setenv CATALINA_OPTS "-Xms512m -Xmx512m"
(tcsh/csh, значение в кавычках)

Просмотрев 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 - для опций других приложений.
Я предпочитаю использовать CATALINA_OPTS.

Как установить размер кучи в JBoss?

Остановите Jboss, отредактируйте значения в файле $JBOSS_HOME/bin/run.conf, запустите сервер. Вы можете изменить (или добавить если ее там нет) значение переменной JAVA_OPTS например на такое: JAVA_OPTS="-server -Xms128m -Xmx128m"

Как установить размер кучи в Eclipse?

Запускайте Eclispe с ключем "-vmargs <ваши опции>". Все опции после -vmargs будут интерпретированы как опции JVM.
Пример:
eclipse -vmargs -Xms64m -Xmx256m

Это установит опции для Eclipse, но не для приложения которое Вы разрабатываете в eclipse. Для того чтобы поменять опции приложения, используйте Run As -> Open Run Dialog -> (x)=Arguments -> VM Arguments

Как установить размер кучи в NetBeans?

Закройте NetBeans, отредактируйте файл netbeans-install/etc/netbeans.conf. Пример:
netbeans_default_options="-J-Xms512m -J-Xmx512m -J-XX:PermSize=32m -J-XX:MaxPermSize=128m -J-Xverify:none

Как установить размер кучи в Apache Ant?

Установите переменную окружения ANT_OPTS. Примеры:
set ANT_OPTS=-Xms512m -Xmx512m
(Windows)
export ANT_OPTS="-Xms512m -Xmx512m"
(ksh/bash)
setenv ANT_OPTS "-Xms512m -Xmx512m"
(tcsh/csh)

Как установить размер кучи в JavaEE SDK/J2EE SDK/Glassfish/Sun Java System Application Server?

Остановите сервер приложений, откройте $GLASSFISH_HOME/domains/domain1/config/domain.xml, найдите там XML элемент с именем java-config -> jvm-options. Пример:

-Xmx512m
-XX:NewRatio=2
-XX:MaxPermSize=128m
...


Также вы можете изменять опции через веб-интерфейс администратора, обычно http://localhost:4848/, или https://localhost:4848/. Откройте Application Server в верхней части левой панели, затем на правой панели откройте JVM Settings -> JVM Options, и Вы увидите список текущих опций. Вы можете добавить новые или изменить существующие.

Еще один способ - использование cli комманды. Смотрите справку:
./asadmin help create-jvm-options
./asadmin help delete-jvm-options

Определение размера swap использованого процессом

Стандартные консольные утилиты Linux не показывают количество памяти процесса выгруженой в подкачку (swapped out).

Однако есть достаточно простой способ узнать это. Все что для нужно - взять идентификатор процесса (PID) и просмотреть файл smaps относящийся к этому процессу: ```bash cat /proc/pid/smaps | grep Swap ``` Эта команда выдаст кучу строк, относящихся к разным сегментам памяти. Чтобы просуммировать все можно воспользоваться awk: ```bash cat /proc/pid/smaps | grep Swap | awk '{ SUM += $2 } END { print SUM }' ``` Выведенное число - размер использованого свопа в килобайтах.


// Оригинал: http://linuxgazette.net/164/lg_tips.html

Введение в nginx, часть 2: Другие возможности

Данная статья была опубликована в электронном приложением к журналу "Системный администратор"- "Open Source #042"

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

Failover и балансировка

Крупные проекты редко состоят из одного сервера приложений. Часто их два или больше, и возникает задача балансировки клиентов по этим серверам, а также выполнения failover — необходимо чтобы выход из строя одного из серверов не был заметен для клиентов.
Простейший способ рещить эту задачу — dns round-robin, т.е. назначение доменному имени нескольких ip-адресов. Но это решение имеет ряд недостатков, и гораздо лучше выглядит решение балансировки запросов по бакендам на фронтенде nginx. В конфигурационном файле выглядит это примерно так:

# объявляем upstream — список бакендов
upstream backend {
# перечисляем dns-имена или ip-адреса серверов и их «вес»
server web1 weight=5;
server 1.2.3.4:8080 weight=5;
# а так можно подключаться к бакенду через unix-сокет
server unix:/tmp/backend3 weight=1;
}
# конфигурация виртуального сервера
server {
listen <...>;
server_name myserver.com;
# отправляем все запросы из локейшена / в апстрим
location / {
proxy_pass http://backend;
}
}

Запросы, приходящие к nginx, распределяются по бакендам соответственно указаному весу. Кроме того, можно сделать так, чтобы запросы с одних и тех же IP-адресов отправлялись на одни и те же серверы (для этого в upstream нужно указать директиву ip_hash). Так можно решить проблему с сессиями, но все же лучше найти какой-нибудь способ их репликации или (что еще лучше) использовать RESTful-подход.
В случае, если один из серверов откажется принимать соединения или соединение к нему отвалится по таймауту, он на некоторое время будет исключен из upstream.



Оптимизация nginx


1. Увеличение количества и объема буферов


Для хранения принятых запросов и еще не отданных ответов nginx использует буферы в памяти, а если запрос или ответ не помещается в них, nginx записывает его во временный файл (и пишет при этом предупреждение в log-файл). Поэтому необходимо установить такие размеры, чтобы в большинстве случаев не требовалось обращаться к временному файлу, а с другой стороны — чтобы буферы не использовали слишком много памяти.

Для этого используются следующие параметры:
client_body_buffer_size (по умолчанию: 8k/16k — в зависимости от архитектуры) — задает размер буфера для чтения тела запроса клиента. Обычно стандартного значения хватает, его требуется повышать, только если ваше приложение устанавливает огромные cookies.
proxy_buffer_size (по умолчанию: 4k/8k) — задает размер буфера, в который будет читаться первая часть ответа, получаемого от проксируемого сервера. В этой части ответа находится, как правило, небольшой заголовок ответа. Стандартного значения обычно хватает.
proxy_buffers (по умолчанию: 8 4k/8k) — задает число и размер буферов для одного соединения, в которые будет читаться ответ, получаемый от проксируемого сервера. Установите этот параметр так, чтобы большинство ответов от бэкенда помещалось в буферы.

2. Механизмы обработки соединений


Есть одна тонкость, касающаяся механизма обработки соединений, а именно — способ получения информации о событиях на сокетах. Существуют следующие методы:

  • select — стандартный метод. На большой нагрузке сильно нагружает процессор.
  • poll — стандартный метод. Также сильно нагружает процессор.
  • kqueue — эффективный метод, используемый в операционных системах FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 и Mac OS X. На 2-процессорных машинах под управлением Mac OS X использование kqueue может привести к kernel panic.
  • epoll — эффективный метод, используемый в Linux 2.6+. В некоторых старых дистрибутивах есть патчи для поддержки epoll ядром 2.4.
  • rtsig — real time signals, эффективный метод, используемый в Linux 2.2.19+. При больших количествах одновременных соединений (более 1024) с ним могут быть проблемы (их можно обойти, но на мой взгляд, лучше с этим не связываться).
  • /dev/poll — эффективный метод, используемый в Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ и Tru64 UNIX 5.1A+.

При компиляции nginx автоматически выбирается максимально эффективный найденый метод, однако скрипту configure можно насильно указать какой метод использовать. Если вы решили сделать это, то лучше использовать такие методы:
Linux 2.6: epoll;
FreeBSD: kqueue;
Solaris, HP/UX и другие: /dev/poll;
Linux 2.4 и 2.2: rtsig, не рекомендуется при больших нагрузках.



Включение gzip позволяет сжимать ответ, отправляемый клиенту, что положительно сказывается на удовлетворенности пользователя, но требует больше времени CPU. Gzip включается директивой gzip (on|off). Кроме того, стоит обратить на следующие важные директивы модуля gzip:

gzip_comp_level 1..9 — устанавливает уровень сжатия. Опытным путем выявлено, что оптимальные значения лежат в промежутке от 3 до 5, большие значения дают маленький выигрыш, но создают существенно большую нагрузку на процессор, меньшие — дают слишком маленький коэффициент сжатия.
gzip_min_length (по умолчанию, 0) — минимальный размер ответа, который будет сжиматься. Имеет смысл поставить этот параметр в 1024, чтобы слишком малеьнике файлы не сжимались (т.к. эффективность этого будет мала).
gzip_types mime-тип [mime-тип ...] - разрешает сжатие ответа методом gzip для указанных MIME-типов в дополнение к "text/html". "text/html" сжимается всегда. Имеет смысл добавить такие mime-типы как text/css, text/javascript и подобные. Разумеется, сжимать gif, jpg и прочие уже компрессированые форматы не имеет смысла.

Кроме того, существует модуль gzip_static, который позволяет раздавать уже сжатые статические файлы. В конфирурационном файле это выглядит так:

location /files/ {
gzip on;
gzip_min_length 1024;
gzip_types text/css text/javascript;
gzip_comp_level 5;
gzip_static on;
}

При использовании такой конфигурации в случае запроса «/files/test.html» nginx будет проверять наличие «/files/test.html.gz», и, если этот файл существует и дата его последнего изменения больше, чем дата последнего изменения файла test.html, будет отдан уже сжатый файл, что сохранит ресурсы процессора, которые потребовались бы для сжатия оригинального файла.

Оптимизация приложений


Существует очень полезный трюк, который позволяет указать разработчикам приложений, какие страницы нужно оптимизировать в первую очередь. Для этого потребуется в конфиге nginx указать новый формат лога:

log_format  my_combined  '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$upstream_response_time "$host"'

access_log /var/log/nginx/access_log my_combined;

Переменная $upstream_response_time содержит время ответа бэкенда, поэтому в лог попадает время обработки каждого запроса бэкендом. Далее понадобятся два скрипта:

1. /usr/local/bin/url_stats_report.sh:

#!/bin/sh

echo "=== Requests which took most of the time ===" > /tmp/report.txt
echo "overall time - number of requests - average time - url" >> /tmp/report.txt

cat /var/log/nginx/*access.log | /usr/local/bin/url_stats.py >> /tmp/report.txt
cat /tmp/report.txt | mail -s "url performance report" root

2. /usr/local/bin/url_stats.py:

#!/usr/bin/env python

import sys

urls = {}

try:
while 1:
line = raw_input()
line_arr = line.split(" ")
try:
host = line_arr[-1]
host = host[1:]
host = host[:-1]
url = line_arr[6]
t = float(line_arr[-2])
#print host, url, t

try:
urls[host + url] = (urls[host + url][0] + t, urls[host + url][1] + 1)
except KeyError, e:
urls[host + url] = (t, 1)
except ValueError, e:
pass


except EOFError, e:
pass

def sort_by_value(d):
""" Returns the keys of dictionary d sorted by their values """
items=d.items()
backitems=[ [v[1],v[0]] for v in items]
backitems.sort(reverse=True)
return [backitems[i][1] for i in range(0,len(backitems))]

if (len(sys.argv) > 1):
f = open(sys.argv[1], 'r')
for k in f.readlines():
k = k.strip()
try:
print urls[k][0], urls[k][1], urls[k][0] / urls[k][1], k
except:
print 0, 0, k
else:
i = 0
for k in sort_by_value(urls):
print urls[k][0], urls[k][1], urls[k][0] / urls[k][1], k
i += 1
if i > 100: break

Они не идеальны, но задачу выполняют: запуская /usr/local/bin/url_stats_report.sh (например, в postrotate утилиты logrotate), вы получаете наглядную картину, какие запросы занимают большую часть времени бэкенда.

Кеширование

Незадолго до выхода этой статьи, Игорь Сысоев выпустил версию nginx 0.7.44 с экспериментальной поддержкой кеширования. Из-за большого количества багов, за которкое время было выпущено несколько версий, и в настоящее время последняя версия — 0.7.50 уже достаточно хорошо (хотя и не идеально) работает с кешированием.
Однако это все еще экспериментальная функция, но я решил рассказать о ней, т.к. ее одень давно ждали многое администраторы, да и лично для меня она очень полезна.
Сейчас nginx умеет кешировать на диске ответы от http и fastcgi запросов на бакенды, указывать ключ для кеширования, учитывать заголовки "X-Accel-Expires", "Expires" и "Cache-Control" и вручную устанавливать максимальное время жизни объекта в кеше.
Обслуживанием кеша (очиста старых файлов, наблюдение за размером и т.п.) занимается специальный процесс cache manager. Положительной особенностью реализации является то, что при старте nginx cache manager начинает проверку кеша в фоне, благодаря чему nginx не делает то что называется «дает сквида», т.е. он не висит несколько минут проверяя кеш перед стартом.
Я намеренно не указываю пример конфигурации, т.к. во-первых директивы могут еще поменяться, а во-вторых нужно глубокое понимание механизма кеширования, что требует вдумчивого чтения документации (http://sysoev.ru/nginx/docs/http/ngx_http_proxy_module.html#proxy_cache) и архивов рассылки nginx-ru.

За кадром


В статье освещена лишь та часть возможностей nginx, которыми я пользуюсь чаще всего. За пределами рассказа остались такие вопросы, как поддержка SSI, работа с memcached, экспериментальный встроенный Perl и сторонние модули, реализующие дополнительную функциональность.

Введение в nginx, часть 1

Данная статья была опубликована в электронном приложением к журналу "Системный администратор"- "Open Source #041 (27.03.2009)"

Введение


nginx (engine x) — это HTTP-сервер и IMAP/POP3 прокси-сервер для UNIX-подобных платформ (FreeBSD и GNU/Linux). Nginx начал разрабатываться Игорем Сысоевым, сотрудником компании Рамблер весной 2002 года, а осенью 2004 года появился первый публично доступный релиз. Он, как и все последующие, распространяется под лицензией BSD.
На данный момент nginx работает на большом количестве высоконагруженных сайтов (среди них — Рамблер, Яндекс, В Контакте, wordpress.com, Wrike и другие). Текущая версия, 0.6.x, рассматривается как стабильная с точки зрения надежности, а релизы из ветки 0.7 считаются нестабильными. При этом важно заметить, что функциональность некоторых модулей будет меняться, вследствие чего могут меняться и директивы, поэтому обратной совместимости в nginx до версии 1.0.0 не гарантируется.

Чем же nginx так хорош и почему его так любят администраторы высоконагруженных проектов? Почему бы просто не использовать Apache?



Почему Apache — плохо?


Для начала нужно объяснить, как вообще работают сетевые серверы. Те, кто знаком с сетевым программированием, знают, что по сути существуют три модели работы сервера:
  1. Последовательная. Сервер открывает слушающий сокет и ждет, когда появится соединение (во время ожидания он находится в заблокированном состоянии). Когда приходит соединение, сервер обрабатывает его в том же контексте, закрывает соединение и снова ждет соединения. Очевидно, это далеко не самый лучший способ, особенно когда работа с клиентом ведется достаточно долго и подключений много. Кроме того, у последовательной модели есть еще много недостатков (например, невозможность использования нескольких процессоров), и в реальных условиях она практически не используется.
  2. Многопроцессная (многопоточная). Сервер открывает слушающий сокет. Когда приходит соединение, он принимает его, после чего создает (или берет из пула заранее созданных) новый процесс или поток, который может сколь угодно долго работать с соединением, а по окончании работы завершиться или вернуться в пул. Главный поток тем временем готов принять новое соединение. Это наиболее популярная модель, потому что она относительно просто реализуется, позволяет выполнять сложные и долгие вычисления для каждого клиента и использовать все доступные процессоры. Пример ее использования — Web-сервер Apache. Однако у этого подхода есть и недостатки: при большом количестве одновременных подключений создается очень много потоков (или, что еще хуже, процессов), и операционная система тратит много ресурсов на переключения контекста. Особенно плохо, когда клиенты очень медленно принимают контент. Получаются сотни потоков или процессов, занятых только отправкой данных медленным клиентам, что создает дополнительную нагрузку на планировщик ОС, увеличивает число прерываний и потребляет достаточно много памяти.
  3. Неблокируемые сокеты/конечный автомат. Сервер работает в рамках одного потока, но использует неблокируемые сокеты и механизм поллинга. Т.е. сервер на каждой итерации бесконечного цикла выбирает из всех сокетов тот, что готов для приема/отправки данных с помощью вызова select(). После того, как сокет выбран, сервер отправляет на него данные или читает их, но не ждет подтверждения, а переходит в начальное состояние и ждет события на другом сокете или же обрабатывает следующий, в котором событие произошло во время обработки предыдущего. Данная модель очень эффективно использует процессор и память, но достаточно сложна в реализации. Кроме того, в рамках этой модели обработка события на сокете должна происходить очень быстро — иначе в очереди будет скапливаться много событий, и в конце концов она переполнится. Именно по такой модели работает nginx. Кроме того, он позволяет запускать несколько рабочих процессов (так называемых workers), т.е. может использовать несколько процессоров.

Итак, представим следующую ситуацию: на HTTP-сервер с каналом в 1 Гбит/с подключается 200 клиентов с каналом по 256 Кбит/с:

Что происходит в случае Apache? Создается 200 потоков/процессов, которые относительно быстро генерируют контент (это могут быть как динамические страницы, так и статические файлы, читаемые с диска), но медленно отдают его клиентам. Операционная система вынуждена справляться с кучей потоков и блокировок ввода/вывода.
Nginx в такой ситуации затрачивает на каждый коннект на порядок меньше ресурсов ОС и памяти. Однако тут выявляется ограничение сетевой модели nginx: он не может генерировать динамический контент внутри себя, т.к. это приведет к блокировкам внутри nginx. Естественно, решение есть: nginx умеет проксировать такие запросы (на генерирование контента) на любой другой веб-сервер (например, все тот же Apache) или на FastCGI-сервер.

Рассмотрим механизм работы связки nginx в качестве «главного» сервера и Apache в качестве сервера для генерации динамического контента:

Nginx принимает соединение от клиента и читает от него весь запрос. Тут следует отметить, что пока nginx не прочитал весь запрос, он не отдает его на «обработку». Из-за этого обычно «ломаются» практически все индикаторы прогресса закачки файлов — впрочем, существует возможность починить их с помощью стороннего модуля upload_progress (это потребует модификации приложения).
После того, как nginx прочитал весь ответ, он открывает соединение к Apache. Последний выполняет свою работу (генерирует динамический контент), после чего отдает свой ответ nginx, который его буферизует в памяти или временном файле. Тем временем, Apache освобождает ресурсы.
Далее nginx медленно отдает контент клиенту, тратя при этом на порядки меньше ресурсов, чем Apache.

Такая схема называется фронтэнд + бэкенд (frontend + backend) и применяется очень часто.


Установка


Т.к. nginx только начинает завоевывать популярность, имеются некоторые проблемы с бинарными пакетами, так что будьте готовы к тому, что его придется компилировать самостоятельно. С этим обычно не возникает проблем, надо лишь внимательно прочитать вывод команды ./configure --help и выбрать необходимые вам опции компиляции, например такие:
./configure \
--prefix=/opt/nginx-0.6.x \ # префикс установки
--conf-path=/etc/nginx/nginx.conf \ # расположение конфигурационного файла
--pid-path=/var/run/nginx.pid \ # ... и pid-файла
--user=nginx \ # имя пользователя под которым будет запускаться nginx
--with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module \ # список нужных
--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 # ... и не нужных модулей

После конфигурирования стоит запустить стандартный make && make install, после чего можно пользоваться nginx.
Кроме того в Gentoo вы можете воспользоваться ebuild'ом из стандартного дерева портов; в RHEL/CentOS репозиторием epel (в нем расположени nginx 0.6.x) или srpm для версии 0.7, который можно скачать отсюда: http://blogs.mail.ru/community/nginx; в Debian можно воспользоваться пакетом nginx из ветки unstable.

Конфигурационный файл


Конфигурационный файл nginx очень удобен и интуитивно понятен. Называется он обычно nginx.conf и распологается в $prefix/conf/ если расположение не было переопределено при компиляции. Я люблю класть его в /etc/nginx/, также делают и разработчики всех пакетов упомянутых выше.
Структура конфигурационного файла такова:

user nginx; # имя пользователя, с правами которого будет запускаться nginx
worker_processes 1; # количество рабочих процессов
events {
<...> # в этом блоке указывается механизм поллинга который будет использоваться (см. ниже) и максимальное количество возможных подключений
}

http {
<глобальные директивы http-сервера, например настройки таймаутов и т.п.>;
<почти все из них можно переопределить для отдельного виртуального хоста или локейшена>;

# описание серверов (это то что в apache называется VirtualHost)
server {
# адрес и имя сервера
listen *:80;
server_name aaa.bbb;

<Директивы сервера. Здесь обычно указывают расположение докуменов (root), редиректы и переопределяют глобальные настройки>;

# а вот так можно определить location, для которого можно также переопределить практически все директивы указаные на более глобальных уровнях
location /abcd/ {
<директивы>;
}
# Кроме того, можно сделать location по регулярному выражению, например так:
location ~ \.php$ {
<директивы>;
}
}

# другой сервер
server {
listen *:80;
server_name ccc.bbb;

<директивы>
}
}

Обратите внимание на то, что каждая директива должна оканчиваться точкой с запятой.
Обратное проксирование и FastCGI

Итак, выше мы рассмотрели преимущества схемы frontend + backend, разобрались с установкой, структурой и синтаксисом конфигурационного файла, рассмотрим тепеть как реализовать обратное проксирование в nginx.

А очень просто! Например так:

location / {
proxy_pass http://1.2.3.4:8080;
}

В этом примере все запросы попадающие в location / будут проксироваться на сервер 1.2.3.4 порт 8080. Это может быть как apache, так и любой другой http-сервер.

Однако тут есть несколько тонкостей, связанных с тем, что приложение будет считать, что, во-первых, все запросы приходят к нему с одного IP-адреса (что может быть расценено, например, как попытка DDoS-атаки или подбора пароля), а во-вторых, считать, что оно запущено на хосте 1.2.3.4 и порту 8080 (соответственно, генерировать неправильные редиректы и абсолютные ссылки). Чтобы избежать этих проблем без необходимости переписывания приложения, мне кажется удобной следующая конфигурация:
Nginx слушает внешний интерфейс на порту 80.

Если бэкенд (допустим, Apache) расположен на том же хосте, что и nginx, то он «слушает» порт 80 на 127.0.0.1 или другом внутреннем IP-адресе.

Конфигурация nginx в таком случае выглядит следующим образом:
server {
listen 4.3.2.1:80;
# устанавливаем заголовок Host и X-Real-IP: к каждому запросу отправляемому на backend
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:$proxy_port;
# или «proxy_set_header Host $host;», если приложение будет дописывать :80 ко всем ссылкам
}

Для того, чтобы приложение различало IP-адреса посетителей, нужно либо поставить модуль mod_extract_forwarded (если оно исполняется сервером Apache), либо модифицировать приложение так, чтобы оно брало информацию о IP-адресе пользователя из HTTP-заголовка X-Real-IP.

Другой вариант бэкенд — это использование FastCGI. В этом случае конфигурация nginx будет выглядеть примерно так:

server {
<...>

# location, в который будут попадать запросы на php-скрипты
location ~ .php$ {
fastcgi_pass 127.0.0.1:8888; # определяем адрес и порт fastcgi-сервера,
fastcgi_index index.php; # ...индексный файл

# и некоторые параметры, которые нужно передать серверу fastcgi, чтобы он понял какой скрипт и с какими параметрами выполнять:
fastcgi_param SCRIPT_FILENAME /usr/www/html$fastcgi_script_name; # имя скрипта
fastcgi_param QUERY_STRING $query_string; # строка запроса
# и параметры запроса:
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
}

# благодяря тому что локейшены с регулярными выражениями обладают большим «приоритетом», сюда будут попадать все не-php запросы.
location / {
root /var/www/html/
}

Статика


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

В конфигурационном файле это выглядит примерно так:

server {
listen *:80;
server_name myserver.com;

location / {
proxy_pass http://127.0.0.1:80;
}

# предположим что все статичные файлы лежат в /files
location /files/ {
root /var/www/html/; # указываем путь на фс
expires 14d; # добавляем заголовок Expires:
error_page 404 = @back; # а если файл не найден, отправляем его в именованный локейшн @back
}

# запросы из /files, для которых не было найдено файла отправляем на backend, а он может либо сгенерировать нужный файл, либо показать красивое сообщение об ошибке
location @back {
proxy_pass http://127.0.0.1:80;
}

Если вся статика не помещена в какой-то определенный каталог, то воспользоваться регулярным выражением:

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js)$ {
# аналогично тому что выше, только в этот location будут попадать все запросы оканчивающиеся на одно из указаных суффиксов
root /var/www/html/;
error_page 404 = @back;
}

К сожалению, в nginx не реализована асинхронная работа с файлами. Иными словами, nginx worker блокируется на операциях ввода-вывода. Так что если у вас очень много статических файлов и, в особенности, если они читаются с разных дисков, лучше увеличивать количество рабочих процессов (до числа, которое в 2—3 раза больше, чем суммарное число головок на диске). Это, конечно, ведет к увеличению нагрузки на ОС, но в целом производительность увеличивается. Для работы с типичным количеством статики (не очень большое количество сравнительно небольших файлов: CSS, JavaScript, изображения) вполне хватает одного-двух рабочих процессов.

To be continued


Продолжение статьи уже можно прочитать на этом сайте или в "OpenSource" #042.

Ссылки


Тут можно найти дополнительноую информацию о nginx:

официальный сайт nginx
сайт Игоря Сысоева
Nginx Wiki
nginx с дополнительными сторонними модулями
src.rpm для последних версий nginx
еще несколько хороших ссылок
список рассылки nginx-ru

Denyhosts - блокировка перебора паролей SSH

Denyhosts - полезная утилита для пресечения попыток подобрать пароль к ssh.

Устанавливается без каких-либо проблем: emerge -av denyhosts в Gentoo, для других дистрибутивов пакеты также существуют и как правило находятся в основном репозитории.

Denyhosts работает следующим образом: он проверяет системный журнал и добавляет в /etc/hosts.deny IP адреса, с которых наблюдается много попыток неудачного входа. Для того чтобы это работало, SSH должен быть собран с tcp_wrappers (что всегда разумно и делается по умолчанию).

У Denyhosts достаточно гибкие настройки, можно указать после скольких неудачных попыток блокировать хост, на какой период это делать и т.п. Настойки по умолчанию на мой взгляд чересчур суровы, поэтому имеет смысл отредактировать файл /etc/denyhosts.conf, который весьма прост для понимания и имеет подробные комментарии.

Есть два способа запустить Denyhosts: в качестве демона или в качестве cron-задания. Памяти он потребляет немного, поэтому проще первое:

/etc/init.d/denyhosts start
rc-upade add denyhosts default

Оптимизация производительности Apache

Введение


По данным Netcraft, Apache - самый популярный веб-сервер в интернет, он обслуживает множество серверов и сайтов. Часто возникает необходимость увеличить производительность веб-сервера. Наверное лучший способ это сделать - перейти к схеме frontend+backend, но это может потребовать достаточно серьезных изменений в приложении (например, у вас наверняка отвалятся всяческие индикаторы прогресса аплоада файлов).

Другой способ - просто увеличить производительность сервера - поставить более быстрый процессор и больше памяти.

Однако и первое и второе требует много времени и ресурсов, так что на первое время можно попробовать ускорить apache путем оптимизации его конфигурации. Существуют оптимизации, которые можно применить только при пересборке apache, другие же можно применять без перекомпиляции сервера.

Загружайте только необходимые модули


Apache - модульная программа, бОльшая часть функций которой реализуется в модулях. При этом эти модули могут быть как вкомпилированы, так и собраны в виде DSO - динамических библиотеках. Большинство современных дистрибутивов поставляет apache с набором DSO, так что не нужные модули можно легко отключить без перекомпиляции.

Запускайте apache только с необходимыми модулями, чтобы уменьшить потребление памяти. Если вы решили скомпилировать apache самостоятельно, то либо тщательно подходите к выбору списка модулей, которые вы включите, либо компилируйте их как DSO используя apxs в apache1 и apxs2 в apache2. Для того чтобы отключить ненужные DSO-модули, достаточно закомментировать лишние строчки LoadModule в httpd.conf. Apache со статически скомпилированными модулями будет потреблять чуть меньше памяти, однако вам придется каждый раз его перекомпилировать для изменения списка модулей.



Выберете подходящий MPM


В apache каждый запрос обрабатывается в своем процессе или потоке. При компиляции apache позволяет выбирать один из нескольким MPM (Multi-processing module), которые отвечают за прослушивание портов, прием запросов и раздачу этих запросов дочерним процессам или потокам, в которых эти запросы будут обработаны.

Выбор MPM зависит от нескольких факторов, таких как наличие поддержки потоков в ОС, количества свободной памяти, а также требований стабильности и безопасности.

Если безопасность очень важна, следует выбрать peruser MPM, пожертвовав производительностью.

Если важна именно производительность, то выбор ограничивается двумя mpm: prefork и worker.

Worker - поточный MPM, т.е. в нем каждый запрос обслуживается в отдельном потоке одного из дочерних процессов. Потоки - более легкие для ОС объекты, чем процессы, они более эффективно используют память и переключения контекста для них происходят быстрее. Однако, из-за того что каждый поток имеет доступ ко всей памяти процесса, worker mpm более подвержен сбоям: сбой одного потока может повлечь падение всего процесса, в котором находился этот поток (именно поэтому worker mpm запускает несколько дочерних процессов с несколькими потоками в каждом).

Perfork - mpm использует несколько дочерних процессов, каждый дочерний процесс обрабатывает одно подключение. Из-за того что процесс - более тяжелая структура, он использует немного больше ресурсов, зато он менее подвержен сбоям - обработка каждого отдельного запроса не зависит от других процессов.

К сожалению, для смены mpm требуется перекомпиляция apache. Тут проявляют свои достоинства source-based дистрибутивы: вы можете легко перекомпилировать apache и все зависимые от него пакеты, не превратив систему в свалку. Бинарные дистрибутивы выходят из этой ситуации по-разному. Например в RHEL в apache rpm находится сразу две версии apache - с worker и prefork mpm (prefork используется по умолчанию). Однако worker mpm не поддерживает php. Так что если вы хотите php и worker mpm вам придется компилировать его самостоятельно либо искать сторонние репозитории.

DNS запросы


Директива HostnameLookups включает reverse DNS запросы, так что в логи будут попадать dns-имена клиентов вместо ip-адресов. Разумеется, что это существенно замедляет обработку запроса, т.к. запрос не обрабатывается пока не будет получен ответ от DNS-сервера. Поэтому следите чтобы эта директива всегда была выключена (HostnameLookups Off), а если вам все-таки нужны dns-адреса, вы можете узнать их позже, прогнав лог в утилите logresolve (которая поставляется с apache).

Кроме того, следите чтобы в директивах Allow from и Deny From использовались ip-адреса а не доменные имена. Иначе apache будет делать два dns запроса (обратный и прямой) чтобы убедиться что клиент-тот за кого себя выдает.

AllowOverride


Если директива AllowOverride не установлена в 'None', apache будет пытаться открыть .htaccess файлы в каждой директории которую он посещает и во всех директориях выше нее. Например:

DocumentRoot /var/www/html
<Directory /var/www/html/>
AllowOverride all
</Directory>

Если будет запрошен /index.html, apache попытается открыть (и интерпретировать) файлы /.htaccess, /var/.htaccess, /var/www/.htaccess, и /var/www/html/.htaccess. Это увеличивает время обработки запроса. Так что, если вам нужен .htaccess только для одной директории, разрешайте его только для нее:

DocumentRoot /var/www/html
<Directory />
AllowOverride None
</Directory>
<Directory /var/www/html/>
AllowOverride all
</Directory>

FollowSymLinks и SymLinksIfOwnerMatch


Если для директории включена опция FollowSymLinks, сервер будет следовать по символическим ссылкам в этой директории. Если для директории включена опция SymLinksIfOwnerMatch, apache будет следовать по символическим ссылкам только если владелец файла или директории, на которую указывает эта ссылка совпадает с владельцем указанной директории. Так что при включенной опции SymLinksIfOwnerMatch apache делает больше системных запросов.

Кроме того, дополнительные системные запросы требуются когда FollowSymlinks НЕ УСТАНОВЛЕН. Т.о. наиболее оптимальная ситуация для производительности - когда опция FollowSymlinks включена.

Content Negotiatio


Старайтесь избегать content negotiaion.

MaxClients


Директива MaxClients устанавливает максимальное количество параллельных запросов, которые будет поддерживать сервер. Apache не будет порождать больше процессов/потоков чем MaxClients. Значение MaxClient не долно быть слишком маленьким (иначе много клиентов останутся необслуженными), но и не стоит устанавливать слишком большое количество - лучше не обслужить часть клиентов чем исчерпать все ресурсы, залезть в своп и умереть под нагрузкой. Хорошим может быть значение MaxClients = количество памяти выделенное под веб-сервер / максимальный размер порожденного процесса или потока. Для статических файлов apache использует около 2-3 Мб на процесс, для динамики (php, cgi) - зависит от скрипта, но обычно около 16-32 Мб.

Вы можете прикинуть примерный размер посмотрев на колонку rss в выводе `ps -ylC httpd --sort:rss`

Если сервер уже обслуживает MaxClients запросов, новые запросы попадут в очередь, размер которой устанавливается с помощью директивы ListenBacklog.

MinSpareServers, MaxSpareServers, и StartServers


Т.к. создание потока, и особенно процесса - дорогая операция, apache создает их заранее. Директивы MaxSpareServers и MinSpareServers устанавливают как много процессов/потоков должны ожидать в готовности принять запрос (максимум и минимум). Если значение MinSpareServers слишком маленькое и неожиданно приходит много запросов, apache вынужден будет создавать много новых процессов/потоков, что создаст дополнительную нагрузку в этой стрессовой ситуации. С другой стороны, если MaxSpareServers слишком велико, apache будет сильно нагружать систему этими процессами, даже если количество клиентов минимально.

Постарайтесь установить такие MinSpareServers и MaxSpareServers, чтобы apache не создавал более 4 процессов/потоков в секунду. Если он создаст более 4, в ErrorLog будет помещено сообщение об этом. Это - сигнал того что MinSpareServers слишком мало.

MaxRequestsPerChild


Директива MaxRequestsPerChild устанавливает сколько запросов может обработать один дочерний процесс/поток прежде чем он будет завершен. По умолчанию значение этой директивы установлено в 0, что означает что однажды созданный процесс/поток не будет завершен никогда (ну кроме случаев остановки сервера или краха этого процесса/потока). Рекомендую установить MaxRequestsPerChild равное какому-нибудь достаточно большому числу (несколько тысяч). Это не создаст излишней нагрузки, связаной с тем что apache будет вынужден создавать новые дочерние процессы, в то же время это поможет избавиться от проблем с утечкой памяти в дочерних процессах (что очень возможно например если вы используете нестабильную версию php).

KeepAlive и KeepAliveTimeout


KeepAlive позволяет делать несколько запросов в одном TCP-подключении. Это особенно полезно для html-страниц с большим количеством изображений. Если KeepAlive установлен в Off, то для самой страницы и для каждого изображения будет создано отдельное подключение (которое нужно будет обработать master-процессу), что плохо и для сервера и для клиента. Так что для подобных случаев рекомендуется устанавливать KeepAlive в On. Для других применений (например для download-сервера) KeepAlive может быть бесполезен и даже вреден, т.к. при включенном KeepAlive сервер закрывает соединение не сразу, а ждет KeepAliveTimeout секунд нового запроса. Для того чтобы процессы не висели слишком долго в бесполезном ожидании, устанавливайте KeepAliveTimeout достаточно малым, около 5-10 секунд обычно достаточно.

Сжатие


HTTP-сжатие было определено в стандарте HTTP/1.1, и сейчас все современные клиентские программы и практически все сервера его поддерживают. Сервер может отдавать ответ в gzip или deflate, а клиентская программа незаметно для пользователя разжимает данные. Это уменьшает количество передаваемого трафика (до 75%), но конечно же повышает использование процессора.
Однако если ваш сервер посещает много клиентов с медленным подключение, сжатие может снизить нагрузку с вашего сервера из-за того что сервер сможет быстрее передать сжатый ответ и освободить ресурсы, занятые дочерним процессом. Особенно сильно этот эффект может быть заметен если у вас быстрый процессор, но мало памяти.

Кеширование конфигурируется директивами модуля mod_deflate. Имейте в виду, что не следует устанавливать степень сжатия gzip более 4-5 - это потребует существенно большего времени CPU, а эффект будет достаточно невелик. Ну и разумеется не нужно пытаться сжать изображения в jpg, gif и png, музыку, видео файлы и все другие бинарные файлы, которые уже и так хорошо сжаты.

Кеширование на стороне клиента


Не забывайте устанавливать Expires заголовки на статические файлы (см. модуль mod_expires). Если файл не изменяется, то его всегда следует попробовать закешировать на клиенте. Тогда у клиента будут быстрее загружаться страницы, а сервер освободится от лишних запросов.

Оригинал: "Configuring Apache for Maximum Performance". Vishnu Ram V: http://linuxgazette.net/123/vishnu.html

запускать задачу раз в месяц в субботу

Часто необходимо запускать что-то (например полный бекап бд) раз в месяц, но в выходной, допустим в ночь с субботы на воскресенье.

Это можно сделать в crontab следующим образом

0 23 * * 6 [`date "+%d"` -lt 8] && /path/to/script

Это запустит скрипт в первую субботу месяца в 23:00.

Monit: простое средство мониторинга

Monit - достаточно простое, но одновременно удобное, достаточно мощное и надежное средство для мониторинга ваших серверов.
Monit умеет мониторить:

  • процессы (наличие, количество потребляемых ресурсов)
  • файлы, директории и файловые системы на изменения (дата создания/изменения, изменения размера и контрольной суммы)
  • сетевые хосты (пинг и коннект на определенный порт по определенному протоколу)
При возникновении проблемы monit отправляет e-mail (шаблоны можно модифицировать) и может перезапустить сервис.
В monit встроен простенький веб-сервер, который позволяет посмотреть состояние объектов мониторинга, включить/выключить определенный объект.
Monit умеет перезапускать сервисы если они падают или не выполняется какое-то условие.

Monit построен с идеей того что система мониторинга должна быть максимально надежной и простой. И это действительно выполняется: на monit можно положиться.

Конечно из-за своей простоты monit не обладает тем количеством возможностей, которыми обладают Enterptise-системы мониторинга. Однако существует дополнение к monit под названием M/Monit, которое позволяет управлять несколькими серверами с monit из одного места. К сожалению, M/Monit распространяется под коммерческой лицензией и за деньги.

Посмотрим что он умеет:

Установка проста:

emerge -av monit

После этого вам необходимо отредактировать файл /etc/monitrc. Он достаточно хорошо документирован и там много примеров, вот еще несколько:

/etc/monitrc

set daemon  120 # проверять объекты каждые 2 минуты
set logfile syslog facility log_daemon

set mailserver localhost # тут для большей надежности можно указать несколько smtp-серверов
set eventqueue # задаем очередь сообщений - чтобы monit мог отправить алерт позже, если в данный момент почтовый сервер не доступен
basedir /var/monit
slots 10
set mail-format { from: monit@ myserver.com }
set alert admin1 admin2 # список получателей алертов

# конфигурация встроенного http сервера
set httpd port 2812 and
use address 0.0.0.0
allow 1.2.3.4
allow admin:password

include /etc/monit.d/*

/etc/monit.d/system
# проверка общих ресурсов сервера
check system myserver
if loadavg (1min) > 30 then alert
if loadavg (5min) > 20 then alert
if memory usage > 75% then alert
if cpu usage (user) > 70% then alert

# проверка apache2:
check process apache with pidfile /var/run/apache2.pid
start program = "/etc/init.d/apache2 start"
stop program = "/etc/init.d/apache2 stop"
if totalmem > 500.0 MB for 5 cycles then restart
if children > 250 then restart
if loadavg(5min) greater than 30 for 8 cycles then stop
if failed host myserver.com port 80 protocol http
and request "/index.html"
then restart
if failed port 443 type tcpssl protocol http
with timeout 15 seconds
then restart
if 3 restarts within 5 cycles then timeout


# проверка свободного места на фс
check device data with path /dev/sdb1
start program = "/bin/mount /data"
stop program = "/bin/umount /data"
if space usage > 80% for 5 times within 15 cycles then alert
if inode usage > 80% then alert
group server

Ссылки:

Настройка OpenVPN, VPN через http (https) прокси

В некоторых сетях единственным доступным сервисом является веб через прокси-сервер. Многие сервисы (ssh, почта, некоторые IM) не могут работать через прокси, но существуют способы пробросить vpn на какой-либо удаленных хост.

Итак, после проведения некоторого исследования, выбор пал на openvpn. И вот как я его настраивал:



1: установка OpenVPN


У меня было две машины: мой ноутбук (note) и домашний сервер vpn.mydomain.ru (который выполняет у меня функции интернет-шлюза, кешрующего прокси, тестового веб-сервера, файлохранилища, и многого чего другого).

Установка и на том и на другом прошла очень легко (строго говоря, он у меня уже был установлен "на всякий случай"):
emerge -av1 openvpn
Отмечу полезный USE-флаг: examples. Он включает установку примеров конфигурационных файлов, которыми можно воспользоваться как основой для написания своих.

2: конфигурация сервера


Первое что нужно сделать, это сгенерировать все необходимые ключи, это можно сделать с помощью скриптов, входящих в комплект openvpn:

cd /usr/share/openvpn/easy-rsa/

# инициализация
. ./vars
./clean-all

# эта команда создает Certificate Authority, выполняется интерактивно (т.е. вам нужно будет
#ответить на несколько вопросов). Можно оставить все по умолчанию, изменив лишь данные о
#географическом положении.
# Единственный вопрос, на который следует обратить внимание - Common Name. Не так важно, что вы
#туда введте, но он должен быть установлен.
./build-ca

# генерация пары ключей для сервера
./build-key-server server

# генерация пары ключей для клиента
./build-key note

# генерация Diffie Hellman:
./build-dh

После этого в поддиректории keys появятся все необходимые ключи.
Переместите их в какое-нибудь надежное и защищеное место.
Скопируйте файлы ca.crt и note.* на клиент.

Строго говоря, можно было сгенерировать пару ключей на клиенте и передать на сервер публичный ключ для подписи. Но поскольку у меня был защищеный канал (ssh) между клиентом и сервером, я сгенерировал все в одном месте.

Далее нужно написать конфигурационный файл для openvpn. У меня получилось так:
# биндимся к порту 443, т.к. это единственный порт, на который разрешено делать CONNECT на том прокси-сервере
#port 1194
port 443

# TCP or UDP server?
proto tcp
;proto udp

dev tun

# пути к файлам сертификатов
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key # This file should be kept secret
dh /etc/openvpn/keys/dh1024.pem

# тут важно выбрать такую подсеть, которая не пересекалась бы ни с одной другой используемой вами
server 192.168.120.0 255.255.255.0

ifconfig-pool-persist ipp.txt

# так можно указывать клиенту, какие сети нужно маршритизировать через этот vpn
;push "route 192.168.1.0 255.255.255.0"

# а так можно указать, что этот vpn следует сделать шлюзом по умолчанию (что нам и нужно)
push "redirect-gateway"



# Разрешаем клентам взаимодействовать друг с другом, по умолчанию отключено
client-to-client

# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120

# включаем компрессию
comp-lzo

# так можно указать максимально количество клиентов
;max-clients 100

# так можно заставить openvpn сбросить права
;user nobody
;group nobody

# The persist options will try to avoid
# accessing certain resources on restart
# that may no longer be accessible because
# of the privilege downgrade.
persist-key
persist-tun

# лог-фай
status openvpn-status.log

Запуск сервера происходит командой openvpn /etc/openvpn/server.conf.
Перед запуском надо подгрузить модуль tun.

3: Конфигурация клиента


Вот конфигурационный файл:
client

dev tun

# указываем протокол и прокси
proto tcp
http-proxy proxy 3128
;http-proxy-retry # retry on connection failures

# указываем адрес и порт удаленного сервера
remote vpn.mydomain.ru 443

resolv-retry infinite
nobind

# Downgrade privileges after initialization (non-Windows only)
;user nobody
;group nobody

persist-key
persist-tun

# пути к сертификатам и ключам
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/note.crt
key /etc/openvpn/keys/note.key

# разрешаем компрессию
comp-lzo

После подгрузки модуля tun и запуска клиента, можно убедиться что интерфейс поднимается, и сервер пингуется.
Внимание: после поднятия vpn, openvpn перепишет шлюз по умолчнию, так что нужно заранее добавить статические маршруты (если таковых нету) к прокси-серверу и местной локальным ресурсам.

Однако после поднятия vpn, внешние ресурсы все еще не будут работать. А все потому что нужно выполнить шаг

4: настройка NAT


Во-первых, разрешаем серверу маршрутизировать пакеты. Для этого пишем в /etc/sysctl следующее:
net.ipv4.ip_forward = 1
net.ipv4.ip_dynaddr = 1
После чего выполняем sysctl -a.

Далее нужно средствами iptables настроить правила маскарадинга. Для этого удобно написать sh-скриптик, который в дальнейшем будет удобно пополнять и редактировать. У меня он имеет примерно такой вид (сокращено):
#!/bin/sh

# маски используемых сетей
IP_LAN="192.168.1.1/24" # моя домашняя сеть
IP_PROVIDER="10.0.0.1/8" # локальная сеть провайдера

# интерфейсы
IF_EXT="eth1" # сюда подключен Ethernet от провайдера
IF_LAN="eth0" # сюда подключена локальная сеть
IF_INET="ppp0" # сюда "подключен" интернет
IF_VPN="tun0" # это интерфейс нашего vpn

IPT="iptables"

# cleaning:
$IPT --flush
$IPT -t nat --flush
$IPT -t mangle --flush
$IPT -X

# тут по желанию и степени паранои
$IPT -P INPUT ACCEPT
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD ACCEPT

# allow loopback
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT

###
# local host:

# allow outgoing connections:
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

# разрешаем подключения к vpn
$IPT -A INPUT -p tcp --dport 443 -j ACCEPT

# разрешаем NAT из локальной сети и VPN:
$IPT -t nat -A POSTROUTING -o $IF_EXT -j MASQUERADE
$IPT -t nat -A POSTROUTING -o $IF_INET -j MASQUERADE

$IPT -A FORWARD -i $IF_LAN -o $IF_EXT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_EXT -o $IF_LAN -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_LAN -o $IF_INET -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_INET -o $IF_LAN -m state --state ESTABLISHED,RELATED -j ACCEPT

$IPT -A FORWARD -i $IF_VPN -o $IF_EXT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_EXT -o $IF_VPN -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_VPN -o $IF_INET -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_INET -o $IF_VPN -m state --state ESTABLISHED,RELATED -j ACCEPT

После выполнения скрипта достаточно сделать /etc/init.d/iptables save и добавить iptables в runlevel: rc-update add iptables default