Nginx

Настройка uWSGI для работы с INI-файлом

Мы можем поместить в файл те же параметры, которые мы использовали с uWSGI, а затем попросить uWSGI запуститься с этим файлом.

Создайте файл с именем mysite_uwsgi.ini:

# mysite_uwsgi.ini file


# Django-related settings
# the base directory (full path)
chdir           = /path/to/your/project
# Django's wsgi file
module          = project.wsgi
# the virtualenv (full path)
home            = /path/to/virtualenv

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /path/to/your/project/mysite.sock
# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true

И запустите uwsgi, используя этот файл:

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

Еще раз, проверьте, что сайт Django работает, как ожидалось.

Как перезагрузить nginx

Для перезагрузки NGINX используйте или .
Команда в консоли:

service nginx reload

либо

/etc/init.d/nginx reload

либо

nginx -s reload

Эти команды остановят и перезапустят сервер NGINX.

Перезагрузить конфигурационный файл без перезагрузки NGINX можно так:

nginx -s reload

Проверить правильность конфигурации можно командой

nginx -t 

В чём разница между reload и restart

Как происходит перезагрузка в NGINX:

  1. Команда посылается серверу
  2. Сервер анализирует конфигурационный файл
  3. Если конфигурация не содержит ошибок, новые процессы открываются с новой конфигурацией сервера, а старые плавно прекращают свою работу
  4. Если конфигурация содержит ошибки, то при использовании
    1. процесс перезагрузки сервера прерывается, сервер не запускается
    2. сервер откатывается назад к старой конфигурации, работа продолжается

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

Ещё лучше, если вы будете предварительно проверять правильность конфигурации командой , например:

nginx -t && service nginx reload

или

nginx -t && nginx -s reload

Концепция

Веб-сервер может обслуживать статичные файлы (HTML, изображения, CSS и т. д.) напрямую из файловой системы. Но он не может напрямую общаться с приложением на Django. Для этого ему нужно что-то, что будет запускать приложение, отправлять запросы от веб-клиентов (браузеров) и возвращать ответы. Для этого создан Web Server Gateway Interface — WSGI. WSGI — это спецификация, которая описывает, как веб-сервер взаимодействует с веб-приложениями и как веб-приложения могут быть объединены в цепочку для обработки одного запроса.

uWSGI — это одна из реализаций WSGI в Python. В этом руководстве мы настроим uWSGI таким образом, чтобы он создавал сокет или порт и обслуживал запросы/ответы веб-сервера по протоколу uwsgi. В итоге наш полный стек компонентов будет выглядеть так:

the web client <-> the web server <-> the socket/the port <-> uwsgi <-> Django

Решение проблем

Валидация конфигурации

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

При доступе с локального IP перенаправляется на localhost

В файле найдите незакомментированную строку (без вначале) и добавьте под ней:

server_name_in_redirect off;

По умолчанию, nginx перенаправляет любые запросы на указанное в опции имя.

Это из-за того, что сервер FastCGI не запущен или используемый сокет имеет неправильные права доступа.

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

Попробуйте остановить службу и удалить файл доменного юникс сокета по умолчанию.

Затем запустите вместо него.
Проверьте статус и нового доменного юникс сокета :

$ systemctl status fcgiwrap.service
$ ls /run/fcgiwrap.sock

Если это сработало, отключите и включите .

Ошибка: No input file specified

1. Скорее всего у вас не установлена переменная , содержащая полный путь до ваших скриптов. Если конфигурация nginx () правильная, то эта ошибка означает, что php не смог загрузить запрашиваемый скрипт. Часто это просто оказывается ошибкой прав доступа, и вы можете запустить php-cgi с правами root:

# spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/bin/php-cgi

или вам следует создать группу и пользователя для запуска php-cgi:

# groupadd www
# useradd -g www www
# chmod +w /srv/www/nginx/html
# chown -R www:www /srv/www/nginx/html
# spawn-fcgi -a 127.0.0.1 -p 9000 -u www -g www -f /usr/bin/php-cgi

