Ну вот мы дошли до самого приятного в настройке нашего VDS — установка nginx. Немного поясню структуру расположения наших сайтов:

В домашней директории будут размещены юзеры, в папках которых будет набор стандартных для работы PHP папок. Каждый PHP будет запускаться от имени юзера сайта через php-fpm, раздаваться все будет через nginx. Все далее описанное будет проделано на ubuntu 14.04 LTS для сайта koteika.ru . Создать папки и юзера придется до установки nginx.
Создаем нового юзера:
sudo useradd -d /home/koteika.ru -m koteika.ru
Добавляем его в группу www-data (долго думал и решил, что они будут в одной группе, может как-то потом их хитро ограничу):
sudo usermod -g www-data koteika.ru
Создаем внутренние папки от рута в домашней папке пользователя:
sudo mkdir /home/koteika.ru/bin sudo mkdir /home/koteika.ru/dev sudo mkdir /home/koteika.ru/etc sudo mkdir /home/koteika.ru/lib sudo mkdir /home/koteika.ru/logs sudo mkdir /home/koteika.ru/public_html sudo mkdir /home/koteika.ru/tmp sudo mkdir /home/koteika.ru/usr
Этим папкам выдаем права на запись от юзера koteika.ru:koteika.ru
sudo chown koteika.ru:koteika.ru /home/koteika.ru/public_html sudo chown koteika.ru:koteika.ru /home/koteika.ru/tmp
Теперь ставим nginx:
sudo apt-get install nginx
Создадим юзера nginx:
sudo useradd nginx
Создадим файл, в который будем записывать адреса забаненных хостов через точку с запятой:
touch /etc/nginx/blockips.conf
Теперь самое время править конфиг nginx, расположен он тут — /etc/nginx/nginx.conf Его надо поправить до примерно такого состояния:
user nginx;
worker_processes 4;
worker_priority -5;
pid /run/nginx.pid;
events {
worker_connections 2048;
multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
send_timeout 120;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_min_length 1100;
# gzip_vary on;
# gzip_proxied any;
gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# nginx-naxsi config
##
# Uncomment it if you installed nginx-naxsi
##
#include /etc/nginx/naxsi_core.rules;
##
# nginx-passenger config
##
# Uncomment it if you installed nginx-passenger
##
#passenger_root /usr;
#passenger_ruby /usr/bin/ruby;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/blockips.conf;
include /etc/nginx/sites-enabled/*;
}
Я измененил следующие параметры:
user — имя нашего юзера nginx
worker_processes — ставим по числу процессоров, но lissyara пишет что помогает когда больше 😉 Памяти у нас 4096, т.ч. поставим 4. Узнать кол-во ядер можно так:
sudo cat /proc/cpuinfo | grep ^processor |wc -l
worker_priority -5 — чтобы статика отдавалась при нагруженом сервере стабильно.
multi_accept on — позволяет немного ускорить nginx, т.к. за раз принимаются все входящие соединения.
server_names_hash_bucket_size — Обязательно указываем, иначе глюки у nginx вылезают очень интересные. Для подробной информации server_names_hash_bucket_size.
keepalive_timeout — тут вроде все почти стандартно.
send_timeout — чтобы даже очень медленные клиенты все смогли принять.
server_tokens — тут можно скрыть версию nginx в заголовках ответа сервера.
gzip_min_length — 1100 — минимальный размер документа для сжатия в gzip (как пишут умные люди — меньший объем дает плохой выигрыш в соотношении размер сжатого файла\загрузка процессора).
gzip_comp_level — 6 — сжимать файлы со средней компрессией, по той же причине.
Ну и в 76 строке подключаем наш файлик /etc/nginx/blockips.conf, в который будем заносить адреса неугодных нам ботов. В него можно сразу прописать:
deny 212.158.160.238; deny 212.158.160.239; deny 83.61.19.182; deny 195.5.154.130; deny 204.12.238.106; deny 174.133.5.250;
Далее создадим файл конфигурации сайта /etc/nginx/sites-available/koteika.ru
server {
listen 88.198.184.77:80 default;
listen [2a01:4f8:b0:7f9d::2]:80 default;
root /home/koteika.ru/public_html;
server_name koteika.ru www.koteika.ru;
access_log /home/koteika.ru/logs/access.log;
error_log /home/koteika.ru/logs/error.log;
client_max_body_size 64m;
location / {
index index.php index.html;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/home/koteika.ru/tmp/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /public_html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /public_html;
}
location ~ /\.ht {
deny all;
}
}
Конфиг нагляден, но пару комментариев оставлю:
listen 78.46.226.56:80 default; — здесь ip:port на котором nginx будет слушать запросы на ваш сайт (на случай если порт нестандартный или несколько адресов у сервера). default — говорит что сайт дефолтный, т.е. если запрос придет на любой хост, для которого нет конфига, то обработан будет здесь.
server_name — имя хоста и алиасов.
client_max_body_size 64m; — ограничил максимальный размер поста на сервер до 64 мб.
В кратце в конфиге написано, что индекс у нас index.php index.html, все файлы оканчивающиеся на .php обрабатываются нашим fastcgi-сервером (пока пхп не ставили), все файлы начинающиеся с .ht запрещены, остальное отдается как статика. Для более полного понимания как работает конфиг nginx лучше посетить sysoev.ru.
Добавляем конфиг сайта в активные:
sudo ln -s /etc/nginx/sites-available/koteika.ru /etc/nginx/sites-enabled
Проверяем конфигурацию nginx
sudo service nginx configtest
Если все впорядке, то перезапускаем nginx:
sudo service nginx restart
Сейчас уже можно отдавать статику, но на запросы PHP nginx пока будет возвращать 502 (собственно PHP пока не установлен и сокета нет). Об установке PHP напишу через пару дней.
В качестве бонуса добавлю конфиг nginx для сайта на wordpress (на примере сайта koteika.ru).
server {
listen 88.198.184.77:80 default;
listen [2a01:4f8:b0:7f9d::2]:80 default;
root /home/koteika.ru/public_html;
server_name koteika.ru www.koteika.ru;
access_log /home/koteika.ru/logs/access.log;
error_log /home/koteika.ru/logs/error.log;
client_max_body_size 64m;
location / {
try_files $uri $uri/ @koteika_entry;
index index.php;
}
location ~ \.php$ {
try_files $uri @koteika_entry;
fastcgi_pass unix:/home/koteika.ru/tmp/php-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /public_html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /public_html;
}
location ~ /\.ht { return 403; }
location @koteika_entry {
fastcgi_pass unix:/home/koteika.ru/tmp/php-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /public_html/index.php;
fastcgi_param DOCUMENT_ROOT /public_html;
}
}
[…] Установка nginx из репозитария и настройка. […]
[…] php. listen – тот самый сокет, котрый мы указывали в конфигурации nginx. request_terminate_timeout – убъется, если зависнет более чем N […]
Вот решил на новой VPS’ке провести настройку по вашим заметкам, за что вам огромное спасибо!
Нашел некоторые недочет в вашем описании:
При создании каталогов пользователя необходимо еще создать каталог
mkdir -p /home/lemb.su/var/run/mysqldзатем командой
ln /var/run/mysqld/mysqld.sock /home/lemb.su/var/run/mysqld/создать ссылку на сокет MySQL иначе пользователи не смогут к нему достучаться.Большое спасибо за ваш труд, с нетерпением жду продолжения (особенно скрипты упрощающие добавление нового сайта)
У меня они через TCP ходят в MySQL, идея с сокетом у меня появлялась, но я подумал, что если юзер повысит привилегии в chroot каким-то образом до root – он просто снесет сокет и все остальные упадут (может я как-то ошибаюсь, было бы кому поправить). А так то ессно лучше, чем через TCP гонять. Надо проконсультироваться у компитентных людей.
Для себя от TCP в MySQL отказался вообще — память расходуется (у меня ее мало 256Mb), а профита по сравнению с сокетом нет…
В данном способе есть недостаток:
При перезапуске MySQL или рестарте системы необходимо повторно создавать хард линк на сокет, так как inode сокета в файловой системе поменялся, и пользовательская ссылка ссылается на не существующий объект. Но это можно решить с помощью модификации /etc/init.d/mysql скрипта.
Создать скрипт который будет пробегаться по пользователям, проверять есть ли у них ссылка на сокет, и если есть обновлять ее.
Если мы будем раскручивать хостинг на файловой системе ext2/ext3 (думаю и на ext4 пойдет), то можно поиграться с командой
chattr. У данной команды есть ключuкоторый дает возможность установить атрибут файлу «не удаляемый». chattr ВикипедияА юзер под рутом не может этот атрибут снять ?
Если мне память не изменяет то удаление хард линка не ведет к удалению исходного файла — поэтому у других пользователей хардлинк на сокет останется. Или я не прав?
Второй вариант: если запретить удаление сокета не в папке пользователя, а в родительской папке…
Максимум что сможет злой юзер это удалить хардлинк на файл?! Не пробовал как система будет вести себя в таком случае, но мне кажется возможно только два варианта: или хардлинк тоже нельзя будет удалить, либо все равно при удалении хардлинка сокет останется…