> For the complete documentation index, see [llms.txt](https://antons-organization-1.gitbook.io/administrirovanie-linux/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://antons-organization-1.gitbook.io/administrirovanie-linux/servisy-linux/veb-server/nginx/ustanovka-i-nastroika-nginx.md).

# Установка и настройка Nginx

Создадим непривилегированного пользователя, в нашем случае **webuser**:

```
adduser webuser
```

Появится интерактивный диалог, в ходе которого необходимо будет задать пароль (New password), подтвердить его (Retype new password), остальные пункты можно не заполнять, просто нажимая ENTER. В последнем вопросе Is the information correct? \[Y/n] необходимо нажать Y и нажать ENTER.

Добавляем пользователя webuser в группу sudo для повышения привилегий:

```
usermod -aG sudo webuser
```

## Установка Nginx

Веб-сервер Nginx может быть установлен как непосредственно на физическую машину, так и в виде контейнера. В данный момент мы рассмотрим установку и настройку на физической машине.

### Debian

Для начала обновим репозитории:

`apt update`

После чего, установим сам nginx:

`apt install nginx -y`

### CentOS

Добавьте EPEL-репозиторий:

```
sudo yum install epel-release
```

Установите Nginx:

```
sudo yum install nginx
```

### Nginx в Docker

Для установки Docker, нужно подготовить систему. Устанавливаем необходимые пакеты:

```
apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
```

Будет задан вопрос: Do you want to continue? \[Y/n]\
Нажимаем Y, затем ENTER.

Добавляем GPG ключ официального репозитория Docker в систему:

```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```

В следующей строке появится надпись OK, добавляем репозиторий Docker:

```
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```

Теперь необходимо обновить информацию о пакетах:

```
apt update
```

Проверим, что установка Docker будет происходить из его репозитория:

```
apt-cache policy docker-ce
```

В ответ должны получить много строк, среди которых должен присутствовать адрес репозитория, добавленный ранее, в нашем примере это:

```
https://download.docker.com/linux/ubuntu focal/stable
```

Ставим сам Docker:

```
apt install docker-ce
```

Будет задан вопрос: Do you want to continue? \[Y/n]\
Нажимаем Y, затем ENTER.

Дожидаемся окончания процесса установки. После docker будет автоматически запущен и добавлен в автозагрузку. Проверим:

```
systemctl status docker
```

В выводе команды должна присутствовать строка **Active: active (running)**, значит процесс-демон работает.

```
systemctl is-enabled docker
```

В ответе увидели «enabled», значит docker успешно добавлен в автозагрузку. На этом установка Docker завершена, переходим к запуску в контейнере веб-сервера nginx.

Создадим проект и его структуру папок в домашнем каталоге нашего пользователя webuser:

```
mkdir -p /home/webuser/myproject/www
```

```
mkdir -p /home/webuser/myproject/nginx_logs
```

```
echo '<html><body>Hello from NGINX in Docker!</body></html>' > /home/webuser/myproject/www/index.html
```

Устанавливаем и запускаем nginx в Docker одной командой:

```
docker run --name nginx_myproject -p 8080:80 -v /home/webuser/myproject/www:/usr/share/nginx/html -v /home/webuser/myproject/nginx_logs:/var/log/nginx -d nginx
```

Docker скачает официальный образ nginx с Docker Hub, сконфигурирует и запустит контейнер.

Здесь:

* **nginx\_myproject** – имя контейнера, создаваемого на базе образа nginx.
* Конструкция **–p 8080:80** выполняет проброс портов, с порта 8080 локальной машины на порт 80 контейнера.
* Флаги **–v** по аналогии с портом – пробрасывают локальную директорию внутрь контейнера, т.е. директория */home/webuser/myproject/www* на локальной машине будет доступна в контейнере как */usr/share/nginx/html*, и */home/webuser/myproject/nginx\_logs* в контейнере это */var/log/nginx*.

Проверяем, работает ли контейнер:

```
docker ps
```

Вывод команды должен быть примерно следующим:

```
CONTAINER ID   IMAGE     COMMAND                  CREATED       STATUS       PORTS                  NAMES
f35d422d233a   nginx     "/docker-entrypoint.…"   7 hours ago   Up 7 hours   0.0.0.0:8080->80/tcp   nginx_myproject
```

Стоит обратить внимание на столбец NAMES, где обнаруживаем имя созданного ранее контейнера nginx\_myproject, колонка STATUS, в которой отображается состояние контейнера, в данном случае он работает уже 7 часов. Если набрать в адресной строке браузера IP адрес сервера и через двоеточие порт, используемый контейнером 8080, т.е. конструкцию вида 123.123.123.123:8080, то в ответ получим:

```
«Hello from NGINX in Docker!»
```

Мы научились запускать веб-сервер nginx в контейнере!

Проброс портов, папок, а так же многий другой функционал, предоставляемый контейнеризацией, должен быть использован исходя из поставленных задач, разнообразие которых выходит за рамки данной статьи. **Дальнейшее описание работы с nginx рассматривается в рамках работы непосредственно на сервере, без контейнеризации.**

## Настройте брандмауэр

Перед дальнейшей работой с Nginx необходимо разрешить HTTP/HTTPS трафик на сервере

### UFW

Для вывода списка конфигураций приложений, которые известны `ufw`, необходимо ввести следующую команду:

```
sudo ufw app list
```

Необходимо получить список профилей приложений:

```
OutputAvailable applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
```

Как показал вывод, есть три профиля, доступных для Nginx:

* **Nginx Full**: этот профиль открывает порт 80 (обычный веб-трафик без шифрования) и порт 443 (трафик с шифрованием TLS/SSL)
* **Nginx HTTP**: этот профиль открывает только порт 80 (обычный веб-трафик без шифрования)
* **Nginx HTTPS**: этот профиль открывает только порт 443 (трафик с шифрованием TLS/SSL)

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

Для активации можно ввести следующую команду:

```
sudo ufw allow 'Nginx HTTP'
```

Для проверки изменений введите:

```
sudo ufw status
```

Вывод укажет, какой трафик HTTP разрешен:

```
OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)
```

### Firewalld

Разрешите HTTP и HTTPS-трафик на брандмауэре:

```
sudo firewall-cmd --permanent --add-service=http 

sudo firewall-cmd --permanent --add-service=https
```

Перезагрузите брандмауэр:

```
sudo firewall-cmd --reload
```

### Iptables

Для добавления разрешающих правил в Iptables рекомендую воспользоваться командами, представленными ниже

#### **HTTP**

```css
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT
```

#### **HTTPS**

```css
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
```

После чего следует сохранить данные правила (см. [Iptables, firewalld, ufw, nftables](/administrirovanie-linux/setevye-nastroiki-linux/iptables-firewalld-ufw-nftables.md#sokhranenie-pravil))

## Запуск nginx

Стартуем наш веб-сервер:

```
service nginx start
```

Проверяем статус:

```
service nginx status
```

Если в статусе присутствует строка **Active: active (running)**, значит сервер работает. Также в этом можно убедиться, набрав в адресной строке браузера IP адрес сервера, будет отображено приветственное сообщение от nginx, которое выглядит так:

<figure><img src="https://selectel.ru/blog/wp-content/uploads/2021/03/image7-1.png" alt="" height="226" width="526"><figcaption></figcaption></figure>

## Иерархия каталогов Nginx

Администрирование сервера nginx в основном заключается в настройке и поддержке его файлов конфигурации, которые находятся в папке ***/etc/nginx***. Рассмотрим подробнее:

* ***`/etc/nginx/nginx.conf`*** – главный файл конфигурации nginx.
* ***`/etc/nginx/sites-available`*** – каталог с конфигурациями виртуальных хостов, т.е. каждый файл, находящийся в этом каталоге, содержит информацию о конкретном сайте – его имени, IP адресе, рабочей директории и многое другое.
* ***`/etc/nginx/sites-enabled`*** – в этом каталоге содержаться конфигурации сайтов, обслуживаемых nginx, т.е. активных, как правило, это символические ссылки sites-available конфигураций, что очень удобно для оперативного включения и отключения сайтов.

Также, рассмотрим файлы журналов:

* **`/var/log/nginx/access.log`**: каждый запрос к вашему веб-серверу регистрируется в этом файле журнала, если Nginx не настроен иначе.
* **`/var/log/nginx/error.log`**: любые ошибки Nginx будут регистрироваться в этом журнале.

## Команды Nginx

Рассмотрим несколько команд, которые полезно знать администратору. После внесения изменений в конфигурационные файлы сервера, рекомендуется провести их синтаксический контроль:

```
nginx -t
```

Если все хорошо, в результате получим сообщение:

```
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

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

```
nginx –v
```

Можно получить расширенную информацию об nginx – его версию, параметры конфигурации сборки:

```
nginx –V
```

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

```
service nginx reload
```

## Настройка Nginx

Рассмотрим главный конфигурационный файл nginx — */etc/nginx/nginx.conf*. По умолчанию он выглядит следующим образом:

```
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
        worker_connections 768;
}
http {
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
        gzip on;
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}
```

Конфигурационный файл состоит из директив. О них и пойдет речь дальше.

### Директивы

Существует два вида директив – **простые** и **блочные**.&#x20;

Простая директива состоит из имени и параметров, разделённых пробелами, и в конце строки ставится точкой с запятой (**;**).&#x20;

Блочная директива устроена так же, как и простая директива, но вместо точки с запятой после имени и параметров следует набор дополнительных инструкций, помещённых внутри фигурных скобок (**{** и **}**). Рассмотрим те, которые пригодятся нам для примера:

* **user** – пользователь, от имени которого работает nginx, здесь это www-data;
* **worker\_processes** – количество процессов сервера, значение выставляется равным количеству ядер процессора, auto – сервер определит автоматически;
* **pid** – файл, внутри которого хранится идентификатор запущенного главного процесса (PID);
* **include** – подключаемый файл или файлы конфигурации;
* **events** – блок директив, определяющих работу с сетевыми соединениями;
* **worker\_connections** – максимальное количество одновременных соединений;
* **http** – блок директив http сервера;
* **sendfile** – метод отправки данных, включаем значением on;
* **tcp\_nopush** и **tcp\_nodelay** – параметры, положительно влияющие на производительность, оставляем значение on;
* **keepalive\_timeout** – время ожидания keepalive соединения до его разрыва со стороны сервера;
* **types\_hash\_max\_size** – регламентирует максимальный размер хэш таблиц типов;
* **default\_type** – указывает тип MIME ответа по умолчанию;
* **ssl\_protocols** – включает указанные протоколы;
* **ssl\_prefer\_server\_ciphers** – указывает, что серверное шифрование; предпочтительнее клиентского, при использовании SSLv3 и TLS протоколов;
* **access\_log** – задает путь к файлу лога доступа, при выставлении значения в off, запись в журнал доступа будет отключена;
* **error\_log** – путь к журналу регистрации ошибок;
* **gzip** – при помощи этой директивы можно включать или отключать сжатие.

### Переменные в nginx

В конфигурационных файлах nginx допустимо пользоваться встроенными переменными. Преимущественно это переменные, представляющие собой поля заголовка запроса клиента, такие как *$remote\_addr*, *$server\_name*. Все переменные начинаются со знака *$*, с полным перечнем можно ознакомиться в документации, на официальном сайте.

## Установка и настройка php-fpm

Для работы веб приложений, написанных на языке PHP необходимо установить **php-fpm** в качестве backend'а:

```
apt install php-fpm php-mysql -y
```

После установки сервис будет автоматически запущен и добавлен в автозагрузку. Создаем файл пула для конкретного сайта *sampledomain.ru*:

```
touch /etc/php/7.4/fpm/pool.d/sampledomain.ru.conf
```

```
nano /etc/php/7.4/fpm/pool.d/sampledomain.ru.conf
```

Создаем следующую конфигурацию:

```
[sampledomain.ru]
listen = /var/run/php/sampledomain.ru.sock
listen.mode = 0666
user = webuser
group = webuser
chdir = /home/webuser/www/sampledomain.ru

php_admin_value[upload_tmp_dir] = /home/webuser/tmp
php_admin_value[soap.wsdl_cache_dir] = /home/webuser/tmp
php_admin_value[date.timezone] = Europe/Moscow
php_admin_value[upload_max_filesize] = 100M
php_admin_value[post_max_size] = 100M
php_admin_value[open_basedir] = /home/webuser/www/sampledomain.ru/
php_admin_value[session.save_path] = /home/webuser/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source
php_admin_value[cgi.fix_pathinfo] = 0
php_admin_value[apc.cache_by_default] = 0

pm = dynamic
pm.max_children = 7
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
```

Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: */etc/php/7.4/fpm/pool.d/sampledomain.ru.conf*, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.

Необходимо создать структуру каталогов веб проекта:

```
mkdir -p /home/webuser/www/sampledomain.ru
```

```
mkdir -p /home/webuser/tmp
```

Задаем владельца каталогов и находящихся внутри файлов:

```
chown -R webuser:webuser /home/webuser/www/
```

```
chown -R webuser:webuser /home/webuser/tmp/
```

Перезагружаем сервис php-fpm, чтобы он мог перечитать файлы конфигураций:

```
service php7.4-fpm restart
```

Проверяем, что сервис перезапустился корректно и наша новая конфигурация *sampledomain.ru* обслуживается:

```
service php7.4-fpm status
```

О том, что сервис запущен, свидетельствует наличие строки **Active: active (running)**, чуть ниже список обслуживаемых конфигураций в виде дерева, где можно увидеть php-fpm: pool sampledomain.ru, значит все работает.

## Конфигурация nginx

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

У нас имеется главный конфигурационный файл, содержимое которого оставляем неизменным для примера. Создадим файл виртуального хоста:

```
touch /etc/nginx/sites-available/sampledomain.ru.conf
```

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Заполняем его следующим содержимым:

```
server
        {
        listen 80;
    	  server_name sampledomain.ru www.sampledomain.ru;
        charset utf-8;
        root /home/webuser/www/sampledomain.ru;
        index index.php index.html index.htm;

    # Static content
        		location ~* ^.+.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|mp3|bmp|flv|rtf|js|swf|iso)$ {
      root /home/webuser/www/sampledomain.ru;
                   }

    location ~ \.php$
        {
          include fastcgi.conf;
          fastcgi_intercept_errors on;
          try_files $uri =404;
          fastcgi_pass unix://var/run/php/sampledomain.ru.sock;
        }

    location / {
        try_files $uri $uri/ /index.php?q=$uri$args;
    }
    }
```

Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: */etc/nginx/sites-available/sampledomain.ru.conf*, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.

Создаем символическую ссылку на данный виртуальный хост из директории */etc/nginx/sites-available* в директорию */etc/nginx/sites-enabled*, чтобы nginx его обслуживал:

```
ln -s /etc/nginx/sites-available/sampledomain.ru.conf /etc/nginx/sites-enabled/
```

Создаем файл для тестирования работы связки nginx и php-fpm:

```
echo "<?php phpinfo(); ?>" > /home/webuser/www/sampledomain.ru/index.php
```

Добавляем пользователя www-data в группу webuser:

```
usermod -aG webuser www-data
```

Конфиги написаны, директории созданы, перезапускаем nginx для того, чтобы он перечитал файлы конфигураций:

```
service nginx restart
```

Переходим в браузере по адресу *<http://sampledomain.ru>* и должны увидеть такую картину:

<figure><img src="https://selectel.ru/blog/wp-content/uploads/2021/03/image5-1.png" alt="" height="392" width="952"><figcaption></figcaption></figure>

Все настроили правильно.

> Если вы хотите проверить работу nginx на клиенте windows, для начала необходимо добавить следующую запись в ваш файл hosts:
>
> IP-адрес\_сервера sampledomain.ru
>
> После чего доступ к сайту по доменному имени будет успешен!

## Настройка SSL сертификата

Получение SSL сертификата необходимо для использования протокола HTTPS. Данный протокол защищает соединение между сервером и клиентом, особенно критично для чувствительных данных, таких как логины, пароли, данные по банковским картам, переписка и так далее. Последние несколько лет поисковые системы наиболее лояльны к сайтам, использующих данный протокол, есть прекрасная возможность получить ssl сертификат бесплатно от Let’s Encrypt, устанавливаем его клиент certbot из официального репозитория:

```
apt install certbot python3-certbot-nginx
```

Будет задан вопрос: Do you want to continue? \[Y/n]\
Нажимаем Y, затем ENTER.

Запрашиваем сертификат у Certbot:

```
certbot certonly --agree-tos -m mymail@yandex.ru --webroot -w /home/webuser/www/sampledomain.ru/ -d sampledomain.ru
```

Появится вопрос о передаче вашего адреса электронной почты компании партнеру: (Y)es/(N)o:\
Жмем Y, потом ENTER.

Сертификат успешно получен, если появилось сообщение:

```
IMPORTANT NOTES:
 — Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/sampledomain.ru/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/sampledomain.ru/privkey.pem
   Your cert will expire on 2021-05-27. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 — Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 — If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le 
```

Сертификат действителен 90 дней. Теперь необходимо позаботиться об автоматическом продлении сертификатов, открываем файл:

```
nano /etc/cron.d/certbot
```

Приводим его к следующему виду:

```
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew --renew-hook "systemctl reload nginx"
```

Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: */etc/cron.d/certbot*, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.

Дважды в день будет происходить проверка необходимости обновления сертификатов на сервере, если какому-либо осталось 30 дней и меньше до истечения срока действия – он будет обновлен, а nginx перезагружен.

Протестируем процесс обновления без внесения изменений:

```
certbot renew --dry-run
```

Ждем около полминуты, на экран будет выведен подробный отчет. Если присутствует строка **Congratulations, all renewals succeeded** – значит все настроено правильно. Если когда-либо в процессе обновления произойдет сбой – Let’s Encrypt уведомит о приближающимся конце срока действия сертификата по электронной почте, указанной при первом запросе.

В данном случае приведет пример получения сертификатов Let's Encrypt, во время демэкзамена может быть выдана задача выдать самоподписанный сертификат OpenSSL, в таком случае рекомендую ознакомиться с соответствующей ссылкой внизу, а также с [Broken mention](broken://pages/E2tdae1JoS07M97K9loZ)

## Редирект с http на https

После получения сертификата необходимо прописать директивы в файл конфигурации виртуального хоста, отвечающие за поддержку SSL. Сразу же реализуем перенаправление всех запросов, приходящих на 80-й порт к порту 443, т.е. с http протокола на https. Открываем файл:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Приводим его к следующему виду:

```
server {
        listen 80;
        server_name sampledomain.ru www.sampledomain.ru;
        root /home/webuser/www/sampledomain.ru;
        return 301 https://sampledomain.ru$request_uri;
        }
server
        {
        listen 443 ssl;
        server_name sampledomain.ru www.sampledomain.ru;
        # SSL support
        ssl_certificate /etc/letsencrypt/live/sampledomain.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sampledomain.ru/privkey.pem;
        charset utf-8;
        root /home/webuser/www/sampledomain.ru;
        index index.php index.html index.htm;

        # Static content
        location ~* ^.+.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|mp3|bmp|flv|rtf|js|swf|iso)$ {
                        root /home/webuser/www/sampledomain.ru;
                   }

        location ~ \.php$
        {
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                try_files $uri =404;
                fastcgi_pass unix://var/run/php/sampledomain.ru.sock;
        }

        location / {
                try_files $uri $uri/ /index.php?q=$uri$args;
        }
        }
