Debian.pro/

Про Debian


Большой мануал: часть 16. Подготавливаем nginx.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.

Предыдущая часть цикла — Ставим пакеты для lamp+nginx.

Следующая часть цикла — Настраиваем SSL в nginx и получаем A-rate.

В этой статье мы поговорим о некоторых настройках nginx, с которыми нам проще будет дальше жить.
Вообще nginx очень гибок и настроить там можно хоть слона (файловый сервер с репликой — да легко!). Но мы будем использовать его всего-лишь в качестве реверс-прокси (то есть пользователи будут приходить в nginx, на часть запросов (статику) nginx будет отвечать сам с диска, а другую часть запросов (к php) будет проксировать в apache). Nginx работает быстрее в тех задачах, которые он умеет выполнять, но не может сам обрабатывать php/python/perlwhatever-скрипты (окей, perl и lua может, но их придется знатно переписать), поэтому к nginx-у нужен бэкэнд, который будет заниматься обработкой скриптов, которые генерят страницу. Бэкэндом может быть другой http-сервер, uwsgi/fastcgi-приложение (точнее, сокет). В нашем случае бэкэндом будет apache, который обрабатывает php.
Первым делом давайте приведем в божеский вид лог-файл nginx. Из коробки этот лог скорее мешает понять, что в реальности происходит.
Для этого создаём файл /etc/nginx/conf.d/01-access-log-format.conf c таким содержимым (ссылка на plain-text без комментариев):

# создаём внутри nginx-a формат лога с названием "lamp". Логи в таком формате будут включать домен, за которым пришел пользователь, время ответа пользователю, время ответа апача и прочие полезности (это помимо того, что есть в дефолтном формате). # Если вам необходимо понимать, по https или http пришел пользователь - добавьте переменнуж $scheme в формат лога.
log_format lamp '[$time_local] $http_host $remote_addr "$request" $status "$http_referer" "$http_user_agent" $request_time $upstream_cache_status $bytes_sent ($upstream_addr:$upstream_status:$upstream_response_time)';

# включаем access_log в формате lamp. Лог будет писать в указанный файл (в нашем примере - /var/log/nginx/access.log)
access_log /var/log/nginx/access.log lamp;

После этого нам нужно удалить строчку про access_log из /etc/nginx/nginx.conf. Выглядит она из коробки примерно так:

access_log /var/log/nginx/access.log;

Удалить её можно текстовым редактором или примерно такой командой:

user@host:~$ sed -i '/access_log .*/d' /etc/nginx/nginx.conf

Перезапускаем nginx (/etc/init.d/nginx restart) и сравниваем старые логи с новыми (запросы разные, но не суть).
Строчка из старого лога:

198.51.100.1 - - [24/May/2016:17:38:51 +0300] "GET / HTTP/1.1" 403 168 "-" "curl/7.17.1 (mips-unknown-linux-gnu) libcurl/7.17.1 OpenSSL/0.9.8i zlib/1.2.3"

Строчка из нового лога:

[24/May/2016:19:19:53 +0300] www.example.com 198.51.100.1 "GET / HTTP/1.0" 200 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/49.0.2623.108 Chrome/49.0.2623.108 Safari/537.36" 2.091 - 2919 (127.0.0.1:81:200:2.090)

Мне с таким логом работать сильно удобнее, особенно когда нужно найти дятла или «медленные» страницы.
На каждом сервере я создаю файл /etc/nginx/conf.d/02-hashes.conf c таким содержимым:

server_names_hash_bucket_size 256;

Оно нужно в том случае, если вы собираетесь держать несколько server {} (или в принципе обрабатывать большое количество доменов) — мы увеличиваем размер буфера под переменные server_name.
Сейчас мы создадим полезный файл на будущее. Суть его будет сводиться к тому, чтобы letsencrypt с модулем webroot корректно работал на нашем сервере. Файлик мы будем инклудить в те вхосты, для которых будем заказывать сертификаты. Создадим каталог:

user@host:~$ mkdir /etc/nginx/includes

Создадим файл /etc/nginx/includes/letsencrypt с таким содержимым (ссылка на plain-text):

# "Сообщаем" nginx-у, что все запросы к uri вида /.well-known/acme-challenge/* должны обрабатываться как статические файлы относительно каталога /var/www/letsencrypt (напр. /var/www/letsencrypt/.well-known/acme-challenge/file)
# Тем самым, когда мы будем запускать letsencrypt с опциями --webroot -w /var/www/letsencrypt, клиент LE будет создавать файлы для проверки в указанном каталоги, а nginx "расшарит" их для внешнего сервиса проверки этих файлов. Ну и мы получим свой сертификат.
location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt;
}

Если вы доросли до выделенной виртуалки для заказа сертификатов, то будет логичным проксировать запросы от letsencrypt-проверки в эту самую виртуалку. Тогда файл /etc/nginx/includes/letsencrypt будет выглядеть так (ссылка на plain-text):

