Недавно приняли решение переехать с хостинга на VPS, будем использовать: CentOS 7, Nginx, Apache, PHP, MySQL. Несмотря на большое количество статей на эту тему, многие аспекты не упоминаются, поэтому выкладываем эту статью чтобы услышать мнение знающих и опытных людей. Настраивать сервер как Вы уже поняли будем первый раз, поэтому о актуальности статьи можно будет судить из комментариев. Nginx будет отдавать статику, а динамику Apache (скрипты PHP), чтобы снизить нагрузку на сервер.

Подготовка.

Все настройки будем применять на рабочем сервере нашего проекта с конфигурацией сервера: CPU — 2 ? 2000 МГц и RAM — 2048 МБ.

Для начала работы находим подходящий VPS с предустановленной CentOS 7, к серверу будем подключаться по SSH через PuTTY.

Вводим название хоста и порт, нажимаем Open:

image

Далее вводим логин [Enter], потом пароль (обратите внимание, ввод пароля не отображается) [Enter]:


Обновить систему, при этом сохранить устаревшие версии пакетов:
[root@test ~]# yum update

Или обновить все пакеты, старые пакеты будут удалены:
[root@test ~]# yum upgrade

Устанавливаем файловый менеджер с текстовым интерфейсом — Midnight Commander:
[root@test ~]# yum install mc

Устанавливаем текстовый редактор — Nano:
[root@test ~]# yum install nano

Проверяем сколько на сервере оперативной памяти и сколько доступно, а также наличие SWAP. Когда заканчивается оперативная память, данные перемещаются на диск, что замедляет работу сервера, работа SWAP нежелательна, но позволяет подстраховать себя:
[root@test ~]# free -m

Создаём файловую структуру и пользователей под сайты.

Создаём каталог (папку) для файлов под все сайты:
[root@test ~]# cd /
[root@test ~]# mkdir -m 755 website

Под каждый отдельный сайт выполните такие действия.

Содержимое каждого сайта будет находиться в собственном каталоге, поэтому создаём нового пользователя и отдельный каталог для разграничения прав доступа:
?-b папка в которой будет создан каталог пользователя
?-m создать каталог
?-U создаём группу с таким же именем как у пользователя
?-s /bin/false отключаем пользователю shell
[root@test ~]# useradd name.site -b /website/ -m -U -s /bin/false

Делаем каталоги для данных сайта (файлы сайта, логи и временные файлы):
[root@test ~]# mkdir -p -m 754 /website/name.site/www
[root@test ~]# mkdir -p -m 754 /website/name.site/logs
[root@test ~]# mkdir -p -m 777 /website/name.site/tmp

Изменяем владельца и группу на каталог, включая вложенные папки:
[root@test ~]# chown -R name.site:name.site /website/name.site/

Изменяем права доступа на каталог — name.site:
[root@test ~]# chmod 755 /website/name.site

Устанавливаем Nginx.

Инструкции по установке приведены на официальном сайте Nginx.

Для настройки репозитория yum в CentOS создаём файл /etc/yum.repos.d/nginx.repo:
[root@test ~]# cd /etc/yum.repos.d
[root@test ~]# touch nginx.repo

Открываем файл nginx.repo:
[root@test ~]# nano /etc/yum.repos.d/nginx.repo

Вставляем такое содержимое и сохраняем файл:
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=1
enabled=1

Для проверки подписи загружаем ключ и импортируем его в менеджер пакетов rpm:
[root@test ~]# rpm --import http://nginx.org/keys/nginx_signing.key

Устанавливаем Nginx:
[root@test ~]# yum install nginx

Запускаем:
[root@test ~]# systemctl start nginx.service

image

Временно останавливаем:
[root@test ~]# systemctl stop nginx.service

Устанавливаем Apache и PHP.

Устанавливаем Apache (в CentOS — httpd):
[root@test ~]# yum install httpd

Устанавливаем PHP:
[root@test ~]# yum install php

Запускаем Apache:
[root@test ~]# systemctl start httpd.service

image
Временно останавливаем:
[root@test ~]# systemctl stop httpd.service

Настраиваем Nginx.

Добавляем в автозагрузку:
[root@test ~]# systemctl enable nginx.service

Открываем основной конфигурационный файл:
[root@test ~]# nano /etc/nginx/nginx.conf

Редактируем и сохраняем:
/etc/nginx/nginx.conf
user nginx;
worker_processes 2;
pid /var/run/nginx.pid;

events {
?worker_connections 1024;
?multi_accept on;
}