```

Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: */etc/nginx/sites-available/sampledomain.ru.conf*, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.

Перезапускаем веб-сервер:

```
service nginx restart
```

Теперь в браузере при попытке перехода по адресу **<http://sampledomain.ru>** будет выполнено перенаправление на **<https://sampledomain.ru>**

## Кэширование в nginx

Основная задача кэширования – это минимизация времени доступа к данным. Nginx умеет работать с несколькими видами кэширования: на стороне сервера, на стороне клиента. Серверное кэширование может иметь самую разнообразную конфигурацию, в зависимости от архитектуры проекта. Поэтому в нашем частном случае рассмотрим кэширование на стороне клиента (браузера) для статического контента.

Открываем файл нашего тестового виртуального хоста:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Находим location, указывающий на отдачу статического контента и добавляем директиву expires:

```
# Static content
        location ~* ^.+.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|mp3|bmp|flv|rtf|js|swf|iso)$ {
                        root /home/webuser/www/sampledomain.ru;
                        expires 1d;
                   }
```

Как обычно сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. В данном случае файлы, расширения которых соответствуют приведенным выше, будут храниться в браузере клиента, только после истечения суток – они будут запрошены повторно.

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

## Мониторинг nginx

В nginx существует стандартная возможность мониторинга работы сервера, выясним доступность модуля в нашей сборке:

```
nginx -V 2>&1 | grep -o with-http_stub_status_module
```

Если в ответ получили **with-http\_stub\_status\_module** – модуль доступен. Рассмотрим включение мониторинга на примере виртуального хоста, открываем файл:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Добавляем *location /nginx\_status*, в итоге файл выглядит следующим образом:

```
server {
        listen 80;
        server_name sampledomain.ru www.sampledomain.ru;
        root /home/webuser/www/sampledomain.ru;
        return 301 https://sampledomain.ru$request_uri;
        }
