Руководство по настройке Linux Web сервера

Материал из I2P-ilita вики
Перейти к навигацииПерейти к поиску
Zrada.png ЗРАДА!

Информация была грубо перекатана со свидомой википедии.
Требуется дополнить её фактами, разбавить картинками, переписать или хотя бы почистить от мусора.

Информация в данной статье несколько устарела

Ибо нет ничего вечного. Меняются версии софта, меняются принципы архитектуры. Например сейчас для php-fpm уже не нужен отдельный скрипт, всё есть в специальном пакете. Для справки и общего хода мыслей всё еще годится, но для практического применения не помешает погуглить перед совершением действий.

Предисловие[править]

Итак, я решил обобщить свой опыт по развёртыванию веб-сервера на основе Linux, который мог бы работать в сети I2P. В принципе ничего необыкновенного или сверхъестественного, но задокументировать смысл имеет. В принципе данный набор позволяет серверу выносить весьма серьёзные нагрузки. Ресурсоёмкость описанной системы - 200-220 Mb в оперативной памяти, без использования swap. На планке оперативки в 512 Мб (которая стоит в сервере сейчас) остаётся ещё очень неплохой запас по ресурсам (в отличие от Windows 2003, которая кушала файл подкачки неимоверно, и неимоверно же тормозила).

Часть руководства почерпнута отсюда, часть является специфичной для I2P.

Подготовка[править]

Описываемый сервер развёрнут на следующей платформе: 

  • ОС: Linux, Debian 6 (однако часть примеров команд в консоли приведена для старой платформы - CentOS с менеджером пакетов Yum. Не было времени поправить)
  • Веб-сервер: nginx 1.0.0 1.0.5
  • MySQL: 5+,
  • PHP в режиме FastCGI. Посредников и иных backend'ов типа Apache - нет. Дополнительно установлен XCache с кэшированием и оптимизацией в память.
  • I2P Router 0.9.3
  • Аппаратная часть всё та же: 512 ОЗУ, 2,4 ГГц проц Pentium, HDD 160 Gb.

Для начала, собственно, требуется установить CentOS (подойдет любой дистрибутив, на самом деле). На чисто серверной машине графический интерфейс не нужен, потому по умолчанию пакеты типа KDE || Gnome не ставим. Плюс вообще можно систему облегчить, пробежавшись по списку пакетов при установке. Очень рекомендую создать дополнительную файловую систему и монтировать её как /www - в ней мы будем хранить все ресурсы веб.

Настройка сервера[править]

Установка и настройка Nginx[править]

Есть куча любителей поставить софт на сервер/рабочую машинку из исходников. Хозяин барин, конечно, но я этого делать не рекомендую. Во-первых, усложняется обновление софта. Каждый раз придётся ручками пересобирать всё. В случае с установкой из репозитория - всё проще: yum update. Но с другой стороны, если вам нужны какие-то специфические модули nginx, или иные особенности конфигурирования, то всё равно придётся собирать.

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

Для 32-разрядных систем: Шаблон:LinuxConsole

Для 64-разрядных систем:

Шаблон:LinuxConsole

Если команда yum search nginx после этого ничего не нашла, то надо проверить файл в директории /etc/yum.repos.d/ с именем centalt.repo:

Шаблон:LinuxConsole

Если его там нет - надо создать: Шаблон:LinuxConsole

И добавить туда строки:

[CentALT] 
name=CentALT Packages for Enterprise Linux 5 - $basearch
baseurl=http://centos.alt.ru/repository/centos/5/$basearch/
enabled=1
gpgcheck=0 

(кто не знает как работать в vim, сначала надо нажать клавишу i, чтобы войти в режим редактирования. Когда вы внесли изменения - Esc, а затем последовательно наберите :w!  Enter, :q! Enter) Но первый способ весьма предпочитительнее - если он не сработал, значит что-то не так.

Всё. устанавливайте nginx:

Шаблон:LinuxConsole

Настроим автозапуск:

Шаблон:LinuxConsole

Управление Nginx производится путём подачи сигналов типа:

Шаблон:LinuxConsole


Конфигурирование виртуальных хостов и реврайтов[править]

