Данный материал является серией статей, вы можете ознакомиться с остальными частями по следующим ссылкам:
https://habr.com/ru/company/nixys/blog/645451/ - первая часть
https://habr.com/ru/company/nixys/blog/646023/ - вторая часть
Статья является обучающим материалом для начинающих администраторов, а также для разработчиков, которые хотели бы познакомиться с миром администрирования проектов. Если вы являетесь опытным администратором, можете смело пропускать данный материал.
Целью серии статей является описание подготовки работы сервера со стеком LEMP (Linux, Nginx, MySQL, PHP), отмечу, что в качестве PHP интерпретатора здесь используется Apache2, а не PHP-FPM, так как показывает практика многим разработчикам по прежнему необходим файл.htaccess, работу с которыми PHP-FPM из коробки не поддерживает.
Со своей стороны мы переносим правила из файла .htaccess в Nginx при необходимости установки PHP-FPM, однако это также занимает определенное время, зачастую разработчикам проще и быстрее внести нужные правила для текущих площадок именно в .htaccess файл. Также статьи описывают развертывание стэка и поднятие на нем работающих площадок. Инструкция подойдет для небольших Bitrix проектов, а тажке для проектов развернутых под любой популярной CMS.
Не смотря на то, что тема уже достаточно подробно отражена в сети, мы решили подробно описать общие стандарты администрирования с нуля, поскольку регулярно получаем большое количество базовых вопросов от людей, так или иначе, связанных с нашей сферой.
Целью статей не является показать как развернуть идеальное окружение, а лишь указать на нюансы в работе и защитить начинающих специалистов от базовых ошибок при настройке.
Во второй частье статьи будут отражены такие темы как:
Базовая настройка Nginx
Базовая настройка Apache2
Базовая настройка MySQL
Базовая настройка Nginx
После базовой настройки основных компонентов сервера, пора начинать настраивать веб-сервера, начнем с Nginx. Пакет уже находится в стандартных репозиториях Debian, поэтому выполняем простую установку:
apt update
apt install nginx
Nginx в нашей конфигурации будет являться точкой входа http/https трафика и обрабатывать статичные данные. После установки начинаем конфигурировать веб-сервер, для этого переходим к файлу /etc/nginx/nginx.conf и приводим его к следующему виду:
user www-data;
worker_processes auto;
worker_priority -15;
include /etc/nginx/modules-enabled/*.conf;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format nixys '$remote_addr\t"$host"\t[$time_local]\t$status\t"$request"\t$request_time ($upstream_response_time)\t$bytes_sent\t"$http_referer"\t"$http_user_agent"';
log_format nixys-debug '$remote_addr\t"$host"\t[$time_local]\t$status\t"$request"\t"req_time: $request_time"\t"bytes_sent: $bytes_sent"\n'
'\t\t\t\t\t\t\t\t"req_file: $request_filename"\t"$http_user_agent"\t"$http_referer"\n'
'\t\t\t\t\t\t\t\t"Request completed: $request_completion"\n'
'\t\t\t\t\t\t\t\t"Body request: $request_body"\n';
access_log /var/log/nginx/access.log nixys;
sendfile on;
tcp_nodelay on;
gzip on;
gzip_proxied any;
gzip_comp_level 4;
gzip_vary on;
gzip_types text/css text/plain application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
server_tokens off;
server_names_hash_bucket_size 33;
reset_timedout_connection on;
client_header_timeout 15;
client_body_timeout 15;
send_timeout 5;
keepalive_timeout 30 15;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Пробегусь по основным изменениям, которые мы добавляем относительно стандартной конфигурации:
worker_priority -15;
Данная строка повышает приоритет процессов Nginx в системе. Это нужно для того, чтобы при высокой нагрузке приоритет обработки отдавался процессам Nginx, что позволит отображать статичные данные площадки
worker_connections 1024;
Повышаем количество соединений одного рабочего процесса для увеличения количества запросов в обработке. Данный параметр можно не изменять, в случае если у вас слабый сервер.
Обязательно включаем сжатие передаваемых данных:
gzip on;
gzip_proxied any;
gzip_comp_level 4;
gzip_vary on; gzip_types text/css text/plain application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
Также хочется отметить следующий формат логов:
log_format nixys '$remote_addr\t"$host"\t[$time_local]\t$status\t"$request"\t$request_time ($upstream_response_time)\t$bytes_sent\t"$http_referer"\t"$http_user_agent"';
log_format nixys-debug '$remote_addr\t"$host"\t[$time_local]\t$status\t"$request"\t"req_time: $request_time"\t"bytes_sent: $bytes_sent"\n'
'\t\t\t\t\t\t\t\t"req_file: $request_filename"\t"$http_user_agent"\t"$http_referer"\n'
'\t\t\t\t\t\t\t\t"Request completed: $request_completion"\n'
'\t\t\t\t\t\t\t\t"Body request: $request_body"\n';
Здесь мы задаем два формата логов для Nginx. Формат логов Nixys будет являться основным, и использоваться для всех виртуальных хостов по умолчанию. Подключенные с ним логи выглядят следующим образом:
31.31.192.22 "site.ru" [18/Dec/2021:06:26:50 +0500] 200 "GET / HTTP/1.1" 0.028 (0.028) 13069 "-" "Mozilla/5.0 (compatible; InterfaxBot/1.0; email:swabuse@interfax.ru)"
Представление логов подобным образом крайне удобно при анализе, разложим строку лога для понимания:
31.31.192.22 – IP адрес клиента
site.ru - название виртуального хоста
18/Dec/2021:06:26:50 +0500 – время поступления запроса
200 – код ответа, полученный в результате выполнения запроса
0.028 – время обработки запроса Nginx
(0.028) - время обработки запроса со стороны, которой Nginx передал запрос (при необходимости). В нашем случае здесь будет отражено время, за которое Apache2 обработал соединение.
13069 - это размер переданных данных в байтах
"Mozilla/5.0 (compatible; InterfaxBot/1.0; email:swabuse@interfax.ru)" – user-agent, переданные клиентом.
Со своей стороны мы считаем данный формат логирования наиболее удачным, так как он позволяет максимально проанализировать ситуацию в случае возникновения проблем в работе площадки.
После внесения этих изменений необходимо перечитать файлы веб-сервера. При любой операции reload или restart сервиса Nginx необходимо обязательно протестировать конфигурацию на наличие ошибок с помощью команды nginx -t, многие администраторы вначале работы забывают об этом, что может привести к простоям в работе проекта:
nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Если все ок, то перечитываем конфигурацию веб-сервера:
service nginx reload
И обязательно проверяем статус:
service nginx status
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled
Active: active (running) since Sun 2021-12-19 19:55:16 MSK; 36min ago
Docs: man:nginx(8)
Process: 2913 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
Main PID: 2246 (nginx)
Tasks: 3 (limit: 1171)
Memory: 9.3M
CGroup: /system.slice/nginx.service
├─2246 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
├─2914 nginx: worker process
└─2915 nginx: worker process
Обратите внимание, что после перезапуска любой службы необходимо обязательно проверить статус ее работы!
На этом базовую настройку Nginx можно считать завершенной.
Базовая настройка Apache2
Переходим к настройке Apache2. Устанавливаем необходимые пакеты:
apt install apache2 libapache2-mpm-itk
Если вы все делали по статье, то Apache2 сразу после установки не запустится и выдаст ошибку:
Action 'start' failed.
The Apache error log may have more information.
apache2.service: Control process exited, code=exited, status=1/FAILURE
Failed with result 'exit-code'.
Failed to start The Apache HTTP Server.
Дело в том, что веб-сервер по умолчанию работает на том же порту, что и запущенный Nginx. Поэтому нам потребуется изменить стандартный 80 порт веб сервера на 81. Для этого редактируем файл /etc/apache2/ports.conf и меняем порт:
-Listen 80
+Listen 81
В нашем случае Apache2 работает с модулем mpm_prefork, поэтому включаем модуль командой:
a2enmod mpm_prefork
После нам потребуется задать параметры работы воркеров, данные параметры вы можете конфигурировать как угодно, в зависимости от нагрузки проекта; они расположены в файле /etc/apache2/mods-enabled/mpm_prefork.conf, базовая настройка выглядит следующим образом:
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 3
MaxSpareServers 10
MaxRequestWorkers 50
MaxConnectionsPerChild 2000
LimitUIDRange 0 65535
LimitGIDRange 0 65535
</IfModule>
Для того, чтобы каждый раз при проверке синтаксиса Apache2 не всплывало сообщение о том, что имя сервера не объявлено, объявляем его в файле apache2.conf
ServerName MAIN_DOMAIN_NAME
Где MAIN_DOMAIN_NAME это имя основной площадки сервера.
Вам также потребуется привести default виртуальный хост веб-сервера к виду:
<VirtualHost *:81>
ServerName default
ServerAdmin webmaster@localhost
DocumentRoot /usr/share/apache2/default-site
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Изменять порт, на котором работает default виртуальный хост необходимо в соответствии с /etc/apache2/ports.conf. В дальнейшем вы увидите, что логи каждой площадки будут расположены в отдельной директории, однако логи стандартного виртульного хоста будут расположены согласно этим настройкам в /var/log/apache2.
Также очень важно настроить корректное отображение внешнего IP адреса клиентов в логах apache2, для этого потребуется активировать следующие модули с помощью команд:
a2enmod remoteip
a2enmod rewrite
Если после этого в логах apache2 площадки фигурирует 127.0.0.1, то необходимо также внести следующие изменения в формат логов:
--- apache2.conf_old 2016-07-06 18:30:37.423038360 +0500
+++ apache2.conf 2016-07-06 18:27:32.874586631 +0500
@@ -204,8 +204,8 @@
# Use mod_remoteip instead.
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
-LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
-LogFormat "%h %l %u %t \"%r\" %>s %O" common
+LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%a %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
Далее потребуется настроить безопасность веб-сервера, для этого вносим изменения в файл /etc/apache2/conf-available/security.conf:
iff --git a/etc/apache2/conf-available/security.conf b/etc/apache2/conf-available/security.conf
index 599333b..73e4a81 100644
--- a/etc/apache2/conf-available/security.conf
+++ b/etc/apache2/conf-available/security.conf
@@ -22,9 +22,7 @@
# and compiled in modules.
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
# where Full conveys the most information, and Prod the least.
-#ServerTokens Minimal
-ServerTokens OS
-#ServerTokens Full
+ServerTokens Prod
#
# Optionally add a line containing the server version and virtual host
@@ -33,8 +31,7 @@ ServerTokens OS
# documents or custom error documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of: On | Off | EMail
-#ServerSignature Off
-ServerSignature On
+ServerSignature Off
#
# Allow TRACE method
@@ -44,7 +41,6 @@ ServerSignature On
#
# Set to one of: On | Off | extended
TraceEnable Off
-#TraceEnable On
#
# Forbid access to version control directories
А также глобально запрещаем доступ к каталогам .svn, .git, .hg:
@@ -52,9 +48,9 @@ TraceEnable Off
# If you use version control systems in your document root, you should
# probably deny access to their directories. For example, for subversion:
#
-#<DirectoryMatch "/\.svn">
-# Require all denied
-#</DirectoryMatch>
+<DirectoryMatch "/\.(svn|git|hg)">
+ Require all denied
+</DirectoryMatch>
#
# Setting this header will prevent MSIE from interpreting files as something
Последним штрихом в настройке веб-сервера будет установка прав на директорию с apache2:
chmod 750 /etc/apache2
После выполнения всех этих действий необходимо проверить синтаксис Apache2:
apache2ctl -t
Syntax OK
После перезапустить веб-сервер:
service apache2 restart
И как обычно, проверить статус работы:
service apache2 status
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2021-12-19 21:12:12 MSK; 1s ago
Docs: https://httpd.apache.org/docs/2.4/
Process: 3727 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 3731 (apache2)
Tasks: 6 (limit: 1171)
Первоначальную настройку Apache2 можно также считать завершенной.
Базовая настройка MySQL.
Переходим к установке и настройке MySQL, в нашем случае это будет версия 5.7. Перед началом установки добавляем ключ репозитория командой:
wget -q -O- http://repo.mysql.com/RPM-GPG-KEY-mysql | apt-key add -
После добавляем нужный репозиторий в пакетный менеджер apt, для этого в конец файла /etc/apt/sources.list дописываем строки вида
deb http://repo.mysql.com/apt/debian/ buster mysql-5.7
deb-src http://repo.mysql.com/apt/debian/ buster mysql-5.7
Обратите внимание на то, что наш сервер базируется на системе Debian 10 (buster), в случае если вы устанавливаете MySQL на другую версию дистрибутива Debian или Ubuntu, то потребуется учесть название дистрибутива в списке репозиториев.
После выполняем обновление доступных пакетов в репозиториях и устанавливаем MySQL:
apt update
apt install mysql-server
Установка запросит дважды ввести пароль от пользователя root.
Возможно потребуется модуль для работы с python, устанавливаем его командой:
apt install python-mysqldb
После установки приступаем к базовой настройке. По умолчанию ulimit (максимальное) ограничение для открытых файлов в системе для процесса составляет 1024, что очень мало, особенно для работы СУБД, увеличим лимит файлов до 8192 через systemctl:
systemctl edit mysql
Вставляем следующий текст:
[Service]
LimitNOFILE = 8192
Перечитываем лимиты и перезагружаем MySQL:
systemctl daemon-reload
systemctl restart mysql
Указываем кодировку СУБД по умолчанию, в нашем случае это UTF8, для этого вносим изменения в файл /etc/mysql/my.cnf:
diff --git a/mysql/my.cnf b/mysql/my.cnf
[mysqld]
+character-set-server = utf8
+collation-server = utf8_unicode_ci
По умолчанию MySQL слушает только локальный IP адрес 127.0.0.1. В случае если необходимы подключения к СУБД извне, потребуется открыть порт 3306 на уровне фаервола сервера, а также указать MySQL слушать все интерфейсы сервера Для этого параметру bind-address указываем следующее значение:
bind-address = 0.0.0.0
Здесь же в файле my.cnf указываем базовые параметры для работы СУБД:
max_allowed_packet = 32M
thread_stack = 512K
thread_cache_size = 64
open_files_limit = 8192
max_connections = 100
query_cache_limit = 4M
query_cache_size = 16M
Данные параметры могут быть скорректированы под нужды проекта.
Для таблиц innodb задаем хранение в отдельных файлах, чтобы избежать возможных проблем, связанных с ростом файла ibdata1:
innodb_file_per_table
И задаем буфер для innodb обычно он равен 60-80% оперативной памяти сервера. Например, для сервера с количеством оперативной памяти 4GB можем выделить на буфер 3GB оперативной памяти:
innodb_buffer_pool_size = 3GB
Значение также можно скорректировать по мере необходимости.
В качестве безопасности, ограничиваем доступ к MySQL для пользователей системы:
chmod 750 /etc/mysql
chown root:mysql /etc/mysql
Перезапускаем СУБД и проверяем статус работы:
service mysql restart
service mysql status
Для того, чтобы каждый раз при входе в консоль MySQL не указывать пароль от root пользователя, создаем файл в домашней директории root и задаем ему права безопасности:
touch /root/.my.cnf
chmod 600 /root/.my.cnf
Созданный файл должен иметь следующее содержание:
[client]
password = MYSQL_ROOT_PASSWORD
Где MYSQL_ROOT_PASSWORD, это пароль от пользователя root.
Теперь для подключения к консоли MySQL от root достаточно просто ввести команду mysql:
mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 40559777
Server version: 5.7.31-34 Percona Server (GPL), Release '34', Revision '2e68637'
Copyright (c) 2009-2020 Percona LLC and/or its affiliates
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
На этом базовую настройку MySQL можно считать завершенной.
Для оптимизации mysql вы можете использовать утилиту mysqltuner. Она есть в стандартных репозиториях. Суть ее в том, что с помощью скриптов анализируются параметры и текущие показатели mysql. В случае, если наблюдаются неоптимизированные параметры, утилита предложит изменить их. Ниже пример вывода анализа mysqltuner:
-------- Recommendations -----------------------------------------------------
General recommendations:
Run OPTIMIZE TABLE to defragment tables for better performance
Reduce your overall MySQL memory footprint for system stability
Adjust your join queries to always utilize indexes
When making adjustments, make tmp_table_size/max_heap_table_size equal
Reduce your SELECT DISTINCT queries without LIMIT clauses
Variables to adjust:
*** MySQL's maximum memory usage is dangerously high ***
*** Add RAM before increasing MySQL buffer variables ***
query_cache_size (> 16M)
join_buffer_size (> 16.0M, or always use indexes with joins)
tmp_table_size (> 128M)
max_heap_table_size (> 128M)
innodb_buffer_pool_size (>= 11G)
Заключение:
В последней третьей статье будут описаны:
Установка и настройка PHP
Процесс создания и настройки виртуальных хостов для веб-серверов.
Выдача SSH и FTP доступов для площадки
Настройка почтовых записей таким образом, чтобы почта отправляемая с сервера не попадала в СПАМ.
В комментариях к предыдущей статье я увидел много критики касательно содержания и уровня материала. Я не соглашусь с тем, что статьи подобного уровня ненужны сообществу. Как показывает практика нашей компании, очень много клиентов еще не готовы и контейнеризации своего проекта, в связи с чем спрос на информацию подобного плана еще высок. Данный материал не панацея, а лишь базовая инструкция, которая должна прояснить базовые моменты и указать администратору на особенности, которые нужно или не нужно делать в начале пути.
Спасибо за внимание!