tech-tips/Программное обеспечение/LEMP-стек/Настройка LEMP сервера для простых проектов. Инструкция для самых маленьких/Часть 2.md

27 KiB
Raw Permalink Blame History

source tags
https://habr.com/ru/company/nixys/blog/646023
lemp
mariadb

[!seealso] Все части

!5962ff0237364c535317a7c24dda1ddb.jpg

Введение

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

Целью серии статей является описание подготовки работы сервера со стеком LEMP ( #Linux, #nginx, #MySQL, #PHP), отмечу, что в качестве php интерпретатора здесь используется #apache2, а не php-fpm, так как показывает практика многим разработчикам по прежнему необходим файл .htaccess, работу с которыми php-fpm из коробки не поддерживает.

Со своей стороны мы переносим правила из файла .htaccess в nginx необходимости установки php-fpm, однако это также занимает определенное время, зачастую разработчикам проще и быстрее внести нужные правила для текущих площадок именно в .htaccess файл. Также статьи описывают развертывание стэка и поднятие на нем работающих площадок. Инструкция подойдет для небольших Bitrix проектов, а тажке для проектов развернутых под любой популярной CMS.

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

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

Базовая настройка nginx

После базовой настройки основных компонентов сервера, пора начинать настраивать веб-сервера, начнем с nginx. Пакет уже находится в стандартных репозиториях #Debian, поэтому выполняем простую установку:

apt update
apt install nginx

nginx в нашей конфигурации будет являться точкой входа http(s) трафика и обрабатывать статичные данные. После установки начинаем конфигурировать веб-сервер, для этого переходим к файлу /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:

diff --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 доступов для площадки
  • Настройка почтовых записей таким образом, чтобы почта отправляемая с сервера не попадала в СПАМ.

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