Базовые фичи Nginx - SUPERCOMPTEAM/NeuroModule GitHub Wiki

Это конспект лекций отсюда: https://www.youtube.com/watch?v=dHsv8EnhSgQ&list=PLhgRAQ8BwWFa7ulOkX0qi5UfVizGD_-Rc

Nginx - в первую очередь обратный прокси-сервер (не совсем web-сервер)

vs Apache:

Apache - по умолчанию prefork: каждый процесс обрабатывает 1 запрос за одну единицу времени Nginx - асинхронная архитектура. Может обрабатывать несколько запросов однвременно. Все запросы к динамическому контенту передается через другие процессы (нельзя встраивать серверные ЯП в свои процессы)

Nginx меньше веcит чем Apache. Nginx работает со статическими ресурсами. Хорошо настроенный сервер nginx будет более эффективным и менее требовательным к ресурсам чем Apache.

Установка

sudo apt-get install nginx

/etc/nginx/ - файлы конфигурации nginx

service nginx status - просмотр текущего состояния nginx

Сборка из исходного кода

wiki/install/mainline

sudo apt-get install libpcre3 libpcre3-dev libssl-dev zlib1g-dev - либы

./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-debug --with-pcre --with-http_ssl_module

https://www.nginx.com/resources/wiki/start/topics/tutorials/installoptions/ - флаги компиляции

Термины

Контекст (context) - разделы в файлах конфигурации, в котором используются директивы (http, server итд). самый верхний - файл конфигурации. в нем настраиваются опции мастер-процесса

Директивы (directives) - конкретные опции конфигурации. состоят из имени опции и значения опции (listen 80 - директива)

файл конфигурации /etc/nginx/nginx.conf

блок server - vhost, внутри контекста http, связан с одним хостом - доменом (поддоменом, ip-адресом). Порт, который будет прослушивать этот хост - по умолчанию порт 80. отсюда listen 80; server_name - домен, поддомен или ip, для которого существует этот хост. root /path - корневая папка с сайтом, статику которого раздаем на сервере.

service nginx reload - перезагрузить конфигурацию nginx. Команда не приведет к остановки nginx. restart - перезапускает.

curl -I позволяет посмотреть mime.type (text/plain - тип контента)

Контекст types. Например используя text/html html можно указать, что ко всем файлам с расширением html применим тип контента text/html. По умолчанию nginx уже подставляет тип контента к определенным расширениям файлов: include mime.types. этот файл лежит в /etc/nginx и в нем есть контекст types.

все это в контексте http.

самый тупой nginx.conf:

events {

}

http {
    include mime.types;
    server {
        listen 80;
        root /sites;
        
    }
}

блоки location - самые часто используемые

location - ссылки после домена. внутри server. В нем например можно написать return 200 'ok'. 200 - код возврата. здесь используется совпадение префикса - странички /site и /sitefwe и /site/1 отрисуют одно и то же. чтобы это выключить, напишем равно после слова location.

Регулярные выражения: ~ после location Чтобы убрать чувствительность к регистру: *~ после location location ^~ - более высокий приоритет чем регулярные выражению. но у location = самый высокий приоритет

try_files $uri =404; - ищем файл в папке root:

events {

}

http {
    include mime.types;
    server {
        listen 80;
        root /sites;
        location /obama {
            root /sites;
            try_files $uri =404;
        }
    }
}

Логирование

директория /var/log/nginx. там есть access.log и error.log Контекст наследуется от родительского контекста. Поэтому в контекст location можем добавить чтобы например ошибки контекста логировались в другой файл: error-log /path. Флаг debug позволит получать больше информации об ошибке.

Существует несколько уровней логирования. Подробнее: http://wiki.nginx.org/CoreModule#error_log

Отключить логирование в location:

access_log off;
error_log off;

обычно логирование access_log не нужно вести к статическим файлам типа css

Наследование и типы директив

типы директив:

  1. стандартный (standart)
  2. массивы (array)
  3. действия (action)
  4. try_files

Стандартная директива например gzip on. В контексте и в его подконекстах gzip будет включен.

Директива массив (например access_log) - работает так же, как стандартная, но можно переопределять в одном контексте несколько раз с разными значениями.

При наследовании стандартных директив и директив массивов в дочернем контексте они полностью перезаписывают логику директив в родительском контексте (одной строкой).

Директива действие (например rewrite). Активируется при вызове. Также примером может служить директива return. В директивах действиях наследование не работает, т.к. поток прирывается действием.

переменные в nginx: http://nginx.org/ru/docs/varindex.html

try_files. Не наследуется. Пример:

try_files x y z; - сперва пробует x, потом y, потом z

Настройка воркеров

Директива worker_processes отвечает за то, сколько workers. Надо указывать число, равное количеству ядер на сервере. Если установить worker_processes auto, то кол-во процессов установится равным кол-ву ядер. По умолчанию стоит 1 (одно ядро)

nproc - кол-во ядер lscpu - информация по процессору

