Ну вот мы дошли до самого приятного в настройке нашего 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 ВикипедияА юзер под рутом не может этот атрибут снять ?
Если мне память не изменяет то удаление хард линка не ведет к удалению исходного файла — поэтому у других пользователей хардлинк на сокет останется. Или я не прав?
Второй вариант: если запретить удаление сокета не в папке пользователя, а в родительской папке…
Максимум что сможет злой юзер это удалить хардлинк на файл?! Не пробовал как система будет вести себя в таком случае, но мне кажется возможно только два варианта: или хардлинк тоже нельзя будет удалить, либо все равно при удалении хардлинка сокет останется…