# Запросы к url-ам вида location /.well-known/acme-challenge/* проксируем на http://external-certificator.example.com
# только учтите, что на external-certificator.example.com в такой схеме нельзя использовать letsencrypt --standalone (т.к. в таком режиме клиент LE создаёт временный самоподписанный сертификат, а сервис letsencrypt проверяет не только файл, но и этот временный сертификат).
# на сертификаторе тоже нужно будет настроить веб-сервер так, чтобы letsencrypt --webroot работал, тогда проверка корректно пройдет с proxy_pass

location /.well-known/acme-challenge/ {
    proxy_pass http://external-certificator.example.com;
}

Теперь настроим default-vhost. В этот vhost будут попадать все запросы, которые не описаны в конфигурации отдельно (проще говоря (но не совсем точно), сюда будут попадать запросы ко всем доменам, которые мы явным образом не описали отдельно). На всякий случай напомню, что любой человек в мире может взять свой домен и прописать ему в А-запись ваш IP. Если не создавать default-vhost, то такой домен может склеиться с вашим, поисковики могут посчитать его основным ну и так далее. Это я уже не говорю о том, что если писать код хреново — то такими «левыми» запросами можно прогружать или ронять сервер. Ну и всякие mass-сканеры, которые ищут уязвимости, тоже пойдут нафиг, на самом деле.
Удалим пример вхоста из пакета nginx, чтобы не мешался:

user@host:~$ rm /etc/nginx/sites-enabled/default; rm /etc/nginx/sites-available/default

Создадим свой дефолтный вхост. Для этого создаём файл /etc/nginx/sites-available/00-default (ссылка на plain-text без комментариев)

# открываем секцию server {}
# в терминологии nginx-a server - это, по сути, виртуальный хост, а если ещё сильнее упростить - то конфигурация одного сайта (но не одного домена!)
server {
# данный server{} будет обрабатывать все запросы на 80м порту сервера на всех ip, кроме описанных (запросов) в конфигурации явным образом. Важна опция default.
# учтите, что если вы хоть где-нибудь в конфигурации напишете что-то вроде "listen ip:80;" - то _все_ запросы для указанной связки ip+port перестанут обрабатываться конфигами, в которых написано listen 80 (независимо от server_name и прочего).
# проще говоря, если у вас на сервере один ip, два конфига, в одном написано "listen 80;", а во втором "listen ip:80;" - то первый конфиг (с listen 80) работать не будет вообще.
    listen 80 default;
# подключаем созданный ранее файл для работы letsencrypt для тех сайтов/доменов/вхостов, которые мы ещё не настроили на сервере (это позволит получать сертификаты до запуска сайта).
# include для файлов без слэша вначале работает относительно каталога /etc/nginx
    include includes/letsencrypt;
# На все остальные запросы отвечаем ошибкой 404 ("Не найдено").
    location / { return 404; }
}

Теперь сделаем симлинк из sites-available/00-default в sites-enabled. Всегда редактируйте файлы в sites-available. Если редактировать файлы в sites-enabled, то редактор может напложить всяких временных файлов, в которых будет копия конфига (например vim генерит .swp-файлы), что приведет к тому, что конфигурация будет работать не тем образом, которым мы ожидаем.
Для conf.d/ каталога это полечили тем, что оттуда (по крайней мере в дефолтном конфиге nginx-а в дебианах и убунтах) инклудятся только файлы *.conf. Можно сделать так и для sites-enabled, но нам лень.

root@server:~# ln -s /etc/nginx/sites-available/00-default /etc/nginx/sites-enabled/00-default

Теперь создадим полезный на будущее файл /etc/nginx/listen. Этот файл мы будем инклудить в каждый server{}. Очень полезно, если когда-нибудь придется внести изменения в каждый server{} (например, для устранения уязвимости средствами конфига).
Файл в минимальном виде может выглядеть так:

listen 80;

Можно и так, чтобы letsencrypt-проверка работала для любого сайта на нашем сервера:

listen 80;
include includes/letsencrypt;

На этом мы пока остановимся. Мы подготовили nginx к тому, что бы нам было удобно его админить. Сейчас мы не будем заниматься тюнингом nginx, это очень и очень обширная тема (по-хорошему ещё статей на 40 подобного размера), а дефолтная конфигурация не самая плохая.

01.06.2016 byinkvizitor68sl|big-manual

Комментарии (2):

  1. Роман :

    А как быть если нет вообще директорий
    sites-enabled
    sites-available
    Прописывать вручную и в nginx.conf строчку include /etc/nginx/sites-enabled/*; добавлять?

  2. > А как быть если нет вообще директорий
    Поставить пакет не из левого репозитория =)

    > Прописывать вручную и в nginx.conf строчку include /etc/nginx/sites-enabled/*; добавлять?
    Тоже верно.

Написать комментарий