В контексте events есть директива worker_connections. Это то, сколько подключений обрабатывает 1 worker процесс. стоит указать число, которое выдаст команда ulimit -n. В контексте events директива multi_accept on позволит одновременно принимать все новые подключения. Иначе он будет принимать только одно подключение за единицу времени.

В контесксте http:

charset utf-8 - кодировка по умолчанию utf-8

open_file_cache max=1000 inactive=20s'; - настройки кеширования файлов open_file_cache_valid 30s; open_file_cache_errors on;

Настройки буферов client_body_buffer_size 16k; - размер буфера POST-запроса, получаемого от клиента client_header_buffer_size 1k; - размер буфера заголов client_max_body_size 8m; - максимльный размер тела запроса клиента client_header_buffers 2 1k; - размер и максимально большой размер заголовов

Сколько секунд ждать после получения client_body и client_header: client_body_timeout 12; client_header_timeout 12;

keepalive_timeout 300; - время сколько держим подключения открытыми (в мс)

send_timeout 10; - макс. кол-во времени (с), через которое соединение будет закрыто

Контекст types указывается после include mimetypes для указания отдельных типов контента.

Директива add_header:

  • Директива-массив
  • Добавляет кастомный заголовок в ответ

Динамические модули nginx v.1.9.11

./configure --help - просмотреть все модули. Если в конце флага =dynamic, то модуль поддерживает динамику

Expires (заголовки)

Используются для оптимизации скорости загрузки.

expires 1M; - (1M - 1 месяц; d - days итд.) уменьшение времени загрузки странички в браузере. Говорит браузеру кешировать определенные ресурсы определенное кол-во времени. При след загрузке страницы браузеру не нужно запрашивать кешированный файл - берет его из кеша.

кешировать со стороны клиента можно: статические css или js файлы.

можно указать expires max; - но это плохо

директивы add_header Pragma public; и add_header Cashe-control public; - сообщают браузеру что файлы можно кешировать любым способом. add_header Vary Accept-Encoding; -

Сжатие данных Gzip

Accept-Encoding: gzip,deflate; - флаг для curl -I для скачивания сжатого файла

gzip on; - директива для подключения gzip gzip_min_length 100; - минимальная длина файла, с которой начинать сжатие. в байтах. gzip_comp_level 3; - чем больше число, тем больше степень сжати; оптимально 2-4. gzip_types text/plaun; - выбор типа файлов к которым применять сжатие. gzip_disable "msi6"; - отключение gzip для определенных браузеров

FastCgi Cache

бенчмарк apache: ab -n 100 -c 10 http://ip - для оценки скорости сервера

директивы для активации кеша fastCgi:

В контексе http:

  • указывем где будут храниться файлы кеша (/tmp очищается при перезагрузке сервера. 1:2 - это уровень подпапок. key_zone - то как мы будем обращаться к микро кешу): fastcgi_cache_path /tmp/nginx_cache levels=1:2 keys_zone=microcache:10m max_size=500m; - max_size равняется кол-ву оперативной памяти по умолчанию

  • указываем в каком формате будем хранить кеш fastcgi_cache_key "$scheme$request_method$host$request_uri" (http/https, get/post)

В блоке location:

fastcgi_cache microcache; - имя (параметр) keyzone, который указали при создании fastcgi_cache_valid 200 60m - код ответа и максимальное время хранения кеша

Ограничение кол-ва запросов на сервер

2 способа:

  1. Ограничить число параллельных соединений

В контексте http:

limit_conn_zone $server_name zone=per_vhost:5m; - ограничение числа параллельных соединений в блоке сервера per_vhost=размер памяти зоны limit_conn_zone $binary_remote_addr zone=per_ip:5m; - ограничиваем относительно ip-адреса.

это мы просто выделили память. Для реализации спускаемся в location:

location ... {
    limit_conn per_ip 1; # только 1 соединение за раз
}

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

  1. Ограничить число одновременных подключений

В контексте http:

limit_req_zone $binary_remote_addr zone=one_per_sec:5m rate=1r/s; - 1 запрос в секунду

location ... {
    limit_req zone=one_per_sec burst=5; # размер буфера
}

Стриминг видео

Модуль mp4 - не устанаавливается по умолчанию. Нужно указать --with_http_mp4_module. Можно контролировать скорость передачи ответа клиенту и размер буффера.

location ~ \.mp4$ {
    root /root/;
    mp4;    # определение модуля
    mp4_buffer_size 4M;
    mp4_max_buffer_size; # размер буфера не больше этого (иначе 500)
}

Http2

  • Бинарный протокол
  • Сжатие заголовков
  • Постоянные соединение
  • Мультиплексные потоки
  • Server PUSH

В HTTP1 несколько скриптов в 1 файл. Для установки соединения между клиентом и сервером требуется каждый раз отправлять заголовки в обе стороны.Также существует ограничение на максимальное кол-во соединений между клиентом и сервером. В http1 за 1 соединение передаем только 1 файл. В http2 - нет. Если поддерживаются серверные PUSH, сервер выдаст сразу всю необходимую информацию.

--with-http_v2_module --with-http_ssl_module (http 2 только с ssl)

http {
    # HTTPS server
    server {
        listen 443 ssl http2;   # просто добавляем сюда http2 чтобы работать с ним
        server_name localhost;

        ssl_certificate /path/to/cert.pem;  # сертификат
        ssl_certificate_key /path/to/cert.key;  # ключ

        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 5m;

        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers off;  # Стандартная директива шифрования

        location / {
            root html;
            index index.html index.htm;
        }
    }
}

SSL

генерация ключей

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /path/to/nginx.key -out /path/to/nginx.crt

файл выше отражает использование ssl в nginx. ток http2 можно убрать

Auth

sudo apt-get install apache2-utils
sudo htpasswd -c /etc/nginx/.htpassw name # Пароль
location ... {
    auth_basic "Restricted Content"; # ограниченный контент
    auth_basic_user_file /path/to/.htpassw;
}

Повышение безопасности сервера

  1. Удалить ненужный функционал. Для этого не будем компилировать неиспользуемые стандартные модули:
./configure --help | grep without   # Список стандартных модулей, которые можем исключить
./cotfigure --without=http_autoindex_module # Компилируем без авто-index.html модуля
  1. Отключение серверных токенов.

С помощью этого можем удалить всю информацию о том, какая версия nginx используется на сервере.

В контексте http:

server_tokens off;
  1. Задание размера буфферов. Против атаки "переполнение буффера"

В контексте http:

client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
  1. Блокировка User-Agent-ов

В контексте http:

if ($http_user_agent ~* badbot) {   # или $http_referer
    return 403;
}
  1. Настройка X-Frame-Options
add_header X-Frame-Options SAMEORIGIN;  # только с одного домена

SSL сертификаты Let's Encrypt

Let's Encrypt - бесплатные автоматически созданные SSL-сертификаты. Cert bot. Выдает сертификаты только на домены.

генерация сертификатов:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

инструменты certbot:

certbot --nginx # сам добавит https в nginx.conf 
certbot certonly -d domain.com  # если хотите пропустить установку
certbot renew --dry-run # обновить вручную
crontab -e  # открыть файл cron
# in cron
@daily certbot renew
crontab -l  # просмотр cron файла
events {}

http {
    server {
        
        listen 80;
        server_name domain.com;

        location / {
            return 200 "Hello world";
        }
    }
}

Обратный прокси и балансировщик

прямое назначение nginx не web-сервер, а обратный прокси-сервер и балансировщик.

nginx -c /path/to/nginx.conf    # Запустить сервер nginx из конкретной конфиги

Прокси

Обратный прокси-сервер выступает посредником между клиентом и вышестоящим (upstream) сервером. чаще всего это backend-сервисы.

events {}

http {

    server {
        listen 8000;
        location /service {
            proxy_pass 'http://localhost:8001/';  # тут обязателен слеш в конце
        }
    }
    
}

Если не укажем путь до прокси, nginx будет использовать оригинальный путь, указанный в location. Поэтому в конце лучше добавить /.

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

events {}

http {

    server {
        listen 8000;
        location /service {
            add_header Header: header;  # Кастомный заголовок клиенту
            proxy_set_header Header: header;    # Кастомный заголовок проксируемому серверу
            proxy_pass 'http://localhost:8001/';  # тут обязателен слеш в конце
        }
    }
    
}

Балансировщик

Балансировщик нагрузки должен распределять запросы по нескольким серверам, снижая нагрузку на конкретные серверы. Также он обеспечивает избыточность: если 1 из серверов отвалится, балансировщик переправит запросы на остальные доступные серверы. Распределение = перенаправление = проксирование.

upstream - контекст, в котором сгруппированы несколько серверов. Чаще всего они обрабатывают одни и те же запросы и выдают одинаковый результат.

events {}

http {

    upstream servers {
        ip_hash;    # Поведение балансировщика, м.б. ip_hash, least_conn и т.д.
        server localhost:8001;
        server localhost:8002;
        server localhost:8003;
    }

    server {
        listen 8000;

        location / {
            proxy_pass 'http://servers';
        }
    } 
}
  1. Round-robin - поведение при распределении запросов, при использовании которой nginx по-очереди отправляет запросы каждому серверу (иногда порядок нарушается). Если убить один из серверов, round-robin перестанет на него посылать запросы. При запуске, сервер снова включается в round-robin.

  2. ip hash или Sticky Sessions - запросы привязываются к ip-адресам пользователей и по возможности для одного пользователя проксируются на один сервер. В случае падения сервера запросы от этого пользователя будут проксироваться на другой. При восстановлении они снова начнут передаваться на восстановленный сервер.

  3. least_conn - nginx не отправляет запросы на серверы, у которых активное соединение.