Конфиг внизу - устарел. Новая версия вики с ним уже не работает, так как там появился злобный ResourceLoader. Речь идёт только о движке MediaWiki - в общем случае данный конфиг работает.

Чтобы долго не описывать сам процесс, приведу пример конфига этой вики. Как правило конфиг виртуальных хостов лежит в /etc/nginx/conf.d/virtual.conf Кстати, почитать по поводу конфига nginx можно, например, тут.

По образу и подобию можно создавать произвольное количество виртуальных хостов для ваших проектов. Кстати - {PATH_TO_YOU_WWW_DIR} - надо заменить на реальный путь к директории, где находится корневой каталог вашего приложения.

################################################################################################
## Тащемта, Rus.I2P сайт.
################################################################################################
server {
    listen 80;
    #listen rus.i2p:80;
    server_name rus.i2p alias www.rus.i2p;
    charset utf-8;

    # Сжимать передаваемые данные
    gzip on;
    # Задайте уровень сжатия от 1 до 9
    # Т.к. посетителей очень ма-а-а-ало,
    # а сеть очень ме-е-е-едленная, лучше 9
    gzip_comp_level 9;

    location / {
        root {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs;
        index index.html index.php;
        rewrite ^/wiki/([^?]*)(?:\?(.*))? /wiki/index.php?title=$1&$2;
        allow 127.0.0.1;     # Разрешаем коннект только с локалхоста.
        deny all;
    }

    location /skins {
        root {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs;
    }
    location /images {
        root {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs;
    }

    error_page 404 /404.html;

    location = /404.html {
            root {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs;
    }

    # Настройки для связки с PHP-FastCGI
    location ~ \.php$ {
            root                {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs;
            fastcgi_pass        127.0.0.1:9000;
            fastcgi_index       index.php;
            fastcgi_param       SCRIPT_FILENAME {PATH_TO_YOU_WWW_DIR}/rusi2p/htdocs/index.php$fastcgi_script_name;
            include             fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one

    location ~ /\.ht {
        deny  all;
    }
}
##==============================================================================================
## / END OF Rus.I2P
##==============================================================================================

В целом, если вам не хочется отказываться от любимого Apache, можно настраивать и на основе него, никаких проблем (если только не дорожите каждым мегабайтом оперативки, но то уже случай тяжёлый и требующий индивидуального подхода) - разницы во "фронте" никакой не будет. Вряд ли на вашем сервере будет такая нагрузка, что Apache с ней не справится (скорее загнётся i2p роутер, что, впрочем, тоже вряд ли). Тем более, что конфигурирование Apache + PHP Module - ощутимо более просто и распространённо.

Установка и настройка MySQL[править]

Собственно, нет ничего проще: 

Шаблон:LinuxConsole

Единственное, потом надо задать рутовый пароль, естественно, и создать требуемые базы. Кроме того, никто не мешает вам выбрать другую БД, например PostgreSQL или Oracle - при этом не надо ложного снобизма. PostgreSQL|Oracle имеет смысл использовать тогда, когда вы планируете задействовать его мощнейший встроенный язык хранимых процедур - PL/SQL. Если нет, и вы просто планируете хранить там данные - да используйте MySQL - он обеспечивает с лихвой все обычные потребности среднего веб-проекта.

Установка и настройка PHP - FastCGI + XCache[править]

Для начала требуется поставить сам PHP с модулями. В список модулей добавляем всё то, что вам нужно. Данный пример невозбранно содран из интернетов (с http://www.itpad.ru/?p=1960). По нему и rus.i2p настраивался. Какие именно модули там ставились точно я не помню, да это и не важно.

Шаблон:LinuxConsole

В него добавим следующее:

#!/bin/sh
. /etc/rc.d/init.d/functions

. /etc/sysconfig/network

[ "$NETWORKING" = "no" ] && exit 0

spawnfcgi="/usr/bin/spawn-fcgi"
php_cgi="/usr/bin/php-cgi"
prog=$(basename $php_cgi)
server_ip=127.0.0.1
server_port=9000
server_user=nginx
server_group=nginx
server_childs=5
pidfile="/var/run/php_cgi.pid"

[ -f /etc/sysconfig/phpfastcgi ] && . /etc/sysconfig/phpfastcgi

start() {
[ -x $php_cgi ] || exit 1
[ -x $spawnfcgi ] || exit 2
echo -n $"Starting $prog: "
daemon $spawnfcgi -a ${server_ip} -p ${server_port} -u ${server_user} 
-g ${server_group} -P ${pidfile} -C ${server_childs} -f ${php_cgi}
retval=$?
echo
return $retval
}

stop() {
echo -n $"Stopping $prog: "
killproc -p ${pidfile} $prog -QUIT
retval=$?
echo
[ -f ${pidfile} ] && /bin/rm -f ${pidfile}
return $retval
}

restart(){
stop
sleep 2
start
}

rh_status(){
status -p ${pidfile} $prog
}
case "$1" in
start)
start;;
stop)
stop;;
restart)
restart;;
status)
rh_status;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
exit 3
esac


Затем, добавляем скрипту право на запуск и добавляем в автозагрузку

Шаблон:LinuxConsole

Собственно, если вы внимательно посмотрите выше на конфиг nginx-а, то увидите, где в настройке сервера указывается, что работать надо с php-FastCGI.

XCache[править]

Тащемта, просто неиллюзорно:

Шаблон:LinuxConsole

И устанавливаем следующие настройки (или отредактируйте по желанию, с условием понимания, что вы делаете):

[xcache-common]
zend_extension = /usr/lib/php/modules/xcache.so
[xcache.admin]
xcache.admin.auth = On
xcache.admin.user = "admin"

; xcache.admin.pass should be md5($your_password), or empty to disable administration.
xcache.admin.pass = "<md5_password_hash>"
xcache.test =       Off
;xcache.coredump_directory = ""

[xcache]
xcache.cacher =               On
xcache.size  =              100M
xcache.count =                 1
xcache.slots =                8K
xcache.ttl   =              3600
xcache.gc_interval =         300

; Same as aboves but for variable cache
; If you don't know for sure that you need this, you probably don't
xcache.var_size  =            4M
xcache.var_count =             1
xcache.var_slots =            8K
xcache.var_ttl   =          3600
xcache.var_maxttl   =       3600
xcache.var_gc_interval =     300

; N/A for /dev/zero
xcache.readonly_protection = Off

; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection
; 2 group of php won't share the same /tmp/xcache
xcache.mmap_path =    "/dev/zero"

xcache.optimizer =           On

xcache.coverager =           Off
;xcache.coveragedump_directory = "/tmp/pcov"

После чего перезапускаем php (не nginx!):)

Шаблон:LinuxConsole

Вообще, имеет смысл сделать какой-нить файл типа phpinfo.php и в нём смотреть - подцепились ли дополнения, или не подцепились.

Установка и настройка I2P роутера[править]

Для начала надо установить java. В принципе у меня работает и на openjdk 1.6.0_20. Но если у вас не так - поставьте Java от Sun. Чтобы не трахаться с поиском, установкой и настройкой - проверьте сначала, может у вас оно есть? Выполните в консоли следующую команду. Если у вас отобразится то же самое, что у меня или близкое к тому - забиваем большой и толстый и идём ставить I2P.

Шаблон:LinuxConsole

Ставится это тоже просто, например около так (выберите пакет, например -devel пакет не обязателен, можно простой установить): 

Шаблон:LinuxConsole

А потом выкачиваем и ставим, тащемта, I2P роутер, например: 

Шаблон:LinuxConsole

Далее следуйте инструкциям ФСБ инсталлятора.

Как правило I2P ставится в директорию /usr/local/i2p - насколько я помню, её можно указать при установке. В принципе не так важно куда ставить, она сможет работать нормально и если вы её установите в домашнюю папку пользователя i2p: /home/i2p, суть не в этом, а в том, что в этой директории лежит скрипт i2prouter - им производится управление службой i2p. Работает примерно так: /usr/local/i2p/i2prouter start|stop|restart - обычный shell-файл. Его можно добавить в автозагрузку. Самый простой (но и самый неправильный) способ - это добавить команду в конец файла /etc/rc.local

# I2P Service start
sleep 20
/usr/local/i2p/i2prouter start

В этом случае роутер будет загружаться от root с запаздыванием на 20 секунд после остальных служб. Это было необходимо в моём случае, так как иначе сервис запускался с ошибками, или не запускался вовсе. Но как утверждают анонимусы - это плохая практика, кошернее запускать от специально созданного пользователя I2P. Если у вас есть оттестированный и рабочий пример того, как надо - пожалуйста, добавьте ниже.

В принципе должен работать вариант такой команды: 

Шаблон:LinuxConsole

Но я лично не проверял. Если работает - гут.

Удалённый доступ к I2P консоли через SSH[править]

Собственно, зависит от того, какая у вас машина. На Linux работает команда

Шаблон:LinuxConsole

Где, соответственно, <USER_NAME> - учётка на том сервере куда стучитесь, а <HOST_IP> - айпишник/DNS имя сервера. В результате на локальной машине вы сможете просто подключиться в браузере к http://localhost:7657 и получить там удалённую консоль, как будто она у вас на локальной машине.

В Windows, как обычно, сложнее. Для начала, надо скачать программку plink.exe и куда-нибудь её поместить, после чего в командной строке набрать: 

Шаблон:LinuxConsole

результат получится аналогичным. Кстати подобные тоннели - весьма полезная вещь, например в качестве прокси на работе, где злые админы заблокировали всякие кошерные сайты. Правда они могли заблокировать и 22-й порт, но то уже другая песня...

Портирование / создание тоннелей[править]

Тащемта, есть две разницы, если у вас уже был какой-то сайт/домен в I2P (и, соответственно, приватные ключи к нему) или не было. Если не было - то имеет смысл посмотреть эту статью. Там создание тоннелей с нуля даже в картинках.

В принципе - портирование тоннелей из старого сервера / окружения на новый - очень похоже. Для начала надо скопировать приватные ключи - те, которые сопоставлены вашим доменам. А дальше шаги примерно аналогичны, просто в качестве приватного ключа указываете имя файла, содержащего приватный ключ от домена, например i2ptunnel6-privKeys.dat - сразу же, при создании тоннеля. Тогда он автоматически подцепит ключ, и будет перенаправлять тоннель на ваш виртуальный хост.

Настройка резервного копирования[править]

В принципе, если есть время, знания и желание, а главное, насущная необходимость - лучше использовать нечто специализированное, наподобие Bacula. Но для небольшого проекта - до 10 сайтов и базы размером до 1 Гб, вполне пойдёт автоматизация путём какого-либо скрипта. Что он должен делать?

  1. Копировать во временную папку необходимые файлы.
  2. Создавать в той же временной папке дамп mysql
  3. Сжимать всё это в архив, и помещать его в хранилище (на другом физическом диске - предпочтительнее)
  4. Удалять временные файлы
  5. Осуществлять сборку мусора (устаревших копий)

Естественно, это всё будет запускаться по cron.

Для начала, нам потребуется архиватор, скачиваем, ставим: 

Шаблон:LinuxConsole

А затем делаем где-нибудь, скажем в /usr/scripts (создайте) файлик следующего содержимого (часть его пока корявая, потом поправлю, как допишу и испытаю - а именно в области удаления устаревших копий):

<?php
/**
 * Тащемта, файл обеспечивает автоматизированное резервное копирование данных хостов, 
 * базы данных, конфиги, и так далее. 
 * 
 * Суть работы - упаковка всего и вся, по путям прописанным в настройках, в единый архив, и помещение его
 * в резервное хранилище на другом физическом разделе. При этом производится нумерация файлов по
 * датам, и удаление файлов, устаревших на N дней. 
 * 
 * @data 25.07.2011
 * @author Alex
 * 
 * 
 */
/**
 * Папки, которые необходимо зарезервировать
 * @var array
 */
$reservPaths = array(
	'/root/.i2p',
	'/www',
	'/usr/local/i2p',
	'/etc/nginx',
	'/etc/php.d',
	'/etc/php.ini',
	//'',
);

/**
 * Где будем хранить бэкапы
 * @var integer
 */
$backupPath = '/backups/web';

/**
 * Указываем время хранения бэкапа
 * @var integer
 */
$backupTTL = 7;

/**
 * Путь к логам 
 * @var string 
 */
$logPath = '/var/log/web_backup.log';

$log = null;
if (!file_exists($logPath))
{
        $log = fopen($logPath, 'w');
}
else
{
        $log = fopen($logPath, 'a+');
}

fwrite($log, "--- START ".date('d.m.Y H:i:s')." ---\n\n");

// Делаем временные папки
$tmp = '/tmp/' . strtoupper( substr( md5( mt_rand() ), 0, 6 ) );
mkdir($tmp, 0777);
mkdir($tmp . '/DB', 0777);

foreach ($reservPaths as $v)
{
	$fix_name = str_replace(array('/', '\\'), '_', $v);
	if (!is_file($v) && is_dir($v))
	{
		mkdir($tmp.'/'.$fix_name, 0777);
		system("cp {$v}/* {$tmp}/{$fix_name}/ -R -f");
	} 
	else
	{
		system("cp {$v} {$tmp}/{$fix_name} -f");
	}
}

// Сохраняем БД
system("mysqldump --all-databases --user 'root' --password='YOU_MYSQL_PASSWORD' --hex-blob > {$tmp}/DB/sqldump");

// Упаковываем, должен стоять пакет p7zip (yum search!)
$date = date('dmY_His');
system("7za a -t7z -m0=lzma '{$backupPath}/{$date}_dump.7z' {$tmp}/* ");

if (file_exists($backupPath.'/'.$date.'_dump.7z'))
{
	system("rm -rf {$tmp}");
}

fwrite($log, date('d.m.Y H:i:s')." > Резервирование окончено, резервная копия в {$backupPath}/{$date}_dump.7z\n");

// Garbage Collector.
$dir = scandir($backupPath);

if (0 < count($dir))
{
	
	$time = time();
	$interval = strtotime( "-{$backupTTL} days" );
	
	foreach ($dir as $v)
	{
		if (('.' != $v) && ('..' != $v))
		{
			$cDate = lstat($backupPath.'/'.$v);
			// Если не работает, то ctime меняем на числовой индекс 10
			// Это потребуется если PHP ниже версии 4.0.6
			if ($interval > $cDate['ctime'])
			{
				unlink($backupPath.'/'.$v);
				fwrite($log, date('d.m.Y H:i:s')." > Файл {$backupPath}'/'{$v} устарел и удалён. \n");
			}
		}
	}
}

fwrite($log, "--- END ".date('d.m.Y H:i:s')." ---");
fclose($log);

Итак, предположим, что у вас скрипт лежит по пути /var/scripts/backup.php - естественно пользователь, от которого вы будете запускать его на выполнение, должен иметь права соответствующие на файл. Для пробы можете запустить его прямо из командной строки, чтобы проверить - корректно ли он работает.

Шаблон:LinuxConsole

Если он ругается на права - необходимо разрешить проблему до того, как вы поместите его в crontab на выполнение. В случае удачного исполнения, в папке с вашими бэкапами создастся файл архива (типа backups/10122011_010300_back.7z).

Теперь следующее. В /etc/ есть директории cron.daily, cron.weekly и т. д.Права на запись в них имеет пользователь root, если у вас есть эти права, то всё ок (а я исхожу из того, что на сервере у вас есть root права). Сделаем: 

Шаблон:LinuxConsole

В открывшемся редакторе введём:

 
#!/bin/sh
/usr/bin/php /usr/scripts/backup.php

Ну и собственно всё. Теперь ваш скрипт будет запускаться по cron раз в сутки, и сваливать результаты своей деятельности в директорию бэкапов. Устаревшие бэкапы будут удаляться (срок хранения задаётся в скрипте). Автор, собственно, очень удивился тому, что скрипт вышел довольно переносимым. Т.е. имея окружение, описанное в требованиях, вы можете перезаписать некоторые параметры и он будет работать. Выяснилось это при переносе rus.i2p на новое железо в начале 2012-го. Ожидались проблемы, однако таковых не последовало - скрипт исправно отрабатывает свою функцию.

См. Также[править]