server
        {
        listen 443 ssl;
        server_name sampledomain.ru www.sampledomain.ru;
        # SSL support
        ssl_certificate /etc/letsencrypt/live/sampledomain.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sampledomain.ru/privkey.pem;
        charset utf-8;
        root /home/webuser/www/sampledomain.ru;
        index index.php index.html index.htm;

        # Static content
        location ~* ^.+.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|mp3|bmp|flv|rtf|js|swf|iso)$ {
                        root /home/webuser/www/sampledomain.ru;
                        expires 1d;
                   }

        location ~ \.php$
        {
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                try_files $uri =404;
                fastcgi_pass unix://var/run/php/sampledomain.ru.sock;
        }

        location / {
                try_files $uri $uri/ /index.php?q=$uri$args;
        }
        location /nginx_status {
                stub_status on;
                access_log off;

        }
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем веб-сервер:

```
service nginx restart
```

В браузере при переходе по адресу **sampledomain.ru/nginx\_status** будет представлена статистика работы сервера:

```
Active connections: 2 
server accepts handled requests
 797 797 334 
Reading: 0 Writing: 1 Waiting: 1
```

* **Active connections** – текущее количество клиентских соединений;
* **accepts** – принятые соединения;
* **handled** – обработанные, обычно равно количеству принятых;
* **requests** – количество клиентских запросов;
* **Reading** – текущее количество соединений, для которых сервер читает заголовок запроса;
* **Writing** – текущее количество соединений, для которых сервер отправляет ответ клиенту;
* **Waiting** – текущее количество простаивающих соединений, для которых сервер ожидает запроса.

