Как создать свой хостинг "с нуля" - Сборка и настройка комплекса ПО

ОГЛАВЛЕНИЕ


Сборка и настройка комплекса ПО

Перед установкой добавляем в /etc/make.conf

WITHOUT_X11=yes 

Устанавливаем MySQL. Собственно, здесь нет ничего экстраординарного:

cd /usr/ports/databases/mysql51-server
export WITH_CHARSET=cp1251
export WITH_XCHARSET=all
export BUILD_OPTIMIZED=yes
make install clean

После установки сервера указываем в /etc/rc.conf

#
# MySQL for virtual hosts
#
mysql_enable="YES"

Записываем файл конфигурации MySQL /var/db/mysql/my.cnf:

[client]
port            = 3306
socket          = /tmp/mysql.sock
default-character-set=cp1251

[mysqld]
bind-address    = 127.0.0.1
port            = 3306
socket          = /tmp/mysql.sock
skip-character-set-client-handshake
default-character-set=cp1251
skip-locking

key_buffer              = 32M
max_allowed_packet      = 16M
table_cache             = 256
sort_buffer_size        = 1M
read_buffer_size        = 1M
read_rnd_buffer_size    = 4M
myisam_sort_buffer_size = 64M
thread_cache_size       = 8
query_cache_size        = 16M
thread_concurrency      = 8
max_connections         = 128
max_user_connections    = 126
log-slow-queries
log
binlog_ignore_db        = mysql
expire_logs_days        = 5
max_binlog_size         = 400M
# Если нет необходимости в работе по сети, включаем опцию skip-networking
#skip-networking
log-bin                 = mysql-bin
server-id               = 1

[mysqldump]
quick
max_allowed_packet      = 16M

[mysql]
no-auto-rehash

[isamchk]
key_buffer              = 128M
sort_buffer_size        = 128M
read_buffer             = 2M
write_buffer            = 2M

[myisamchk]
key_buffer              = 128M
sort_buffer_size        = 128M
read_buffer             = 2M
write_buffer            = 2M

[mysqlhotcopy]
interactive-timeout

запускаем сервер

/usr/local/etc/rc.d/mysql-server start 

и проверяем, все ли работает нормально

ps axw | grep mysql

  780 con- I      0:00.01 /bin/sh /usr/local/bin/mysqld_safe
     --defaults-extra-file=/var/db/mysql/my.cnf --user=mysql --datadir=/var/db/mysql --pid-file=/v
  862 con- S    107:52.92 /usr/local/libexec/mysqld --defaults-extra-file=/var/db/mysql/my.cnf
     --basedir=/usr/local --datadir=/var/db/mysql --pid-file=/va
 7861  p0  S+     0:00.00 grep mysql

Задаем пароль для MySQL root:

mysql -uroot

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 24356
Server version: 5.1.15-beta-log FreeBSD port: mysql-server-5.1.15

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY 'topsecret';
mysql> GRANT ALL ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY 'topsecret';

На этом установка MySQL окончена.

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

+------------+         +-------------------+         +-------------------+
| посетитель | ------> | Внешний IP: NGINX | ------> | 127.0.0.1: Apache |
+------------+         +-------------------+         +-------------------+

При такой схеме все запросы, приходящие на Apache, будут иметь один и тот же адрес - адрес, на котором запущен nginx. Для того чтобы Apache воспринимал запросы с IP адресов посетителей, а не прокси nginx, необходимо дополнительно установить модуль mod_realip.

Итак, устанавливаем nginx:

cd /usr/ports/www/nginx 
make install clean

Устанавливаем Apache:

cd /usr/ports/www/apache13
export WITH_APACHE_SUEXEC=yes
export APACHE_SUEXEC_LOG=/var/log/apache/suexec_log
export APACHE_SUEXEC_USERDIR=www
export APACHE_SUEXEC_DOCROOT=/home/www
make install clean

Устанавливаем mod_realip:

cd /usr/ports/www/mod_realip 
make install clean

На этом собственно установка вебсервера окончена. Следующий шаг - сборка php и mod_php. Из портов можно установить PHP4 или PHP5 - принципиальной разницы в технологии установки и конфигурирования нет, а потому будет описана только сборка mod_php5. Для нормальной работы с временными файлами (сессии, загрузка файлов и т.п.) требуется дополнительный патч, изменяющий права доступа с 0600 до 0660, чтобы вебсервер имел право записи в них. Патч доступен по адресу PHP4, patch-main::open_temporary_file.c.4 и PHP5, patch-main::open_temporary_file.c.5