2. Другой причиной может быть то, что задан неправильный аргумент в секции в . Убедитесь, что указывает на ту же директорию, что и в на том же сервере. Либо вы можете просто задать абсолютный путь до корневого каталога, не определяя его в каких-либо location секциях.

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

4

Также обратите внимание, что не только php-скрипты должны иметь права на чтение, но также и вся структура каталогов должна иметь право на исполнение, чтобы пользователь PHP мог добраться до этого каталога.

Ошибка: «File not found» в браузере или «Primary script unknown» в лог-файле

Убедитесь, что вы определили и в ваших директивах или :

 location ~ \.php$ {
      root           /srv/http/root_dir;
      index          index.php;
      fastcgi_pass   unix:/run/php-fpm/php-fpm.sock;
      include        fastcgi.conf;
 }

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

Ошибка: chroot: ‘/usr/sbin/nginx’ No such file or directory

Если у вас возникает эта ошибка при запуске демона nginx в chroot, скорее всего, это происходит из-за отсутствующих 64-битных библиотек в изолированном окружении.

Если ваш chroot запущен в , вам нужно добавить требуемые 64-битные библиотеки.

Сначала создайте каталоги:

# mkdir /srv/http/usr/lib64
# cd /srv/http; ln -s usr/lib64 lib64

Затем скопируйте требуемые 64-битные библиотеки, перечисленные командой в .

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

Альтернативный скрипт для systemd

/etc/nginx/nginx.conf
user http;
pid /run/nginx.pid;

абсолютным путем к файлу является .3

/etc/systemd/system/nginx.service
Description=nginx (Chroot)
After=syslog.target network.target


Type=forking
PIDFile=/srv/http/run/nginx.pid
RootDirectory=/srv/http
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reload
ExecStop=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop


WantedBy=multi-user.target

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

/etc/systemd/system/nginx.path
Description=nginx (Chroot) path

PathExists=/srv/http/site/Public_html

WantedBy=default.target

Включите и замените на in .

Ссылка в файле юнита позволяет systemd следить за процессом (необходим абсолютный путь). Если это нежелательно, вы можете изменить тип one-shoot по умолчанию и удалить ссылку из файла юнита.

Создание настроек для нескольких сайтов

После настройки основного сайта рекомендуем Вам составить список сайтов и определить, какой сайт должен открываться по IP-адресу сервера (если он один). Затем в директории /etc/nginx/sites-available создать файлы с сайтами, заполнить их настройками и сохранить их. Так как сервер учитывает только настройки из директории /etc/nginx/sites-enabled, то необходимо создать символическую ссылку на файл:

$ ln -s /etc/nginx/sites-available/имя_сайта
/etc/nginx/sites-enabled/имя_сайта

Это позволит Вам отключать сайт на время без удаления его конфигурационного файла. Проверить конфигурацию NGINXпосле работ можно командой:

$ sudo nginx -t

Если вывод содержит «syntax is ok» и «test is successful», то можно применить настройки, написав команду:

$ sudo service nginx reload

Устранение проблем

В случае проблем следующие команды помогут найти ошибки.

Проверка конфигурации

Проверьте, что запущенная конфигурация nginx не содержит ошибок.

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

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

Проверка запущенных процессов

Проверьте, запущены ли процессы nginx:

  PID TTY      STAT   TIME COMMAND
26092 ?        Ss     0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
26093 ?        S      0:00 nginx: worker proces

Проверка адреса привязки и портов

Проверьте, что демон nginx прослушивает правильный TCP-порт (например, 80 для HTTP или 443 для HTTPS):

tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN      0          12336835   -26092/nginx: master

Добавление бэкендов

Для того, чтобы начать балансировать нагрузку, необходимо добавить бэкенды в настройки nginx. Для примера, я возьму отдельный виртуальный хост. Идем в его конфиг и в самое начало добавляем три бэкенда через директиву upstream.

upstream cache-api {
    server 10.32.18.6:8080;
    server 10.32.18.7:8080;
    server 10.32.18.8:8080;
}

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