Также статистику можно получить из командной строки:

```
curl https://sampledomain.ru/nginx_status
```

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

## Проксирование запросов

Nginx умеет проксировать запросы на другие сервера, понадобиться это для масштабирования и защиты back-end серверов. В качестве примера, запустим back-end сервер apache в контейнере:

```
docker run --name backend_apache -p 8081:80 -d httpd
```

Дожидаемся процесса скачивания образа, контейнер запуститься автоматически, убеждаемся, что среди запущенных контейнеров присутствует **backend\_apache**:

```
docker ps
```

Открываем файл виртуального хоста:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Изменим блок *location /* так, чтобы при обращении к sampledomain.ru запрос был передан веб-серверу apache, работающему в контейнере:

```
location / {
                proxy_pass http://127.0.0.1:8081;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Real-IP $remote_addr;
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем веб-сервер:

```
service nginx restart
```

Директива **proxy\_pass** задает протокол, адрес и порт проксируемого ресурса, **proxy\_set\_header** директивы настраивают заголовки запросов, передают проксируемому ресурсу информацию о соединении.

Если перейти в браузере по адресу **<http://sampledomain.ru>**, можно увидеть *«It works!»*, отдаваемый ранее созданным контейнером с apache.

## Балансировка нагрузки

Для улучшения отказоустойчивости, масштабируемости, уменьшения время отклика, распределения полезной нагрузки придумали балансировщики нагрузок. На примере посмотрим, как приспособить для этого nginx.

Открываем файл виртуального хоста:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Над блоком *server* добавляем следующее:

```
upstream backends {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}
```

Также вносим изменения в блок *location /*:

```
location / {
                proxy_pass http://backends;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Real-IP $remote_addr;
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем веб-сервер:

```
service nginx restart
```

Директива upstream перечисляет все back-end сервера, между которыми следует распределить нагрузку. В блоке location / изменился параметр директивы proxy\_pass на <http://backends>, где backends – имя, которое присвоили группе серверов директивы upstream.

Ранее мы запустили два контейнера: первый с nginx на порту 8080, второй с apache на порту 8081. Теперь перейдя в браузере по ссылке **<http://sampledomain.ru>** и несколько раз обновляя страницу можно наблюдать чередование ответов *«It works!»* и *«Hello from NGINX in Docker!»*, значит балансировка работает.

Существует несколько методов балансировки:

**round-robin** – используется по умолчанию, нагрузка распределяется равномерно между серверами с учетом веса.

**least\_conn** – запросы поступают к менее загруженным серверам.

Пример использования:

```
upstream backends {
    least_conn;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}
```

**ip\_hash** — запросы распределяются по серверам на основе IP-адресов клиентов, т.е. запросы одного и того же клиента будут всегда передаваться на один и тот же сервер, пример:

```
upstream backends {
    ip_hash;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}
```

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

Разберем на примере:

```
upstream backends {
    server 127.0.0.1:8080 weight=5;
    server 127.0.0.1:8081 weight=2;
}
```

В данной конфигурации, из 7 запросов, 5 будет обработано сервером 127.0.0.1:8080, а 2 машиной 127.0.0.1:8081

## Безопасность nginx

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

### HTTP аутентификация

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

Установим утилиту для генерации хешированных паролей:

```
apt install apache2-utils
```

Будет задан вопрос: Do you want to continue? \[Y/n]\
Нажимаем Y, затем ENTER.

Теперь создадим файл, в котором будет содержаться список логинов и паролей пользователей:

```
touch /etc/nginx/conf.d/htpasswd
```

Добавим пользователя user:

```
htpasswd /etc/nginx/conf.d/htpasswd user
```

Будет предложено ввести пароль, вводимые символы не отображаются, это нормально, после нажать ENTER:

```
New password:
```

Ввести повторно тот же пароль:

```
Re-type new password:
```

Появление ответа **Adding password for user user** означает, что все сделано верно. Точно так же можно добавить других пользователей. Чтобы сменить пароль пользователя user – нужно повторно ввести предыдущую команду, данные в файле будут обновлены.

В примере будем защищать доступ к нашему виртуальному хосту, а конкретно к статистике работы сервера, открываем файл конфигурации:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Редактируем *location /nginx\_status* следующим образом:

```
location /nginx_status {
                stub_status on;
                access_log off;
                auth_basic "Enter your credential data: ";
                auth_basic_user_file /etc/nginx/conf.d/htpasswd;

        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем nginx:

```
service nginx restart
```

Теперь при переходе в раздел просмотра статистики **sampledomain.ru/nginx\_status** необходимо будет сначала ввести логин и пароль для доступа к разделу, в противном случае сервер выдаст ошибку: *401 Authorization Required*.

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

### Ограничение доступа по IP адресу

В качестве примера отредактируем тренировочный виртуальный хост:

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Рассмотрим блок *location /nginx\_status*, приведем его к виду:

```
location /nginx_status {
                stub_status on;
                access_log off;
                allow 192.168.0.0/24;
                allow 192.168.1.1;
                deny all;
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем nginx:

```
service nginx restart
```

В данном примере разрешен доступ для компьютеров из сети 192.168.0.0 с маской подсети 255.255.255.0 (/24) и хоста с адресом 192.168.1.1. Для всех остальных доступ закрыт.

### Комбинация ограничений

Рассмотрим ситуацию, когда имеется предприятие, с внутренней сетью 192.168.0.0/24, и сотрудники из нее должны беспрепятственно попадать в нужный раздел, но в то же время необходимо предоставить доступ снаружи, используя авторизацию по логину и паролю. Тогда *location /nginx\_status* принимает следующий вид:

```
location /nginx_status {
                stub_status on;
                access_log off;
                satisfy any;
                allow 192.168.0.0/24;
                deny all;
                auth_basic "Enter your credential data: ";
                auth_basic_user_file /etc/nginx/conf.d/htpasswd;
        }
```

Сфокусируем внимание на директиве **satisfy**. В данном случае она имеет параметр any, что означает предоставление доступа при выполнении хотя бы одного из условий. При смене параметра на all – сотрудникам предприятия будет разрешен доступ только из внутренней сети с аутентификацией по логину и паролю.

### Предотвращение DDoS атак

DDoS — это распределенная атака отказа в обслуживании, происходит с нескольких IP адресов, направлена на ухудшение или полное отсутствие доступности сервера за счёт огромного количества запросов. Чаще всего, это происки недобросовестных конкурентов, реже из хулиганских побуждений. В nginx предусмотрен механизм, позволяющий, если не полностью подавить атаку, то как минимум смягчить ее влияние на работу системы.

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

```
nano /etc/nginx/sites-available/sampledomain.ru.conf
```

Доводим до следующего состояния:

```
limit_req_zone $binary_remote_addr zone=one:10m rate=90r/m;
limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
        listen 80;
        server_name sampledomain.ru www.sampledomain.ru;
        root /home/webuser/www/sampledomain.ru;
        return 301 https://sampledomain.ru$request_uri;
        }
server
        {
        listen 443 ssl;
        server_name sampledomain.ru www.sampledomain.ru;
        # SSL support
        ssl_certificate /etc/letsencrypt/live/sampledomain.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sampledomain.ru/privkey.pem;
        charset utf-8;
        root /home/webuser/www/sampledomain.ru;
        index index.php index.html index.htm;

        # Static content
        location ~* ^.+.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|mp3|bmp|flv|rtf|js|swf|iso)$ {
                        root /home/webuser/www/sampledomain.ru;
                        expires 1d;
                   }

        location ~ \.php$
        {
                limit_req zone=one;
                limit_conn addr 10;
    		    include fastcgi.conf;
                fastcgi_intercept_errors on;
                try_files $uri =404;
                fastcgi_pass unix://var/run/php/sampledomain.ru.sock;
        }

        location / {
                try_files $uri $uri/ /index.php?q=$uri$args;
        }
        location /nginx_status {
                stub_status on;
                access_log off;
                satisfy any;
                allow 192.168.0.0/24;
                deny all;
                auth_basic "Enter your credential data: ";
                auth_basic_user_file /etc/nginx/conf.d/htpasswd;
        }
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем nginx:

```
service nginx restart
```

* **limit\_req\_zone** – директива, хранящая состояние ключа, в нашем случае это адрес клиента *$binary\_remote\_addr*, в зоне *one*, размером 10 Мб, со скоростью обработки запросов не превышающая 90 в минуту.
* **limit\_req** – директива в *location \~ .php$*, ссылающаяся на зону разделяемой памяти.
* **limit\_conn\_zone** – директива, хранящая состояние ключа, в нашем случае это адрес клиента *$binary\_remote\_addr*, в зоне *addr*, размером 10Мб.
* **limit\_conn** — директива в *location \~ .php$*, ссылающаяся на зону разделяемой памяти, задающая лимит на количество соединений с одного IP адреса, в данном случае 10.

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

## Ошибки nginx

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

### 502 bad gateway

Эта ошибка говорит о том, что back-end, обрабатывающий запрос от nginx – перестал отвечать. Произойти это могло также по нескольким причинам. Во-первых, back-end мог упасть полностью и для восстановления его необходимо запустить. Во-вторых, если nginx и back-end сервер находятся на физически разных машинах – между ними могла банально пропасть связь. Для проверки необходимо воспользоваться командой ping. Так же, возможно, часть процессов php-fpm перегружены или не хватает их количества для обслуживания всех клиентов, тогда эта ошибка будет иметь «плавающий» характер. Открываем файл:

```
nano /etc/php/7.4/fpm/pool.d/sampledomain.ru.conf
```

Если действительно проблема в нехватке процессов — стоит «покрутить» следующие настройки:

```
pm = dynamic
pm.max_children = 7
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
```

### 504 Gateway Time-out

Одна из причин возникновения ошибки – превышение времени ожидания ответа от сервера, например от php-fpm. Такое случается, когда скрипты php долго выполняются или зависли. Если обработка запроса требует большего времени – увеличим время ожидания на передачу запроса **fastcgi\_send\_timeout** и получение ответа **fastcgi\_read\_timeout**, редактируем блок *location \~ .php$*:

```
location ~ \.php$
        {
                limit_req zone=one;
                limit_conn addr 2;
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                try_files $uri =404;
                fastcgi_pass unix://var/run/php/sampledomain.ru.sock;
                fastcgi_send_timeout 120;
                fastcgi_read_timeout 120;
        }
```

Сохраняем результат Ctrl+O, подтверждаем нажатием ENTER, выходим из редактора Ctrl+X. Перезапускаем nginx:

```
service nginx restart
```

### 413 Request Entity Too Large

Ошибка возникает, когда на сервер загружается файл, превышающий значение директивы **client\_max\_body\_size**, по умолчанию – 1 Мб. Добавим в блок *server*:

```
server {
	### остальные директивы
client_max_body_size 50m;
	### остальные директивы
}
```

В примере максимально допустимый размер тела запроса клиента увеличен до 50 Мб. При повторном возникновении ошибки – снова увеличить. Не забываем сохраняться и после изменений – перезапускать nginx:

```
service nginx restart
```

Искать причины возникновения тех или иных ошибок правильнее всего в логах, которые находятся в папке */var/log/nginx/*. Однако, у начинающего администратора возникают сложности с интерпретацией, содержащейся в них информации.

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

{% embed url="<http://nginx.org/ru/docs/example.html>" %}

{% embed url="<https://selectel.ru/blog/install-nginx/>" %}

{% embed url="<https://webguard.pro/web-services/nginx/generacziya-ssl-sertifikata-dlya-nginx-openssl.html>" %}

{% embed url="<https://jino.ru/spravka/articles/nginx_server_blocks.html#%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85-%D1%85%D0%BE%D1%81%D1%82%D0%BE%D0%B2>" %}