cd /usr/ports/lang/php5
fetch http://reki.ru/products/samag/PHPPatchset.tar.gz
tar -xzf PHPPatchset.tar.gz
mv PHPPatchset/patch-main::open_temporary_file.c.5 files/
make install clean

В появившемся меню указываем требуемые опции:

+--------------------------------------------------------------------+
¦                     Options for php5 5.2.1_3                       ¦
¦ +----------------------------------------------------------------+ ¦
¦ ¦  [X] CLI        Build CLI version                              ¦ ¦
¦ ¦  [X] CGI        Build CGI version                              ¦ ¦
¦ ¦  [X] APACHE     Build Apache module                            ¦ ¦
¦ ¦  [ ] DEBUG      Enable debug                                   ¦ ¦
¦ ¦  [X] SUHOSIN    Enable Suhosin protection system               ¦ ¦
¦ ¦  [X] MULTIBYTE  Enable zend multibyte support                  ¦ ¦
¦ ¦  [ ] IPV6       Enable ipv6 support                            ¦ ¦
¦ ¦  [ ] MAILHEAD   Enable mail header patch                       ¦ ¦
¦ ¦  [X] REDIRECT   Enable force-cgi-redirect support (CGI only)   ¦ ¦
¦ ¦  [X] DISCARD    Enable discard-path support (CGI only)         ¦ ¦
¦ ¦  [ ] FASTCGI    Enable fastcgi support (CGI only)              ¦ ¦
¦ ¦  [X] PATHINFO   Enable path-info-check support (CGI only)      ¦ ¦
¦ ¦                                                                ¦ ¦
¦ ¦                                                                ¦ ¦
¦ ¦                                                                ¦ ¦
+-+----------------------------------------------------------------+-+
¦                       [  OK  ]       Cancel                        ¦
+--------------------------------------------------------------------+

проверить работоспособность установленного PHP можно командой echo "<? phpinfo(); ?>" | php

В выводе команды полностью отсутствуют упоминания о mysql, gd, iconv и прочих функциях. Что неудивительно, ибо в системе FreeBSD все дополнительные модули ставятся отдельно.

Чтобы установить необходимые модули можно воспользоваться двумя тактиками: поставить все за один раз, подав команды

cd /usr/ports/lang/php5-extensions 
make install clean

и выбрав необходимый набор модулей из меню.

Или - собрать каждый модуль по отдельности:

cd /usr/ports/www/php5-session
make install clean

cd /usr/ports/graphics/php5-gd
make install clean
...
и т.д.

В случае необходимости можно дополнительно установить Zend Optimizer. Он также есть в портах FreeBSD (/usr/ports/devel/ZendOptimizer). Установка Zend не представляет никакой сложности; а сам продукт практически не нуждается в настройке.

По окончании установки, прописываем в файл /etc/rc.conf параметры для запуска nginx и Apache:

#
# Nginx Accelerator
#
nginx_enable="YES"

#
# Apache Backend
#
apache_enable="YES"

Конфигурируем nginx (файл /usr/local/etc/nginx/nginx.conf):

user  www;
worker_processes  2;

pid         /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] $request '
                      '"$status" $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log         off;

    sendfile           on;

    keepalive_timeout  65;

    gzip               on;

    server {
        listen       XXX.YYY.ZZZ.DDD:80;
        server_name  localhost;

        location /
        {
                # Максимальный размер отдаваемого файла
                client_max_body_size  20M;

                # Адрес, на который будем проксировать
                proxy_pass http://127.0.0.1:80;
                proxy_redirect off;

                proxy_set_header Host                 $host;
                proxy_set_header X-Real-IP            $remote_addr;

                proxy_connect_timeout 90;
                proxy_send_timeout    90;
                proxy_read_timeout    90;
                proxy_send_lowat      12000;

                proxy_buffer_size          4k;
                proxy_buffers              4 32k;
                proxy_busy_buffers_size    64k;
                proxy_temp_file_write_size 64k;
                proxy_temp_path            /var/tmp/nginx;
       }
    }
}

Конфигурируем Apache(файл /usr/local/etc/apache/httpd.conf):

LoadModule realip_module      libexec/apache/mod_realip.so

ServerName 127.0.0.1

Listen 127.0.0.1:80

RealIP  localhost on

<Directory /home/www/*/*/www>
        AllowOverride All
        Options +Indexes +ExecCGI FollowSymLinks
        DirectoryIndex index.php index.html index.htm