location / {
    proxy_pass http://cache-api/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }

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

weight Задает вес сервера, по умолчанию 1. Чем больше вес сервера, тем пропорционально больше запросов он будет принимать от балансировщика.
max_conns Ограничивает максимальное число одновременных активных соединений к проксируемому серверу Значение по умолчанию равно 0 и означает, что ограничения нет.
max_fails Задаёт число неудачных попыток работы с сервером, которые должны произойти в течение времени, заданного параметром fail_timeout, чтобы сервер считался недоступным на период времени, также заданный параметром fail_timeout. Дефолтное значение — 1.
fail_timeout Задаёт время, в течение которого должно произойти заданное число неудачных попыток работы с сервером для того, чтобы сервер считался недоступным и время, в течение которого сервер будет считаться недоступным. По умолчанию параметр равен 10 секундам.
backup Помечает сервер как запасной сервер. На него будут передаваться запросы в случае, если не работают основные серверы.
down Помечает сервер как постоянно недоступный.

Подробнее об этом написано в официальной документации, в описании модуля ngx_http_upstream_module. К примеру, конфиг бэкендов для балансировки может быть таким.

server 10.32.18.6:8080 max_fails=2 fail_timeout=10s;
server 10.32.18.7:8080 max_fails=2 fail_timeout=10s;
server 10.32.18.8:8080 max_fails=2 fail_timeout=10s;

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

Установка Nginx на Ubuntu 20.04

Установить Nginx можно двумя способами. Первый способ заключается в установки пакета из официального репозитория Ubuntu. На момент написания статьи (1 августа 2021 года) актуальной версией Nginx присутствующей в репозитории Ubuntu была версия 1.18.0. Данная версия считается устаревшей. Актуальной же версией считается 1.20.1 (по состоянию на 1 августа 2021 года).

1. Официальные репозитории Ubuntu

Если вы хотите установить версию Nginx из репозиториев Ubuntu необходимо выполнить следующие действия. Для начала обновляем списки пакетов при помощи команды:

Для того, чтобы установить Nginx, достаточно выполнить команду:

После этого программу можно использовать. Проверка и настройка программы будет описана в разделах ниже.

2. Официальные репозитории Nginx

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

Установите необходимые пакеты:

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

Для подключения репозитория со стабильной версией nginx, выполните следующую команду:

Для подключения репозитория с основной версией nginx, выполните следующую команду:

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

Проверьте, верный ли ключ был загружен:

Вывод команды должен содержать полный отпечаток ключа 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62:

Переместите ключ в каталог доверенных ключей apt:

Чтобы установить nginx, выполните следующие команды:

Версия Nginx от разработчиков немного отличается от версии из официальных репозиториев. Все дополнительные конфигурационные файлы здесь находятся в папке /etc/nginx/conf.d. Если вы хотите использовать папки sites-available и sites-enabled, то необходимо их создать:

Затем добавьте следующую строчку в конец секции http файла /etc/nginx.conf для того чтобы из папки /etc/nginx/sites-enabled загружалась конфигурация сайтов:

Затем перезапустите Nginx:

3. Запуск Nginx

После установки пакета, проверяем что Nginx успешно запустился при помощи команды:

Если в статусе вместо active будет inactive (dead), то сервис необходимо запустить вручную при помощи команды:

Так же обратите внимание, что вы не можете запускать Apache и Nginx на одном порту. В таком случае вы получите ошибку nginx address already in use 80. Для корректной работы Nginx, необходимо будет отключить веб-сервер Apache (если он у вас используется) или изменить его порт с 80 (который используется по умолчанию) на другой свободный порт

4. Настройка брандмауэра

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

5. Проверка работы Nginx

После того, как Nginx будет запущен, он будет доступен по адресу сервера, на который он устанавливался. Вы можете проверить, всё ли работает, просто перейдя по адресу сервера, введя его в браузере. Для примера Nginx был установлен на localhost:

Если вы увидите приветственное сообщение как на скриншоте выше это означает что Nginx успешно установлен и запущен.

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

Рассмотрим практически установку Nginx на Linux, взяв за основу один из самых популярных дистрибутивов данной операционной системы – CentOS.

  1. Добавляем yum-репозиторий Nginx на ОС с помощью команды:
    sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
  2. Для установки используем команду sudo yum install nginx. Подтверждаем появившееся извещение.
  3. Для запуска сервера используем команду:
    sudo systemctl start nginx.service
  4. Проверить, успешна ли установка, можно, посетив общественный IP-адрес сервера. Узнать его можно через команду:
    ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'
  5. Чтобы Nginx автоматически запускался при загрузке ОС, вводим:
    sudo servicectl enable nginx.service

Основные ошибки nginx и их устранение

502 Bad Gateway

Ошибка означает, что NGINX не может получить ответ от одного из сервисов на сервере. Довольно часто эта ошибка появляется, когда NGINX работает в связке с Apache, Varnish, Memcached или иным сервисом, а также обрабатывает запросы PHP-FPM.
Как правило, проблема возникает из-за отключенного сервиса (в этом случае нужно проверить состояние напарника и при необходимости перезапустить его) либо, если они находятся на разных серверах, проверить пинг между ними, так как, возможно, отсутствует связь между ними.
Также, для PHP-FPM нужно проверить права доступа к сокету.
Для этого убедитесь, что в прописаны правильные права

listen = /tmp/php5-fpm.sock 
listen.group = www-data
listen.owner = www-data

504 Gateway Time-out

Ошибка означает, что nginx долгое время не может получить ответ от какого-то сервиса. Такое происходит, если Apache, с которым NGINX работает в связке, отдаёт ответ слишком медленно.
Проблему можно устранить с помощью увеличения времени таймаута.
При работе в связке NGINX+Apache в конфигурационный файл можно внести изменения:

server { 
... 
   send_timeout 800;
   proxy_send_timeout 800;
   proxy_connect_timeout 800;  
   proxy_read_timeout 800;  
... 
}

Тут мы выставили ожидание таймаута в 800 секунд.

Upstream timed out (110: Connection timed out) while reading response header from upstream

Причиной может быть сложная и потому долгая обработка php в работе PHP-FPM.
Здесь тоже можно увеличить время ожидания таймаута

location ~ \.php$ { 
   include fastcgi_params;
   fastcgi_index index.php; 
   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 
   fastcgi_pass unix:/tmp/php5-fpm.sock;  
   fastcgi_read_timeout 800;
}

800 секунд на ожидание ответа от бекенда.

Это лишь временные меры, так как при увеличении нагрузки на сайт ошибка снова станет появляться. Устраните узкие места, оптимизируйте работу скриптов php

413 Request Entity Too Large

Ошибка означает, что вы пытались загрузить слишком большой файл. В настройках nginx по умолчанию стоит ограничение в 1Mb.
Для устранения ошибки в nginx.conf нужно найти строку

client_max_body_size 1m;

и заменить значение на нужное. Например, мы увеличим размер загружаемых файлов до

client_max_body_size 100m;

Также, можно отключить проверку размера тела ответа полностью значением ноль:

client_max_body_size 0;

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

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

304 Not Modified не устанавливается

Если возникает проблема с правильным отображением ответного заголовка сервера , то проблема, скорее всего, в пунктах:

  • В секции конкретного сайта включен (Подробнее в документации). По умолчанию, ssi отключен, но некоторые хостеры и ISPManager любят его прописывать в дефолтную конфигурацию сайта включенным. Его нужно обязательно отключить, закомментировав или удалив эту строку;
  • if_modified_since установить в , то есть на уровне или конкретного прописать:

Правильность ответа можно проверить с помощью:

  • Консоли разработчика браузера (F12) в разделе (не забываем перезагружать страницу);
  • Или сторонних сервисов, например last-modified.com.

Настройка виртуального хоста Nginx

Вообще, у Nginx только один конфигурационный файл — это /etc/nginx/nginx.conf. Все остальные файлы из папки /etc/nginx/* подключаются в этот файл с помощью директивы include. Поэтому теоретически все виртуальные хосты или только часть из них могут быть размещены в этом файле. Однако так делать не рекомендуется.

Для этого уже существует папка /etc/nginx/sites-available/ и /etc/nginx/sites-enabled. Первая просто содержит файлы конфигурации, в каждом из которых находится отдельный виртуальный хост. Вторая папка содержит ссылки на файлы из /etc/nginx/sites-available и подключена к основному конфигурационному файлу. Даже если в вашей системе пока такая структура не используется, я рекомендую её создать, чтобы в конфигурации всегда был порядок.

1. Синтаксис виртуального хоста

Каждый виртуальный хост представляет из себя такой блок кода:

server { listen ip_адрес:порт; server_name доменные_имена; root /путь/к/файлам/сайта/; index index.php index.html; …. location / {} ….}

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

  • listen — указывает на IP-адрес и порт, на котором программа будет ожидать соединения от этого сайта. Чтобы выбрать любой IP-адрес, можно указать звёздочку, а порт указывать обязательно. Также в этой строке можно добавить параметр default_server, тогда этот виртуальный хост будет использоваться по умолчанию;
  • server_name — доменные имена, на которые будет отзываться этот хост. При отправке запроса на сервер, браузер указывает, к какому домену он обращается. Nginx анализирует этот параметр и выбирает необходимый виртуальный хост. Чтобы обрабатывать все домены, используйте символ подчеркивания _;
  • root — путь к файлам сайта, которые будут открываться при запросе к этому виртуальному хосту. У Nginx должен быть доступ на чтение ко всем папкам по этому пути;
  • index — файлы, которые будут открываться, если адрес файла не указан в URL;
  • location — это набор правил обработки путей в url. Каждый location может содержит путь URL а внутри него можно настроить открытие другого файла, аутентификацию, запрос к другому серверу и другие подобные вещи. Nginx анализирует все location в конфигурационном файле и выбирает самое подходящее. Из этого правила есть одно исключение. Если несколько location содержат регулярные выражения, то для обработки будет выбран первый подходящий.

2. Виртуальный хост по умолчанию

Теперь разберём создание виртуальных хостов nginx на примере. Давайте создадим виртуальный хост, который будет обрабатывать все необработанные запросы:

Все директивы, которые используются в блоке server, могут использоваться и в блоках location. Но нам не обязательно указывать root и index в каждом location. Если их опустить, то будут наследоваться те, которые были указаны в родительском блоке. Блоки server ведут себя аналогичным образом, поэтому, если мы не укажем другой путь к access.log, то будет использоваться путь, указанный в /etc/nginx/nginx.conf и так далее.

Теперь нам нужно активировать созданный виртуальный хост nginx. Для этого создайте символическую ссылку:

Затем убедитесь, что файлы из этого каталога подключены в основном конфигурационном файле:

Затем выполните эту команду, чтобы убедится, что вы не допустили ошибок:

Далее перечитайте конфигурацию nginx:

Теперь, если вы откроете IP-адрес сервера, то откроется созданный нами виртуальный хост.

2. Виртуальный хост с доменом

Аналогичным образом можно создать виртуальный хост для домена. Например example.ru:

Если вы работаете на локальной машине и доступа к DNS выбранного домена у вас нет, то надо добавить его IP в файл /etc/hosts:

Повторите процедуру активации домена, и затем в браузере при запросе к домену example.ru откроется стартовая страница Nginx. Если по каким-либо причинам виртуальный хост Nginx не работает, вы можете посмотреть полный скомпилированный файл nginx.conf:

Также можно проверить, есть ли в нём конфигурация нужного хоста, например, ищем упоминания example.ru:

3. Отключение виртуального хоста

Благодаря структуре директорий, которую мы использовали, будет довольно просто отключить ненужный хост. Все наши виртуальные хосты Nginx находятся в папке /etc/nginx/sites-available, а в активной папке только ссылки на эти файлы. Поэтому для удаления достаточно удалить на него ссылку из папки /etc/nginx/sites-enabled/:

А затем, при необходимости, мы можем активировать его обратно, просто создав ссылку.

Метод балансировки

Рассмотрим способы балансировки, которые можно использовать в NGINX:

  1. Round Robin.
  2. Hash.
  3. IP Hash.
  4. Least Connections.
  5. Random.
  6. Least Time (только в платной версии NGINX).

Настройка метода балансировки выполняется в директиве upstream. Синтаксис:

upstream <название апстрима> {
    <метод балансировки>
    …
}

Round Robin

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

Hash

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

upstream dmosk_backend {
    hash $scheme$request_uri;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

* это самый распространенный пример настройки hash — с использованием переменных $scheme (http или https) и $request_uri. При данной настройке каждый конкретный URL будет ассоциирован с конкретным сервером.

IP Hash

Ассоциация выполняется исходя из IP-адреса клиента и только для HTTP-запросов. Таким образом, для каждого посетителя устанавливается связь с одним и тем же сервером. Это, так называемый, Sticky Session метод.

Для адресов IPv4 учитываются только первые 3 октета — это позволяет поддерживать одинаковые соединения с клиентами, чьи адреса меняются (получение динамических адресов от DHCP провайдера). Для адресов IPv6 учитывается адрес целиком.

Пример настройки:

upstream dmosk_backend {
    ip_hash;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

Least Connections

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

Настройка выполняется с помощью опции least_conn:

upstream dmosk_backend {
    least_conn;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

Random

Запросы передаются случайным образом (но с учетом весов). Дополнительно можно указать опцию two — если она задана, то NGINX сначала выберет 2 сервера случайным образом, затем на основе дополнительных параметров отдаст предпочтение одному из них. Это следующие параметры:

  • least_conn — исходя из числа активных подключений.
  • least_time=header (только в платной версии) — на основе времени ответа (расчет по заголовку).
  • least_time=last_byte (только в платной версии) — на основе времени ответа (расчет по полной отдаче страницы).

Пример настройки:

upstream dmosk_backend {
    random two least_conn;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

Least Time

Данная опция будет работать только в NGINX Plus. Балансировка выполняется исходя из времени ответа сервера. Предпочтение отдается тому, кто отвечает быстрее.

Опция для указания данного метода — least_time. Также необходимо указать, что мы считаем ответом — получение заголовка (header) или когда страница возвращается целиком (last_byte).

Пример 1:

upstream dmosk_backend {
    least_time header;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

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

Пример 2:

upstream dmosk_backend {
    least_time last_byte;
    server 192.168.10.10;
    server 192.168.10.11;
    server 192.168.10.12;
}

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

Режим Emperor

uWSGI может работать в режиме «emperor». В этом режиме он следит за каталогом конфигурационных файлов uWSGI и порождает экземпляры («vassals») для каждого найденного файла.

Всякий раз, когда в конфигурационный файл вносятся изменения, emperor автоматически перезапускает vassal.

# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
# run the emperor
uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Вам может потребоваться запустить uWSGI с помощью sudo:

sudo uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Эти опции означают:

  • : каталог где искать vassals (конфигурационные файлы)
  • : идентификатор пользователя user id процесса после его запуска
  • : идентификатор группы group id процесса после его запуска

Nginx

Какие проблемы мы хотим решить с помощью Nginx:

  1. Единая точка входа. Нам не нужно помнить и держать в многочисленных конфигурационных файлах разные IP-адреса и порты для каждого экземпляра сервиса — достаточно знать только IP-адрес нашего Nginx-сервера. К тому же, вся информация о местонахождении сервисов (IP и порт) находится в одном месте, что облегчает поддержание актуального состояния всей нашей микросервисной экосистемы.
  2. Балансировка нагрузки. Указывая несколько экземпляров каждого нашего сервиса, мы можем распределить нагрузку, например, по алгоритму round-robin.
  3. Failover. Мы можем перестать использовать экземпляры сервисов, которые в данный момент работают некорректно, — timeout или статус-код ответа нас не устраивают.

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

http {
    include mime.types;
    default_type application/octet-stream;

    upstream service1 {
        keepalive 512;
        // для каждого экземпляра сервиса мы указываем адрес,
        // разрешенное количество неудачных запросов и время,
        // в течение которого этот экземпляр сервиса не будет принимать запросы
        //после достижения максимального количества неудачных запросов
        server 10.0.0.1:5000 max_fails=5 fail_timeout=1m;
        server 10.0.0.2:5000 max_fails=5 fail_timeout=1m;
    }

    server {
        listen 80;
        //перечень условий, по которым запрос будет передан к следующему экземпляру сервиса в рамках upstream
        proxy_next_upstream error timeout invalid_header http_500 http_503;
        server_name localhost;
        
        location ~* ^/service1/(.*) {
                set $path /$1$is_args$args;
                proxy_pass http://service1$path;
                proxy_pass_request_headers	  on;
        }
    }
}

Пока все довольно компактно, но что будет, когда мы начнем масштабировать систему, вводя все новые и новые сервисы? Давайте посмотрим на наш новый конфиг:

http {
    include mime.types;
    default_type application/octet-stream;

    upstream service1 {
        keepalive 512;
        server 10.0.0.1:5000 max_fails=5 fail_timeout=1m;
        server 10.0.0.2:5000 max_fails=5 fail_timeout=1m;
    }
    
    upstream service2 {
        keepalive 512;
        server 10.0.0.3:5000 max_fails=5 fail_timeout=1m;
        server 10.0.0.4:5000 max_fails=5 fail_timeout=1m;
    }
    
    upstream service3 {
        keepalive 512;
        server 10.0.0.5:5000 max_fails=5 fail_timeout=1m;
        server 10.0.0.6:5000 max_fails=5 fail_timeout=1m;
    }
    ...
    ...
    ...
    upstream service100 {
        keepalive 512;
        server 10.0.0.199:5000 max_fails=5 fail_timeout=1m;
        server 10.0.0.200:5000 max_fails=5 fail_timeout=1m;
    }
    
    server {
        listen 80;
        proxy_next_upstream error timeout invalid_header http_500 http_503;
        server_name localhost;
        
        location ~* ^/service1/(.*) {
                set $path /$1$is_args$args;
                proxy_pass http://service1$path;
                proxy_pass_request_headers	  on;
        }
        
        location ~* ^/service2/(.*) {
                set $path /$1$is_args$args;
                proxy_pass http://service2$path;
                proxy_pass_request_headers	  on;
        }
        
        location ~* ^/service3/(.*) {
                set $path /$1$is_args$args;
                proxy_pass http://service3$path;
                proxy_pass_request_headers	  on;
        }
        ...
        ...
        ...
        location ~* ^/service100/(.*) {
                set $path /$1$is_args$args;
                proxy_pass http://service100$path;
                proxy_pass_request_headers	  on;
        }
    }
}

Когда у нас десятки сервисов, то вместо простого и лаконичного конфигурационного файла мы получаем условно бесконечный набор похожих между собой конструкций. Теперь этот конфиг будет крайне трудно как читать, так и модифицировать.

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

Единственный логичный выход из ситуации — автоматизация процесса внесения изменений в конфиг Nginx. Но для этого нужно где-то хранить данные обо всех наших сервисах.

nginx и uWSGI и test.py

Давайте еще раз запустим приложение «hello world» test.py.

uwsgi --socket :8001 --wsgi-file test.py

Это почти так же, как и раньше, за исключением того, что один из вариантов отличается:

socket :8001: использует протокол uwsgi, порт 8001

В то же время nginx настроен на связь с uWSGI через этот порт и с внешним миром через порт 8000. Посетите:

Теперь наш стек будет следующим:

the web client <-> the web server <-> the socket <-> uWSGI <-> Python

Между тем, вы можете попытаться взглянуть на вывод uswgi по адресу http://example.com:8001 — но вполне вероятно, что он не будет работать, потому что ваш браузер работает по протоколу http, а не через протокол uWSGI, хотя вы должны увидеть вывод uWSGI в терминале.

Настройка отладки в NGINX

В целях отладки настройки NGINX вы можете писать данные в логи, но я советую воспользоваться директивой add_header. С её помощью вы можете выводить различные данные в http headers.
Пример, как можно определить, в каком location обрабатывается правило:

  location ~ \.ph(p\d*|tml)$ {
    try_files /does_not_exists @fallback;
    add_header X-debug-message "This is php" always;
  }

  location ~* ^.+\.(jpe?g|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar|swf)$ {
    expires 365d; log_not_found off; access_log off;
    try_files $uri $uri/ @fallback;
    add_header X-debug-message "This is static file" always;
  }

Теперь, если проверить, какие заголовки отдаёт статичный файл, например , то вы увидите среди них и наш

Отладочная информация NGINX в заголовках HTTP headers

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

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: