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

552 lines
27 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
source: https://habr.com/ru/company/nixys/blog/646023
tags: [lemp, mariadb]
---
> [!seealso] Все части
> * [Часть 1](Часть%201.md)
> * [Часть 2](Часть%202.md)
> * [Часть 3](Часть%203.md)
![[5962ff0237364c535317a7c24dda1ddb.jpg]]
## Введение
Статья является обучающим материалом для начинающих администраторов, а также для разработчиков, которые хотели бы познакомиться с миром администрирования проектов. Если вы являетесь опытным администратором, можете смело пропускать данный материал.
Целью серии статей является описание подготовки работы сервера со стеком LEMP ( #Linux, #nginx, #MySQL, #PHP), отмечу, что в качестве php интерпретатора здесь используется #apache2, а не php-fpm, так как показывает практика многим разработчикам по прежнему необходим файл `.htaccess`, работу с которыми php-fpm из коробки не поддерживает.
Со своей стороны мы переносим правила из файла `.htaccess` в nginx необходимости установки php-fpm, однако это также занимает определенное время, зачастую разработчикам проще и быстрее внести нужные правила для текущих площадок именно в `.htaccess` файл. Также статьи описывают развертывание стэка и поднятие на нем работающих площадок. Инструкция подойдет для небольших Bitrix проектов, а тажке для проектов развернутых под любой популярной CMS.
Не смотря на то, что тема уже достаточно подробно отражена в сети, мы решили подробно описать общие стандарты администрирования с нуля, поскольку регулярно получаем большое количество базовых вопросов от людей, так или иначе, связанных с нашей сферой.
Целью статей не является показать как развернуть идеальное окружение, а лишь указать на нюансы в работе и защитить начинающих специалистов от базовых ошибок при настройке.
## Базовая настройка nginx
После базовой настройки основных компонентов сервера, пора начинать настраивать веб-сервера, начнем с nginx. Пакет уже находится в стандартных репозиториях #Debian, поэтому выполняем простую установку:
```shell
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
```
Если всё ок, то перечитываем конфигурацию веб-сервера:
```shell
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. Устанавливаем необходимые пакеты:
```shell
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** и меняем порт:
```diff
-Listen 80
+Listen 81
```
В нашем случае apache2 работает с модулем **mpm_prefork**, поэтому включаем модуль командой:
```shell
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, для этого потребуется активировать следующие модули с помощью команд:
```shell
a2enmod remoteip
a2enmod rewrite
```
Если после этого в логах apache2 площадки фигурирует `127.0.0.1`, то необходимо также внести следующие изменения в формат логов:
```diff
--- 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`:
```shell
diff --git a/etc/apache2/conf-available/security.conf b/etc/apache2/conf-available/security.conf
```
```diff
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`:
```diff
@@ -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:
```shell
chmod 750 /etc/apache2
```
После выполнения всех этих действий необходимо проверить синтаксис apache2:
```
apache2ctl -t
Syntax OK
```
После перезапустить веб-сервер:
```shell
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. Перед началом установки добавляем ключ репозитория командой:
```shell
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:
```shell
apt update
apt install mysql-server
```
Установка запросит дважды ввести пароль от пользователя root.
Возможно потребуется модуль для работы с python, устанавливаем его командой:
```shell
apt install python-mysqldb
```
После установки приступаем к базовой настройке. По умолчанию `ulimit` (максимальное) ограничение для открытых файлов в системе для процесса составляет `1024`, что очень мало, особенно для работы СУБД, увеличим лимит файлов до `8192` через systemctl:
```shell
systemctl edit mysql
```
Вставляем следующий текст:
```
[Service]
LimitNOFILE = 8192
```
Перечитываем лимиты и перезагружаем MySQL:
```shell
systemctl daemon-reload
systemctl restart mysql
```
Указываем кодировку СУБД по умолчанию, в нашем случае это `UTF8`, для этого вносим изменения в файл `/etc/mysql/my.cnf`:
```diff
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 для пользователей системы:
```shell
chmod 750 /etc/mysql
chown root:mysql /etc/mysql
```
Перезапускаем СУБД и проверяем статус работы:
```shell
service mysql restart
service mysql status
```
Для того, чтобы каждый раз при входе в консоль MySQL не указывать пароль от **root** пользователя, создаем файл в домашней директории **root** и задаем ему права безопасности:
```shell
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 доступов для площадки
- Настройка почтовых записей таким образом, чтобы почта отправляемая с сервера не попадала в СПАМ.
В комментариях к предыдущей статье я увидел много критики касательно содержания и уровня материала. Я не соглашусь с тем, что статьи подобного уровня ненужны сообществу. Как показывает практика нашей компании, очень много клиентов еще не готовы и контейнеризации своего проекта, в связи с чем спрос на информацию подобного плана еще высок. Данный материал не панацея, а лишь базовая инструкция, которая должна прояснить базовые моменты и указать администратору на особенности, которые нужно или не нужно делать в начале пути.