</Directory>
<Directory /home/www/*/*/cgi>
        AllowOverride All
        Options -Indexes +ExecCGI FollowSymLinks
        DirectoryIndex index.cgi index.html index.htm index.cgi
</Directory>

NameVirtualHost 127.0.0.1:80

Запускаем nginx и Apache:

/usr/local/etc/rc.d/nginx start 
/usr/local/etc/rc.d/apache.sh start

Проверяем, все ли работает так, как надо:

ps axw | grep nginx

 3803  ??  Is     0:00.00 nginx: master process /usr/local/sbin/nginx
 3804  ??  S      0:22.79 nginx: worker process (nginx)
 3805  ??  S      0:22.31 nginx: worker process (nginx)
 8128  p0  D+     0:00.00 grep nginx

ps axw | grep httpd
 1363  ??  Ss     0:03.24 /usr/local/sbin/httpd
 8124  ??  S      0:01.83 /usr/local/sbin/httpd
 8125  ??  R      0:01.16 /usr/local/sbin/httpd
 8126  ??  S      0:01.20 /usr/local/sbin/httpd
 8129  ??  S      0:01.16 /usr/local/sbin/httpd
 8130  ??  S      0:01.08 /usr/local/sbin/httpd
 8131  ??  S      0:01.23 /usr/local/sbin/httpd
 8132  ??  S      0:01.27 /usr/local/sbin/httpd

Для FTP доступа установим сервер pure-ftpd. Pure-ftpd - один из самых надежных и одновременно удобных FTP серверов, зарекомендовавший себя великолепной работой на протяжении многих лет.

cd /usr/ports/ftp/pure-ftpd 
make install clean

Указываем, что собирать сервер следует с поддержкой СУБД PostgreSQL, в которой будут храниться виртуальные пользователи. Выбор базы данных зависит от используемой системы управления хостингом. В нашем случае она построена на основе собственной разработки, базирующейся на СУБД PostgreSQL.

+--------------------------------------------------------------------+
¦                  Options for pure-ftpd 1.0.21_1                    ¦
¦ +----------------------------------------------------------------+ ¦
¦ ¦[ ] LDAP           Support for users in LDAP directories        ¦ ¦
¦ ¦[ ] MYSQL          Support for users in MySQL database          ¦ ¦
¦ ¦[ ] PAM            Support for PAM authentication               ¦ ¦
¦ ¦[X] PGSQL          Support for users in PostgreSQL database     ¦ ¦
¦ ¦[X] PRIVSEP        Enable privilege separation                  ¦ ¦
¦ ¦[X] PERUSERLIMITS  Per-user concurrency limits                  ¦ ¦
¦ ¦[X] THROTTLING     Bandwidth throttling                         ¦ ¦
¦ ¦[X] BANNER         Show pure-ftpd welcome upon session start    ¦ ¦
¦ ¦[X] UPLOADSCRIPT   Support uploadscript daemon                  ¦ ¦
¦ ¦[ ] UTF8           Support for charset conversion (expreimental)¦ ¦
¦ ¦[X] SENDFILE       Support for the sendfile syscall             ¦ ¦
¦ ¦                                                                ¦ ¦
¦ ¦                                                                ¦ ¦
¦ ¦                                                                ¦ ¦
¦ ¦                                                                ¦ ¦
+-+----------------------------------------------------------------+-+
¦                       [  OK  ]       Cancel                        ¦
+--------------------------------------------------------------------+

При выборе установки с PostgreSQL, автоматически поставятся порты databases/postgresql82-client и databases/postgresql82-server После установки добавляем в файл /etc/rc.conf строчки

# 
# BILLING DATABASE
#
postgresql_enable="YES"

меняем домашний каталог для пользователя pgsql на /var/db/pgsql

mkdir /var/db/pgsql
chown pgsql:pgsql /var/db/pgsql
chmod 0700 /var/db/pgsql
pw usermod pgsql -d /var/db/pgsql

и инициализируем базу данных:

su - pgsql
initdb --encoding=UTF8 --locale=ru_RU.UTF-8 --pgdata=/var/db/pgsql/data

  The files belonging to this database system will be owned by user "pgsql".
  This user must also own the server process.

  The database cluster will be initialized with locale ru_RU.UTF-8.
......

конфигурируем файл /var/db/pgsql/data/postgresql.conf:

max_connections = 150
shared_buffers = 40MB
max_fsm_pages = 76800
log_destination = 'syslog'
silent_mode = on
autovacuum = on
datestyle = 'iso, dmy'
lc_messages = 'ru_RU.UTF-8'
lc_monetary = 'ru_RU.UTF-8'
lc_numeric = 'ru_RU.UTF-8'
lc_time = 'ru_RU.UTF-8'