http {
?error_log /var/log/nginx/error.log warn;
?access_log off;
?
?charset utf-8;
?server_tokens off;
?
?include /etc/nginx/mime.types;
?default_type application/octet-stream;
?
?reset_timedout_connection on;
?client_header_timeout 15;
?client_body_timeout 30;
?send_timeout 15;
?keepalive_timeout 5;
?keepalive_requests 30;
?client_max_body_size 8m;
?
?limit_rate_after 30M;
?limit_rate 500K;
?
?open_file_cache max=10000 inactive=3m;
?open_file_cache_min_uses 2;
?open_file_cache_valid 1m;
?
?sendfile on;
?tcp_nodelay on;
?tcp_nopush on;
?
?include /etc/nginx/conf.d/*.conf;
}


От какого пользователя запускаем Nginx:
user nginx;

Указываем количество рабочих процессов (зависит от количества ядер процессора и количества жёстких дисков, потому что головка диска быстрее перемещаться не сможет):
worker_processes 2;

Идентификатор процесса запущенного сервера:
pid??/var/run/nginx.pid;

Секция events:
events {
?#
}

Внутри блока events, максимальное количество одновременных соединении с сервером (worker_processes ? worker_connections):
worker_connections 1024;

Внутри блока events, принимать соединения сколько будет возможно:
multi_accept on;

Секция http, остальное будет находиться внутри неё:
http {
?#
}

Записывать ошибки (уровня: warn, error, crit, alert) по указанному пути:
error_log /var/log/nginx/error.log warn;

Отключаем запись журнала доступа (жёсткий диск скажет спасибо):
access_log off;

Установим кодировку по умолчанию:
charset utf-8;

Отключим показ версии Nginx:
server_tokens off;

Подключить mimetypes:
include? /etc/nginx/mime.types;

Если MIME-тип файла не удастся определить, то по умолчанию файл будет бинарным:
default_type application/octet-stream;

Закрывать соединение если клиент не отвечает:
reset_timedout_connection on;

Читать заголовок запроса клиента не более 15 секунд:
client_header_timeout 15;

Читать тело запроса клиента не более 30 секунд — интервал устанавливается не на всю передачу тела запроса, а только между двумя последовательными операциями чтения:
client_body_timeout 30;

Если клиент не принимает ответ более 15 секунд, сбрасываем соединение:
send_timeout 15;

Держим соединение открытым не более пяти секунд:
keepalive_timeout 5;

Максимальное количество запросов с открытым соединением от одного клиента:
keepalive_requests 30;

Запросы больше 8 мегабайт принимать не будем:
client_max_body_size 8m;

Чтобы один пользователь не занял весь свободный канал трафика, после 30 Мб наложим ограничение на скорость отдачи данных:
limit_rate_after 30M;

Максимальная скорость с клиентом в рамках одного соединения после наложенных ограничений будет не более 500 Кб/с:
limit_rate 500K;

Устанавливаем максимальное количество файлов, информация о которых будет содержаться в кеше и удаляться, если файл не будет запрошен повторно в течении 3 минут:
open_file_cache max=10000 inactive=3m;

Если файл будет запрошен более 2 раз, поместить в кэш:
open_file_cache_min_uses 2;

Проверять актуальность кэша каждую минуту:
open_file_cache_valid 1m;

Отдавать статику без посредников:
sendfile on;

Не буферизировать данные:
tcp_nodelay on;

Отправлять заголовки одним пакетом:
tcp_nopush on;

Подключить конфиги:
include /etc/nginx/conf.d/*.conf;

Для каждого сайта создаём виртуальный хост Nginx.

Чтобы Nginx получил доступ к файлам сайта, добавим пользователя nginx в группу name.site:
[root@test ~]# usermod -a -G name.site nginx

Затем создаём конфигурационный файл:
[root@test ~]# touch /etc/nginx/conf.d/name.site.conf

Открываем файл:
[root@test ~]# nano /etc/nginx/conf.d/name.site.conf

Редактируем и сохраняем:
/etc/nginx/conf.d/name.site.conf
server {
?listen? 80;
?server_name name.site www.name.site;
?#access_log /website/name.site/logs/nginx_access.log;
?error_log /website/name.site/logs/nginx_error.log;

?location / {
??proxy_pass http://127.0.0.1:8080/;
??proxy_read_timeout 300s;
??proxy_set_header Host $host;
??proxy_set_header X-Real-IP $remote_addr;
??proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
??proxy_buffering off;
?}
?
?location ~* \.(css|js|png|gif|jpg|jpeg|ico)$ {
??root /website/name.site/www;
??expires 1d;
?}?

?error_page 500 502 503 504 /50x.html;
?location = /50x.html {
??root /usr/share/nginx/html;
?}
}


Сервер слушает на 80 порту:
listen? 80;

Имя сервера, определяет в каком блоке будет выполнен запрос, указывается имя домена:
server_name name.site www.name.site;

Путь к журналу ошибок Nginx конкретного сайта:
error_log /serves/name.site/logs/nginx_error.log;

Перенаправить запрос Apache:
proxy_pass http://127.0.0.1:8080/;

Обрывать коннект через 300 секунд, если превышен таймаут при чтении ответа с сервера Apache:
proxy_read_timeout 300s;

Передать заголовки:
proxy_set_header Host $host;

Передать IP клиента:
proxy_set_header X-Real-IP $remote_addr;

Передать список серверов по которым прошёл запрос и добавить свой:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Отключить буферизацию проксируемого сервера:
proxy_buffering off;

Статику будет отдавать Nginx:
location ~* \.(css|js|png|gif|jpg|jpeg|ico)$ {
?root /serves/name.site/www;
?expires 1d;
}

Настраиваем Apache.

Посмотрите какой именно модуль Apache у вас установлен. У меня — apache2-mpm-prefork (один процесс с одним потоком будет обрабатывать одно соединение, рекомендуется как безопасный совместно с PHP):
[root@test ~]# apachectl -V

Открываем httpd.conf:
[root@test ~]# nano /etc/httpd/conf/httpd.conf

Редактируем и сохраняем:
httpd.conf
ServerRoot "/etc/httpd"
DocumentRoot "/website"
Include conf.modules.d/*.conf

User apache
Group apache

Listen 127.0.0.1:8080
ServerName 127.0.0.1:8080
ServerAdmin root@localhost

ServerSignature Off
ServerTokens Prod

RLimitMEM 786432000
TimeOut 250

AddDefaultCharset utf-8
DefaultLanguage ru

KeepAlive Off
ContentDigest Off
EnableSendfile off

ErrorLog "logs/error_log"
LogLevel error

<IfModule mime_module>
?TypesConfig /etc/mime.types
</IfModule>

<Directory />
?DirectoryIndex index.php
?AllowOverride none
?Require all denied
</Directory>

<IfModule mpm_prefork_module>
?StartServers 5
?MinSpareServers 5
?MaxSpareServers 10
?MaxClients 30
?MaxRequestsPerChild 2500
</IfModule>

<Files ".ht*">
?Require all denied
</Files>

IncludeOptional sites-enabled/*.conf


Устанавливаем корневой каталог Apache:
ServerRoot "/etc/httpd"

Каталог где будут храниться файлы сайтов:
DocumentRoot "/website"

Подгружаем конфигурационные файлы:
Include conf.modules.d/*.conf

От какого пользователя запускаем сервер:
User apache

От какой группы запускаем сервер:
Group apache

Указываем IP и порт с которых будем принимать запросы, снаружи этот сервер видно не будет:
Listen 127.0.0.1:8080

Имя хоста и порт для определения самого себя:
ServerName 127.0.0.1:8080

Адрес электронной почты который отправляется клиенту в случае ошибок:
ServerAdmin root@localhost

Отключаем отправку информации версии системы и сервера Apache:
ServerSignature Off

Отключаем отправку клиенту в заголовке информацию о Apache:
ServerTokens Prod

Ограничиваем использование памяти 750 мегабайтами:
RLimitMEM 786432000

Максимальное время приёма запроса, обработки, отправки контента серверу Nginx:
TimeOut 250

Устанавливаем кодировку:
AddDefaultCharset utf-8

Задаём язык содержимого:
DefaultLanguage ru

Отключаем обработку большого количества запросов в одном соединении:
KeepAlive Off

Выключить генерацию Content-MD5 заголовков HTTP:
ContentDigest Off

Apache статику отдавать не будет, поэтому отключаем:
EnableSendfile off

Записываем ошибки Apache по указанному пути /etc/httpd/logs/error_log:
ErrorLog "logs/error_log"

Указываем c какого уровня записывать ошибки:
LogLevel error

Подключить mimetypes:
<IfModule mime_module>
?TypesConfig /etc/mime.types
</IfModule>

Секция Directory:
<Directory />
?...
</Directory>

Внутри блока Directory, в случае указания пути до каталога, по умолчанию отдавать index.php::
DirectoryIndex index.php

Внутри блока Directory, запретить переопределение информации доступа в .htaccess:
AllowOverride none

Внутри блока Directory, запретить доступ к файлам сервера:
Require all denied

Секция mpm_prefork_module:
<IfModule mpm_prefork_module>
?...
</IfModule>

Внутри блока mpm_prefork_module, после запуска Apache создать 5 процессов:
StartServers 5

Внутри блока mpm_prefork_module, минимальное количество неиспользуемых процессов (если все процессы будут заняты, то запустятся новые свободные процессы):
MinSpareServers 5

Внутри блока mpm_prefork_module, максимальное количество неиспользуемых (запасных) процессов:
MaxSpareServers 10

Внутри блока mpm_prefork_module, максимальное количество дочерних процессов которые можно запустить одновременно, остальные встают в очередь (с увеличением дочерних процессов, увеличивается потребление памяти):
MaxClients 30

Внутри блока mpm_prefork_module, после указанного числа обработанных запросов, процесс перезапускается (необходимо при переполнении — утечки памяти):
MaxRequestsPerChild 2500

Закрываем доступ к .htaccess:
<Files ".ht*">
?Require all denied
</Files>

Подгружаем конфигурационные файлы:
IncludeOptional sites-enabled/*.conf

Для каждого сайта создаём виртуальный хост Apache.

Добавляем пользователя apache в группу каждого сайта:
[root@test ~]# usermod -a -G name.site apache

Создаём каталог под конфигурационные файлы виртуальных хостов Apache:
[root@test ~]# mkdir /etc/httpd/sites-enabled

Создаём конфигурационный файл:
[root@test ~]# touch /etc/httpd/sites-enabled/name.site.conf

Открываем файл:
[root@test ~]# nano /etc/httpd/sites-enabled/name.site.conf

Редактируем и сохраняем:
/etc/httpd/sites-enabled/name.site.conf
<VirtualHost *:8080>
?ServerName name.site
?ServerAlias www.name.site

?DocumentRoot /website/name.site/www

?<Directory "/website/name.site">
??AllowOverride None
??Require all granted
?</Directory>

?DirectoryIndex index.php

?ErrorLog /website/name.site/logs/error.log
?CustomLog /website/name.site/logs/requests.log combined
</VirtualHost>



Блок VirtualHost, указывается какой порт слушать:
<VirtualHost *:8080>
?...
</VirtualHost>

Имя домена:
ServerName name.site

Зеркало домена:
ServerAlias www.name.site

Каталог где будут храниться файлы этого сайта:
DocumentRoot /website/name.site/www

Открыть доступ к файлам сайта:
Require all granted

Если путь указан до каталога, по умолчанию открывать:
DirectoryIndex index.php

Путь к журналу ошибок Apache конкретного сайта:
ErrorLog /website/name.site/logs/error.log

Путь к журналу доступа:
CustomLog /website/name.site/logs/requests.log combined

Проверка Nginx и Apache.

Добавляем Apache в автозагрузку:
[root@test ~]# systemctl enable httpd.service

Создаём, редактируем и сохраняем файл:
[root@test ~]# touch /website/name.site/www/index.php
[root@test ~]# nano /website/name.site/www/index.php

Копируем конфиг php:
[root@test ~]# cp /etc/httpd/conf.d/php.conf /etc/httpd/sites-enabled/php.conf

Запускаем Nginx и Apache:
[root@test ~]# systemctl start nginx.service
[root@test ~]# systemctl start httpd.service

Настраиваем PHP.

Открываем php.ini:
[root@test ~]# nano /etc/php.ini

Редактируем и сохраняем:
/etc/php.ini
engine = On
expose_php = Off
short_open_tag = Off
zlib.output_compression = Off
disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec, parse_ini_file, show_source, etc

display_startup_errors = Off
display_errors = Off
log_errors = On
error_log = "/usr/local/zend/var/log/php.log"
ignore_repeated_errors = Off
ignore_repeated_source = Off
html_errors = On

implicit_flush = Off
output_buffering = 4K
realpath_cache_size = 2M
realpath_cache_ttl = 1800
zend.enable_gc = On

max_input_time = 200
max_execution_time = 30
file_uploads = On

memory_limit = 256M
post_max_size = 8M
upload_max_filesize = 2M
max_file_uploads = 4

extension_dir = "/usr/local/zend/lib/php_extensions"
date.timezone = Europe/Moscow
default_mimetype = "text/html"
default_charset = "UTF-8"

variables_order = "CGPS"
register_argc_argv = Off
auto_globals_jit = On
enable_dl = Off

allow_url_fopen = On
allow_url_include = Off


Включаем интерпретатор PHP, по необходимости можно выключить на конкретном сайте:
engine = On

Отключаем заголовки отправляемые клиенту о PHP:
expose_php = Off

Отключаем короткую запись тегов PHP <?… ?>:
short_open_tag = Off

Выключаем сжатие страниц:
zlib.output_compression = Off

Отключаем опасные функции:
disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec, parse_ini_file, show_source, etc

Не выводить на экран ошибки возникшии во время старта PHP:
display_startup_errors = Off

Не показывать ошибки:
display_errors = Off

Логируем ошибки, после выключения их вывода на экран:
log_errors = On

Файл в который будут записываться ошибки:
error_log = "/usr/local/zend/var/log/php.log"

Не записывать одинаковые ошибки, которые проиcходят в конкретном файле и строке (ignore_repeated_source — нужно выключить):
ignore_repeated_errors = Off

При включении не записывает одинаковые ошибки, которые могут происходить в разных файлах и строках, поэтому выключаем:
ignore_repeated_source = Off

Выключить HTML теги при просмотре сообщений об ошибках:
html_errors = On

Складываем данные в буфер:
implicit_flush = Off

Буферизация вывода для всех файлов, максимальное количество:
output_buffering = 4K

Используем кэш realpath, тем самым уменьшая количество вызовов stat():
realpath_cache_size = 2M

Установим время хранения кэша 30 минут:
realpath_cache_ttl = 1800

Включаем сборщик циклических ссылок:
zend.enable_gc = On

Указываем максимальное время в течении которого будут приниматься данные на сервер (POST, GET, HEAD), время измеряется с запуска PHP до момента выполнения скрипта:
max_input_time = 200

Указываем максимальное время выполнения скрипта (значение не больше чем в Apache — Timeout) — вместо set_time_limit:
max_execution_time = 30

Разрешить загрузку файлов на сервер:
file_uploads = On

Максимальный размер памяти, который можно использовать скрипту:
memory_limit = 256M

Максимальный размер данных, отправляемых методом POST (должно быть меньше — memory_limit):
post_max_size = 8M

Максимальный размер закачиваемого файла (должно быть меньше — post_max_size):
upload_max_filesize = 2M

Количество файлов, которые можно передать за один запрос:
max_file_uploads = 4

Путь до каталога с модулями расширения:
extension_dir = "/usr/local/zend/lib/php_extensions"

Устанавливаем временную зону:
date.timezone = Europe/Moscow

Тип данных:
default_mimetype = "text/html"

Устанавливаем кодировку UTF-8:
default_charset = "UTF-8"

Порядок обработки переменных — $_COOKIE, $_GET, $_POST, $_SERVER:
variables_order = "CGPS"

Не объявлять переменные argv и argc:
register_argc_argv = Off

Переменные SERVER и ENV будут создаваться в момент использования, что приводит к увеличению производительности:
auto_globals_jit = On

Выключаем динамическую подгрузку, влияет на безопасность:
enable_dl = Off

Разрешаем работу с внешними файлами по URL:
allow_url_fopen = On

Отключаем использование внешних файлов:
allow_url_include = Off

Устанавливаем и настраиваем MySQL.

Отрываем my.cnf:
[root@test ~]# nano /etc/mysql/my.cnf

Количество параллельных процессов, обрабатывающих конкурентные запросы к MySQL (количество ядер умноженных на два):
thread_concurrency = 4

Устанавливаем кодировку по умолчанию для новых таблиц:
default-character-set = utf8

Будем использовать таблицы InnoDB:
default-storage-engine = InnoDB

Устанавливаем размер буфера индексов таблиц в оперативной памяти (актуально для таблиц MyISAM):
key_buffer_size = 5M

Буфер данных и индексов таблиц — InnoDB:
innodb_buffer_pool_size = 300M

Максимальный размер оперативной памяти, выделяемой для временных таблиц, создаваемых MySQL:
tmp_table_size = 50M

Максимальное количество открытых таблиц, которые будут находиться в кэше:
table_open_cache = 64

Буфер данных, который используется для записи информации на диск — InnoDB:
innodb_log_buffer_size = 0M

Отключаем кэширование запросов:
query_cache_size = 0

Размер буфера который используется для сортировки (ORDER BY) или группировки GROUP BY) данных в каждом потоке:
sort_buffer_size = 512K

Выделяем для каждого потока память на каждую таблицу, при увеличении этого значения может пострадать скорость выполнения запроса:
read_buffer_size = 512K

Влияет на скорость сортировки, для запросов с — ORDER BY:
read_rnd_buffer_size = 1M

Размер буфера с использованием JOIN, если не используются индексы в этих запросах:
join_buffer_size = 2M

Размер стека, место для хранения списка задач (открыть или закрыть таблицу, выполнить запрос и т.п.):
thread_stack = 1M

Выделяем память для буфера соединения и его результатов, может быть увеличено до max_allowed_packet:
net_buffer_length = 30K

Максимальный размер данных, которые можно передать за один запрос:
max_allowed_packet = 5M

Максимальное количество одновременных соединений:
max_connections = 75

Количество соединений, которые могут стоять в очереди:
back_log = 250

Слушать только localhost:
bind-address = 127.0.0.1

Не использовать TCP/IP соединения, передавать данные через сокет:
skip-networking

Чтобы рассчитать примерное потребление оперативной памяти на сервере MySQL (насколько я понял) можно воспользоваться следующей формулой (не забывайте, что серверу Apache уже выделено 750 МБ и ещё нужно оставить серверу Nginx):
key_buffer_size + innodb_buffer_pool_size + tmp_table_size + ((sort_buffer_size + read_buffer_size + read_rnd_buffer_size + join_buffer_size + thread_stack) ? max_connections) = ?

Немного про безопасность.

Под root заходить нежелательно, поэтому создаём нового пользователя:
[root@test ~]# adduser newuser

Задаём пароль пользователю — newuser:
[root@test ~]# passwd newuser

Устанавливаем пакет sudo:
[root@test ~]# yum install sudo

Заносим нового пользователя в sudo:
[root@test ~]# gpasswd -a newuser wheel

Если вы подключаетесь к SSH через 22 порт, то нужно его изменить, открываем sshd_config:
[root@test ~]# nano /etc/ssh/sshd_config

Меняем порт на любой свободный (не забываем через установленный у вас firewall закрыть 22 порт и открыть новый, например 54139):
Port 54139

Запрещаем попытку входа с пустым паролем:
PermitEmptyPasswords no

Запретим вход в терминал root:
PermitRootLogin no

Разрешим логиниться в терминале только новому пользователю —
newuser:
AllowUsers newuser

Перезагружаем ssh:
[root@test ~]# service sshd restart


P.S. Можно использовать Nginx с php-fpm, но есть такое мнение, что при правильно настроенном Apache особой разницы в производительности не наблюдается.

Особое внимание хотелось обратить на безопасность и производительность сервера, поэтому если вы нашли ошибки или недочёты, просим написать это в комментариях и в случае необходимости мы внесём изменения в статью.
Поделиться с друзьями
-->

Комментарии (40)


  1. varnav
    28.09.2016 13:17

    LAPM это что такое? Всю жизнь был LAMP.


    1. XAKPM
      29.09.2016 08:20

      Спасибо за замечание, опечатался )


  1. iwram
    28.09.2016 13:20
    +2

    По поводу безопасности. Советую воспользоваться бесплатной утилитой nmap и посмотреть какими портами смотрит ваш сервер в мир. Вот например ваша машина которую вы настраивали.
    Starting Nmap 6.40 ( http://nmap.org ) at 2016-09-28 17:13 KRAT
    Nmap scan report for srv180-vps-st.jino.ru (81.177.165.220)
    Host is up (0.13s latency).
    Not shown: 985 filtered ports
    PORT STATE SERVICE
    22/tcp open ssh
    80/tcp open http
    443/tcp open https
    1443/tcp closed ies-lm
    49153/tcp open unknown
    49154/tcp open unknown
    49155/tcp open unknown
    49157/tcp open unknown
    49158/tcp open unknown
    49159/tcp open unknown
    49160/tcp open unknown
    49163/tcp open unknown
    49167/tcp open unknown
    49176/tcp open unknown
    49400/tcp open compaqdiag
    Device type: general purpose
    Running: Linux 3.X
    OS CPE: cpe:/o:linux:linux_kernel:3
    OS details: Linux 3.0 — 3.9

    Поменяйте стандартный порт 22 на другой свободный (посмотрите например файлик cat /var/log/security, там будет много роботов).
    Также если есть боязнь потерять управление при смене порта ssh. поставьте бесплатную панель управления https://vestacp.com/ (например потерял подключение по ssh, можете подключиться через панель управления и рестартануть сервис или сменить порт на другой и поправить настройки файрвола). Ну и конечно поменять потом стандартный порт весты на другой.
    Не было упоминаний про файрвол. Следует обратить внимание на безопасность. :)


    1. varnav
      28.09.2016 13:22

      А UDP порты не сканируете?


    1. DarkTwin
      28.09.2016 13:28

      Поменяйте стандартный порт 22 на другой свободный

      Так port knocking модно, да и старый добрый Fail2ban не забудем.
      На счет «Весты» — тяжелая она и наверное избыточна в данном случае.


      1. skurudo
        28.09.2016 15:27

        Есть Advanced install — можно поставить только те компоненты, которые будут нужны.


    1. varnav
      28.09.2016 17:34

      Менять 22 порт на другой — это не защита а игра в прятки.
      Защита — это отключение парольного входа (только по ключу), отключение SSH для root, fail2ban.


      1. iwram
        29.09.2016 06:00

        Согласен. Забыл дописать про fail2ban и вход для root.
        По защитам и безопасности есть отдельные статьи, где данные вопросы очень хорошо освящены. Своим комментарием я хотел показать, что даже после настройки (в которой ты уверен), нужно все равно перепроверить используя различные утилиты и проверять доступ извне.


  1. varnav
    28.09.2016 13:22
    +2

    Очень не хватает пояснений почему такое большое количество настроек изменяется. Чем предложенные варианты лучше тех, которые установлены по умолчанию.


    1. KlimovDm
      28.09.2016 14:09

      А ничем. Тут почти все по умолчанию, все изменения скорее косметические, чем для тюнинга.


      1. varnav
        28.09.2016 17:33

        Ну вот и мне так же показалось…


  1. thunderspb
    28.09.2016 13:25
    +2

    Читал-читал… Надеялся увидеть нафига ставить апач… Так и не нашел. А почему не nginx+php-fpm? И тогда уж не LAMP, а LNAMP?

    ЕМНИП после установки sudo еще в конфиге нужно раскомментить %wheel группу… Хотя может уже и не надо.

    Отказоусточивость — где? Безопасность? Порт ssh поменяли? Ну хотябы тогда уж в nginx включили бы naxsi…

    Ах да, про firewall забыл… но это уже другая история :)


    1. thunderspb
      28.09.2016 13:47

      Еще, почему порт 80? а где ssl?

      А еще в nginx лучше модно upstream.

      Ну и fail2ban уже упомянули выше


      1. thunderspb
        28.09.2016 13:56

        Ой, SELinux же забыл!


    1. igurylev
      29.09.2016 08:23

      > в конфиге нужно раскомментить %wheel группу
      В CentOS 7 уже не нужно, эта строчка раскомментирована и так.
      > Нафига ставить апач
      Чтобы беспроблемно работали правила в .htaccess, в противном случае для каждой cms-ки придётся править конфиг nginx-а.


    1. XAKPM
      29.09.2016 11:18

      Спасибо


  1. simpleadmin
    28.09.2016 13:36
    +11

    Я, конечно, тоже использую хабр как записную книжку, но не до такой же степени.


    1. XAKPM
      29.09.2016 10:37

      Как уже отмечено в статье, устанавливаем и настраиваем первый раз. Хотелось услышать в комментариях полезные советы и кроме того может кому то пригодится.


      1. simpleadmin
        29.09.2016 10:49
        +2

        В данном случае совет только один, прежде чем писать почитайте, в частности по nginx читать:
        — всё подряд от VBart
        — действительно хорошие методы борьбы с флудом от kyprizel
        — просто бест-практик от lexore — https://habrahabr.ru/post/231277/
        и т.п.


  1. KorP
    28.09.2016 14:42
    +2

    Обновить систему, при этом сохранить устаревшие версии пакетов:

    [root@test ~]# yum update

    на дворе был 2016 год, на Хабре учили обновлять центось :(


  1. G-M-A-X
    28.09.2016 18:10
    +3

    >Nginx, Apache

    Зачем 2?

    >Настраивать сервер как Вы уже поняли, будем первый раз, поэтому о актуальности статьи можно будет судить из комментариев.

    Корелляции тут 0. :)

    >Установим кодировку по умолчанию:
    charset utf-8;

    Вряд ли так стоит делать…

    >Перенаправить запрос Apache:
    proxy_pass http://localhost:8080/;

    проксировать следует только php.

    >Читать заголовок запроса клиента не более 10 секунд:
    client_header_timeout 10;

    Мобилки могут сказать привет :)

    >client_body_timeout 25;
    и
    client_max_body_size 8m;

    У клиента должна быть скорость интернета от 2,6 mbps.

    >Если клиент не принимает ответ более 8 секунд, сбрасываем соединение:
    send_timeout 8;

    Опять мобилки :)

    Забыли прописать хост по умолчанию… :)

    >Отключаем обработку большого количества запросов в одном соединении:
    KeepAlive Off

    Почему?

    >Подключить mimetypes:
    <IfModule mime_module>
    ?TypesConfig /etc/mime.types


    Зачем, статику ж отдает nginx?

    >Закрываем доступ к .htaccess:
    <Files ".ht*">
    ?Require all denied


    Лучше на nginx закрыть…


    1. XAKPM
      29.09.2016 11:10

      > Nginx, Apache

      >> Зачем 2?

      Ответил в начале статьи.

      > Установим кодировку по умолчанию:
      charset utf-8;

      >>Вряд ли так стоит делать…

      Почему?

      По тайм-аутам поправил.

      >Подключить mimetypes:
      <IfModule mime_module>
      ?TypesConfig /etc/mime.types

      >>Зачем, статику ж отдает nginx?

      У меня не запустился Apache без указания mimetypes


      1. G-M-A-X
        29.09.2016 14:19

        >Ответил в начале статьи.

        Но на самом деле вы проксируете не только php… :)

        >Почему?

        Потому что достаточно указать мета-тег кодировки в html.
        Возможны случаи (хз как сейчас), что клиент не будет обращать внимание на мета-тег при установленном хедере.

        Тем более вы кодировку по умолчанию указываете на двух серверах.


      1. G-M-A-X
        29.09.2016 14:41

        В догонку.
        Если client_body_timeout это между 2-мя операциями чтения, то увеличивать до 100 не нужно было. :)
        Можно было оставить 25. :)
        По умолчанию 60 сек.


  1. VBart
    29.09.2016 00:00
    +6

    Целый ряд вредных советов по настройке nginx, ни чем не обоснованных значений директив.


    1. XAKPM
      30.09.2016 04:36

      Можете привести несколько «правильных» примеров? Прочитаю в ближайшее время ваши публикации, посмотрел у вас тоже всё начиналось с минусовой кармы ))


      1. VBart
        30.09.2016 12:47
        +3

        Начните с того, что не трогайте настройки, которые вы до конца не понимаете как работают. Вот с какой целью вы выключили proxy_buffering? Это требуется в очень редких случаях, а в остальных ведет только к снижению производительности и расходу ресурсов. Зачем включили multi_accept? Зачем вообще трогали keepalive_timeout? Зачем спиливаете заголовки Range? Хотели защитить Apache, для этого есть директива max_ranges, хотя эта уязвимость была исправлена более 5 лет назад и если вы с тех пор не обновлялись, то у вас в любом случае проблемы. Вы также неправильно понимаете что содержится в переменной $proxy_add_x_forwarded_for. Указание localhost в директиве proxy_pass вместо явного IP-адреса, может приводить к тому, что он будет резолвиться в IPv4 и IPv6, при этом Apache у вас слушает только на IPv4. Остальные настройки тоже вызывают вопросы. К примеру, вы зачем-то зарезервировали место под хранение 10 000 файловых дескрипторов в каждом рабочем процессе на 3 минуты. Иными словами вы предполагаете, что ваш сервер будет практически непрерывно раздавать одновременно до 10 тысяч различных файлов. И это учитывая, что при этом вы установили максимально 1024 соединения на рабочий процесс.


        В чем была цель написания данного материала? Статьи тут пишут для того, чтобы делиться знанием, а не незнанием. А вопросы в стиле "помогите разобраться, исправьте мои ошибки" — для этого существуют другие ресурсы. Те же списки рассылки, например. Существует платная поддержка, люди платят деньги, чтобы кто-то их консультировал, исправлял ошибки и обучал.


        посмотрел у вас тоже всё начиналось с минусовой кармы ))

        Вы меня с кем-то путаете.


  1. Lelik13a
    29.09.2016 05:53

    А где сжатие трафика Nginx-ом?
    Где настройки буферов проксирования?

    > query_cache_size = 0
    > innodb_log_buffer_size = 0M
    ???

    > table_open_cache = 64
    Для сайтопомойки то?..
    Cтатистику базы анализировать надо, а не с потолка брать.

    > access_log off;
    На спичках сэкономили и убили статистику

    > limit_rate 500K;
    А потом зарезали времена взаимодействия с клиентом, да ограничили MaxClients 30 — пусть повисят подольше, да жрут побольше.

    > memory_limit = 256M
    щедро, не bitrix ли часом?

    А где apc/opcache/xcache?


  1. shep
    29.09.2016 08:33

    В CentOS 7 Minimal по-умолчанию включен SELinux, который, по идее, пока вы не проставите правильный контекст для папок /website/* не даст вашим веб-серверам и php работать нормально.
    Т.к. Вы несколько раз делаете акцент на безопасности, удивлен что о SELinux нем ничего нет.
    Но главное, что Ваша инструкция не начинается как большинство, даже официальных: «1. Отключаем SELinux. 2...n Настраиваем»


  1. troyanskiy
    29.09.2016 08:35

    P.S. Можно использовать Nginx с php-fpm, но есть такое мнение, что при правильно настроенном Apache особой разницы в производительности не наблюдается.

    Если надо особо хитро настраивать apache чтобы не было разницы, то зачем нужен apache?
    Имхо чем проще система (меньше «звеньев»), тем легче в обслуживании…


    1. thunderspb
      29.09.2016 11:48

      Я бы даже сказал, что правильно настроенный работает и без nginx :)


      1. troyanskiy
        29.09.2016 12:13

        Это уже зависит от «религии» и нужд «приложения». Кто-то ставить nginx, кто-то apache. Но ставить оба, как-то не вижу смысла, разве что как ступень перехода от одного к другому.
        Я лично стараюсь использовать по минимуму… Есть сервер, который отдает только статику, он на nginx и больше там ничего не надо, на сервере бекэнда стоит только node.js без каких либо других веб серверов, т.к. они там не нужны.


        1. thunderspb
          29.09.2016 13:47

          не, ну так я и спросил у ТС — нафига там апач вообще? htaccess легко переписывается в nginx, есть простенькие онлайн конвертеры. для популярных cms легко найти примеры конфигов. Зачем этот жирный апач ставить? Я уже давно избавился от него на своих серверах. Ну не нужен он :) nginx просто проксирует запросы на бекенды и раздает статику. Дойдут руки — поковыряю openresty…


          1. KlimovDm
            29.09.2016 14:12

            > Ну не нужен он :) nginx просто проксирует запросы на бекенды и раздает статику

            Ну, если вы поглядите конфиги, то увидите то же самое. nginx у авторов отдает статику и проксирует динамику на локальный интерфейс, на котором висит apache (backend типа). Похоже Lelik13a прав — там bitrix :)


        1. G-M-A-X
          29.09.2016 14:25
          +1

          apache под nginx нужен для .htaccess на шаред хостинге.

          Но это не случай автора, он .htaccess вроде отключил.


          1. XAKPM
            30.09.2016 04:31

            Это сделано намерено, на любом хосте можно включить .htaccess


            1. G-M-A-X
              30.09.2016 11:54

              Но вы не шаред хостинг и выключили (не пользуетесь). :)

              Смысла в Апаче 0. :)

              Только память жрет.


              1. XAKPM
                30.09.2016 15:13

                CMS потому что. + разные сайты крутятся на этом сервере.


  1. SicYar
    29.09.2016 08:35
    +1

    Неплохой такой конечно ман для самых-самых маленьких)) а почему не XAMMP? лично мне нравится, все супер быстро, на nginxe наружу прокинул и наслаждайся. А почему CentOS? Сейчас VPS с огромным количеством осей на все вкусы есть. Хотя бы какое то обоснование да и конкретику по технологиям было бы интересно прочитать в тексте.


  1. MarvinD
    29.09.2016 15:09

    Кстати, ценнейший комментарий от shep насчет SELinix. Для начинающих, на кого ориентирована статья, это может стать преградой. Отключать SELinux — очень плохаяспорная мысль.

    Добавьте для читателей простоту использования «ls -Z», «semanage fcontext -a -t httpd_log_t <путь-до-лога>», «restorecon -Rv». Для вас это, возможно, очевидно, но для новичков — вряд ли.

    Потом, настройки firewall вообще не раскрыты, а между тем на CentOS 7 по-умолчанию стоит нетривиальный для новичков firewalld. Возможно, есть смысл его отключить и настроить iptables по-старинке.

    SSH, независимо от порта, на котором он будет работать, использовать намного лучше с ключами. Раз вы работаете из Putty, хотя бы отметьте, что есть puttygen и как его едят.

    Вопросы защиты всего описанного вами комбайна встанут сразу как только вы его подключите к интернет. Сразу, а не через 2 месяца.

    fail2ban, на мой взгляд, крайне желательно поставить.

    И да, новички хотят понимать, зачем им ставить сразу nginx и apache.

    В общем, я бы разделил статью на части:
    1. подготовка хоста с CentOS 7 под свой LAMP. Упор на безопасность.
    2. собственно, настройка элементов LAMP.
    3. политика резервирования всего этого хозяйства, восстановление после сбоя. rsync — ок. Конкретно, как? rsync через ssh — прекрасно. Как? И самое главное, пример (хотя бы на виртуалку) восстановления после сбоя.

    С моей точки зрения, домашний LAMP неплохо делать на виртуальных машинах. На том же CentOS настраиваете kvm, создаете гостевую гигов на 30. И в нее уже все что вы описали, за что вам спасибо! И бекапить виртуалку и восстанавливать ее после сбоя в разы может быть проще.

    Я сам такие статьи пишу для себя, как мануал для личного пользования, на хабр выложить не решаюсь, вот и сижу в ридонли. А вы молодец, решились. Удачи!