Андрей ШетухинАндрей Шетухин
Создаём собственный хостинг, или Сам себе ISP
Часть вторая
В предыдущей части была описана общая схема веб-хостинга, первоначальная подготовка сервера к настройке, установка необходимого программного обеспечения и его минимальная настройка. Сегодня мы рассмотрим создание системы домашних каталогов пользователей, отделение пользователей друг от друга и от системы, а также настройку производительности системы.
Общие концепции
Как уже упоминалось в первой части (см. №4 за 2007 год), мы разделяем типы пользователей. То есть у нас есть отдельный пользователь c отдельным паролем для доступа к СУБД, FTP и для работы в шелле по SSH.
Чтобы не возникало неразберихи, следует как-то систематизировать все создаваемые сущности. Хорошим и проверенным методом является следующий: все пользователи данной техплощадки имеют один и тот же префикс в виде имени площадки. Пример: u00000, где u – сокращение от «user», а 00000 – порядковый номер площадки по базе данных.
Для площадки с номером 12345 у нас будут следующие реквизиты:
- /home/www/u12345 – каталог с сайтами, например /home/www/u12345/somesite.ru;
- u12345 – имя пользователя для работы по SSH и FTP;
- u12345.ftp.ourhosting.ru – название хоста для доступа на техплощадку по FTP;
- u12345.ssh.ourhosting.ru – название хоста для доступа на техплощадку по SSH;
- u12345 – имя пользователя для работы c базой данных;
- u12345 – собственно база данных;
- u12345.mysql.ourhosting.ru – имя хоста, на котором расположена БД.
В случае, если пользователю понадобятся дополнительные базы данных, их имена будут u12345_2, u12345_3, u12345_4 и т. д.
Разумеется, у хостинга должны быть настроены зоны DNS так, чтобы при запросе имен хостов отдавались правильные IP-адреса.
Небольшое отступление. Очень плохая практика называть пользователей значимыми именами, например «alex» или «somesite_ru», это очень неудобно с точки зрения организации биллинга, системы резервного копирования и миграции данных между машинами, заставляет каждый раз придумывать новые имена, а самое главное – при наличии достаточного количества клиентов приводит к повторениям и дальнейшей путанице.
Профиль пользователя
На сегодняшний день реалии таковы, что большая часть сайтов имеют кодировку Windows-1251. Применительно к вопросу веб-хостинга это означает, что вся локализация консоли, веб-сервера и сервера базы данных должна быть ru_RU.CP1251. Для локализации консоли необходимо создать дополнительный класс russianwww в файле /etc/login.conf:
#
# Russian Web Users Accounts.
# Setup proper environment variables.
#
russianwww|Russian Users Accounts:\
:charset=CP1251:\
:lang=ru_RU.CP1251:\
:umask=0007:\
:tc=default:
После необходимых правок /etc/login.conf, пересоздаем базу данных:
cap_mkdb /etc/login.conf
Для локализации Apache придется изменить файл /usr/local/sbin/apachectl, внеся в него следующие строки:
#!/bin/sh
# Localization
umask 0002
LC_ALL=ru_RU.CP1251; export LC_ALL
LANG=ru_RU.CP1251; export LANG
MM_CHARSET=CP1251; export MM_CHARSET
Для сервера MySQL достаточно будет создавать пользовательские базы данных с кодировкой cp1251 и cp1251_general_ci collation:
CREATE DATABASE `u00001` DEFAULT CHARACTER SET cp1251 COLLATE cp1251_general_ci;
Система каталогов пользователей
Как уже было описано в первой части статьи (см. №4 за 2007 год), пользователи виртуального хостинга размещаются на отдельном разделе /home в каталоге www. Если с течением времени свободное место в /home/www закончится, мы сможем установить в сервер дополнительный физический диск и смонтировать его в /home/www1. При этом общая схема работы хостинга не изменится, и дополнительная настройка не понадобится.
Для того чтобы пользователи не имели доступа к «чужим» данным, необходимо правильно выставить права и владельцев каталогов. Такая настройка каталогов пользователей – очень важный момент, поэтому остановимся на ней подробнее.
Итак, пользователи не должны иметь доступ к каталогам друг друга, но при этом надо позаботиться о доступности этих данных веб-серверу. К счастью, механизм UNIX permissions позволяет решить эту проблему: мы создадим специальную группу, в которую будут входить пользователи веб-хостинга и пользователь, от которого запущен веб-сервер Apache:
pw groupadd virtwww -M www
Создаем каталоги:
mkdir -p /home/www
chown root:wheel /home/www
Права на каталог /home/www должны быть 0711, чтобы нельзя было получить список файлов/каталогов внутри. Пользователи могут войти в каталог, но не могут получить листинг.
Создаем пользователя нашего веб-хостинга:
pw useradd u00001 -g virtwww -d /home/www/u00001 -s /usr/local/bin/bash -L russianwww -m
pw groupadd u00001 -M u00001
Таким образом, каждый пользователь имеет две группы: первичную – virtwww и дополнительную, совпадающую по имени с именем пользователя.
Устанавливаем права на домашний каталог пользователя:
chmod 04710 /home/www/u00001
chown u00001:www /home/www/u00001
При таких правах на каталог никто, кроме пользователя u00001 и веб-сервера, не будет иметь доступа к данным пользователя, а созданные внутри файлы и каталоги будут наследовать ID и GID владельца.
Для хранения лог-файлов мы выберем каталог /var/log/apache.
Именно здесь нам потребуется введенная дополнительно группа у пользователя хостинга: при её помощи мы выдадим права на просмотр лог-файлов.
Создаем каталог, в котором будут храниться лог-файлы:
mkdir -p /var/log/apache
chmod 0711 /var/log/apache
chown root:wheel /var/log/apache
mkdir /var/log/apache/u00001
chmod 0750 /var/log/apache/u00001
chown root:u00001 /var/log/apache/u00001
Теперь осталось расписать процедуру заведения виртуального хоста для пользователя. Сделаем это на примере сайта example.ru:
- Создаем каталоги:
mkdir -p /home/www/u00001/example.ru/www
mkdir -p /home/www/u00001/example.ru/cgi
mkdir -p /home/www/u00001/example.ru/tmp
chown -R u00001:virtwww /home/www/u00001/example.ru
chmod -R 04770 /home/www/u00001/example.ru
mkdir /var/log/apache/u00001/example.ru
chmod 0750 /var/log/apache/u00001/example.ru
- Прописываем конфигурацию для Apache:
<VirtualHost 127.0.0.1:80>
ServerName example.ru
ServerAlias www.example.ru
DocumentRoot /home/www/u00001/example.ru/www
ScriptAlias /cgi /home/www/u00001/example.ru/cgi
ErrorLog /var/log/apache/u00001/example.ru/error_log
TransferLog /var/log/apache/u00001/example.ru/access_log
php_admin_value upload_tmp_dir /home/www/u00001/example.ru/tmp
php_admin_value doc_root /home/www/u00001/example.ru
php_admin_value user_dir www
php_admin_value open_basedir /home/www/u00001:/usr/local/share/smarty:/usr/local/share/pear
php_admin_value session.save_path /home/www/u00001/example.ru/tmp
User u00001
Group virtwww
</VirtualHost>
- Проверяем конфигурацию Apache:
/usr/local/sbin/apachectl configtest
Syntax OK
|
- Перезапускаем веб-сервер Apache и проверяем работу системы:
/usr/local/sbin/apachectl restart
echo "<? phpinfo(); ?>" > /home/www/u00001/example.ru/www/test.php
fetch http://example.ru/test.html
test.php 34 kB 13 MBps
rm /home/www/u00001/example.ru/www/test.php
|
- Заводим FTP-доступ для пользвателя. Поскольку всех FTP-пользователей мы храним в БД, вся процедура создания доступа по FTP сводится к созданию ровно одной записи:
INSERT INTO ftp.ftpusers VALUES('u00001', 'topsecret', '1001', '1000', '/home/www/u00001', 0, 1, '');
где 1001 – UID пользователя, а 1000 – GID группы virtwww.
Проверяем доступ по FTP:
ftp localhost
Trying ::1...
Connected to localhost.
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 1 of 50 allowed.
220-Local time is now 01:58. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
Name (localhost:stellar): u00001
331 User u00001 OK. Password required
Password:
230-User u00001 has group access to: u00001 virtwww
230 OK. Current restricted directory is /
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> quit
221-Goodbye. You uploaded 0 and downloaded 0 kbytes.
221 Logout.
|
Для автоматизации создания учетных записей пользователей можно воспользоваться скриптом, доступным по адресу http://www.reki.ru/products/webhosting/addftpuser.
Настройка параметров системы
Настройка параметров системы преследует две цели. Первая цель: повысить уровень безопасности путем изоляции пользователей друг от друга и от системы и вторая – достичь оптимальной производительности хостинга.
Для изоляции клиентов хостинга на уровне файловой системы мы воспользовались системой UNIX permissions. Теперь необходимо изолировать клиентов на уровне доступа к списку процессов, используемых ресурсов и т. п. Для этого в файл /etc/sysctl.conf вносим строчку:
security.bsd.see_other_uids=0
и перечитываем конфигурацию:
/etc/rc.d/sysctl restart
Для того чтобы при падении программ система писала core-файлы в один каталог, а не во всю файловую систему, также добавляем строчки:
kern.sugid_coredump=0
kern.corefile=/var/tmp/%N.core
Для оптимизации работы системы пропишем следующие параметры:
kern.ipc.maxsockbuf=16777216
net.inet.tcp.rfc1323=1
net.inet.tcp.sendspace=1048576
net.inet.tcp.recvspace=1048576
net.inet.tcp.sack.enable=1
kern.maxfiles=204800
kern.maxfilesperproc=200000
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
net.inet.ip.portrange.randomized=0
net.inet.tcp.nolocaltimewait=1
Детальное их описание довольно сложно и выходит за рамки данного руководства; интересующимся следует обратиться к текстам докладов Первой конференции российских веб-разработчиков: http://www.rit2007.ru/org.html.
Выводы
Разумеется, это всего лишь прототип реального хостинга и при количестве клиентов до нескольких сотен будет работать в предлагаемой конфигурации. Для развертывания системы в эксплуатацию с несколькими тысячами пользователей необходимо, как минимум, разнести веб-сервер и сервер БД, а для биллинга выделить отдельную машину. Также следует рассмотреть вопросы организации резервных копий (backup), систему миграции пользователей между серверами хостинговой площадки, а также – систему миниторинга пользовательской активности. Возможно, об этом – в следующих статьях.
Удачи!