файл прав доступа к базе данных /var/db/pgsql/data/pg_hba.conf

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
# "local" is for Unix domain socket connections only
local   all         all                               md5
# IPv4 local connections:
host    all         all         127.0.0.1/32          md5
# IPv6 local connections:
host    all         all         ::1/128               md5

и запускаем сервер PostgreSQL

/usr/local/etc/rc.d/postgresql start 

Проверяем работу:

ps axw | grep postgres

  749  ??  Ss     0:05.39 /usr/local/bin/postgres -D /var/db/pgsql/data
  751  ??  Ss     0:08.97 postgres: writer process    (postgres)
  752  ??  Ss     0:00.64 postgres: stats collector process    (postgres)

Конфигурируем Pure-FTPD (/usr/local/etc/pure-ftpd.conf)

ChrootEveryone              yes
BrokenClientsCompatibility  no
MaxClientsNumber            50
Daemonize                   yes
MaxClientsPerIP             8
VerboseLog                  no
DisplayDotFiles             yes
AnonymousOnly               no
NoAnonymous                 yes
SyslogFacility              ftp
DontResolve                 yes
MaxIdleTime                 15
PGSQLConfigFile             /usr/local/etc/pureftpd-pgsql.conf
LimitRecursion              2000 8
AnonymousCanCreateDirs      no
MaxLoad                     4
AntiWarez                   yes
Umask                       110:007
MinUID                      100
AllowUserFXP                no
AllowAnonymousFXP           no
ProhibitDotFilesWrite       no
ProhibitDotFilesRead        no
AutoRename                  no
AnonymousCantUpload         no
MaxDiskUsage                99
CustomerProof               yes

Указываем, откуда брать информацию о виртуальных пользователях (/usr/local/etc/pureftpd-pgsql.conf).

PGSQLServer     127.0.0.1
PGSQLPort       5432
PGSQLUser       pureftpd
PGSQLPassword   topsecret
PGSQLDatabase   billing
PGSQLCrypt      cleartext
PGSQLGetPW      SELECT passwd   FROM ftp.ftpusers WHERE ftpuser='\L' AND enabled = 1;
PGSQLGetUID     SELECT user_id  FROM ftp.ftpusers WHERE ftpuser='\L' AND enabled = 1;
PGSQLGetGID     SELECT group_id FROM ftp.ftpusers WHERE ftpuser='\L' AND enabled = 1;
PGSQLGetDir     SELECT homedir  FROM ftp.ftpusers WHERE ftpuser='\L' AND enabled = 1;

Создаем таблицу пользователей в СУБД PostgreSQL:

psql -U pgsql

CREATE USER billing WITH PASSWORD 'supersecret' NOCREATEDB NOCREATEUSER;
CREATE DATABASE billing WITH ENCODING='UTF8' OWNER=billing;
CREATE SCHEMA ftp;
CREATE TABLE ftp.ftpusers
(
       ftpuser   VARCHAR(255) NOT NULL CHECK (LENGTH(ftpuser) > 0),
       passwd    VARCHAR(255) NOT NULL CHECK (LENGTH(passwd) > 0),
       user_id   INT NOT NULL DEFAULT '-1',
       group_id  INT NOT NULL DEFAULT '-1',
       homedir   VARCHAR(255) NOT NULL CHECK (LENGTH(homedir) > 0),
       expires   bigint not null default '-1',
       enabled   bigint not null default '0',
       descr     text,
       CONSTRAINT ftpusers_pk PRIMARY KEY (ftpuser)
) WITHOUT OIDS;

CREATE USER pureftpd WITH PASSWORD 'topsecret' NOCREATEDB NOCREATEUSER;
GRANT USAGE  ON SCHEMA  ftp        TO pureftpd;
GRANT SELECT ON ftp.ftpusers       TO pureftpd;
Мы разделяем типы пользователей. То есть, у нас есть отдельный пользователь 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 - имя хоста, на котором расположена БД

Разумеется, у нашего хостинга должны быть настроены зоны DNS так, чтобы при запросе имен хостов отдавались правильные IP адреса.

Небольшое отступление. Очень плохая практика называть пользователей значимыми именами, например "alex" или "somesite_ru": это очень неудобно с точки зрения организации биллинга, системы резервного копирования и миграции данных между машинами, заставляет каждый раз придумывать новые имена, а самое главное - при наличии достаточного количества клиентов приводит к повторениям и дальнейшей путанице.