Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.
Предыдущая часть цикла — Создаём конфиг для нашего сайта в apache2.
Следующая часть цикла — Учимся делать редиректы в nginx.
Уххххрррр. Часть 20. Сегодня этот сайт наконец-то заработает %).
Мы тут где-то когда-то ставили nginx, а я забыл рассказать, для чего. Попробуем исправить это упущение. TLDR — чтобы связка lamp жрала меньше памяти.
Апач устроен так, что на каждый запрос к нему, он занимает один процесс на некоторое время (или тред, не суть важно). Например, к вам пришел клиент с мобильника и 30 секунд качает страницу — один из процессов занят этим клиентом. Что ещё хуже, потом этот же чувак в верстке найдет 4 картинки и начнет качать их, займёт ещё 4 процесса. В апаче 2.4 «картинки с диска» стали отдаваться намного легче, но nginx в этом плане всё ещё на голову быстрее и менее затратен по ресурсам. Количество процессов апача ограничено, каждый запущенный весьма прожорлив по памяти (а когда клиентов нет, апач тушит часть процессов/тредов, в зависимости от настроек).
И тут впрыгивает дядя nginx. У него схема работы немного другая. Называется state machine. Не помню наизусть, но попробую рассказать на пальцах. В единый момент времени воркер nginx-а либо принимает от кого-то (в нашем случае — апача) данные, либо отправляет их кому-то. То бишь всё это выглядит так. Клиент пришел к nginx-у, сказал ему «дай мне ххх», nginx ответил ему «ща» и спросил ххх у апача. Пока апач ворочается и пытается сгенерить страницу, nginx бежит и отдаёт другому клиенту пару картинок с диска. Возвращается к апачу, спрашивает между делом «есть чо?», идет ещё дальше отдать пару картинок. И даже когда nginx получит ответ от апача, медленный клиент nginx-у не помешает — его процесс будет занят ровно в тот момент, когда медленному клиенту будут отправляться пакетики (а это достаточно короткий промежуток времени). Пока клиент придет и скажет «давай дальше» — можно ещё пару картинок запулить другим клиентам.
Всё это приводит к тому, что с клиентами общается быстро работающий nginx, который тратит мало памяти и CPU. А апач занимается только тем, что из лапши php-кода рисует страницы. При этом, с точки зрения апача, единственный его клиент — nginx на localhost-е. В итоге прожорливый по памяти апач в активном состоянии проводит ровно то время, которое необходимо для генерации страницы.
Ну и в целом, торчать голым задомапачем наружу в наше время не очень спокойно — с безопасностью, возможностями фильтрации и прочим у nginx-а сильно лучше. Но генерить страницы из php-исходников nginx не умеет ни в каком виде — поэтому за него и нужно ставить какой-то ещё софт (будь-то апач, php-fpm или ещё что-то).
Ещё важно понимать, что apache и nginx на самом деле ни в какой связке не настраиваются. Они настраиваются каждый сам по себе и работают отдельно (но апач мы настроили так, чтобы он слушал только 127.0.0.1, ибонех). Просто в части конфигурации nginx будет написано «вот на такие запросы сходи туда по http, получи ответ и отдай его клиенту». Важно понимать, что по такой же схеме там может быть не апач, а любой другой софт, отвечающий по http(s) (ну или по другим протоколам, но тогда настраивать уже по-другому нужно будет).
Ладно. Давайте уже переходить к конфигу, а то я как-то однажды целый час рассказывал ответ на вопрос «зачем нужен nginx».
Допустим, у нас сайт example.com. Он будет доступен и по https, и по http, но с домена www.example.com будет редирект (сам редирект сделаем в следующей статье). Так же для наглядности допустим, что у нас есть домен-алиас dev.example.com, по которому этот сайт тоже должен отвечать (например, мы хотим абсолютно одинаковый конфиг положить на prod и dev сервер положить).
Создаём файл /etc/nginx/sites-available/example.com.conf:
server {
# Подцепляем файл /etc/nginx/listen, мы его подготовили в части 16
include listen;
# подцепляем файл /etc/nginx/listen_ssl, если делаем https (перечитайте часть 17)
include listen_ssl;
# подцепляем файл includes/letsencrypt
# (только если не подцепляли его в файле listen)
#include includes/letsencrypt;
# указываем значения заголовка Host:, на которые этот конфиг будет отзываться:
server_name example.com dev.example.com;
# заводим переменную $root_path - она будет несколько раз использоваться в дальнейшем.
# это путь до докрута нашего сайта.
set $root_path /home/example_com/data/www/example.com;
# отключаем переход по символическим ссылкам в докруте, если ссылка и исходный файл принадлежат разным пользователям (например, нельзя будет создать симлинку на /etc/passwd обычным пользователем и почитать её по http).
disable_symlinks if_not_owner from=$root_path;
# указываем, какие страницы считать индексными (если эти страницы существуют - то по пути каталога по http откроется файл с одним из этих имен (первый совпавший) в каталоге)
index index.html index.php index.htm;
# открываем секцию location / {}
# в location / будут попадать все запросы, не попавшие в иные location
location / {
# запросы здесь нужно проксировать в апач
proxy_pass http://127.0.0.1:81;
# если апач отдаст редирект на урл http://127.0.0.1:81/example, то клиенту нужно передать редирект на /example
proxy_redirect http://127.0.0.1:81/ /;
# передаём в апач значение заголовка host, чтобы апач мог выбрать у себя конфиг сайта
proxy_set_header Host $host;
# передаём заголовки, содержащие исходные ip-адреса нашего клиента
# разные CMS могут смотреть на разные заголовки, так что отправляем оба
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
# передаём апачу в специальном заголовке, по http или по https пришел к нам клиент
# некоторые CMS этот заголовок игнорируют, но большинство - нет
# например wordpress исходя из этого заголовка выбирает протокол в урлах для верстки
proxy_set_header X-Forwarded-Proto $scheme;
# закрываем секцию location / {}
}
# заводим именованный location @apache
# в него нельзя обратиться напрямую через web, но его можно использовать в конфигурации.
# по сути у нас конфигурация location @apache полностью дублирует location / (и для корректной работы должна дублировать его).
location @apache {
proxy_pass http://127.0.0.1:81;
proxy_redirect http://127.0.0.1:81/ /;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
# открываем секцию location для статических файлов.
# "~*" - матчинг location и url будет происходить по регулярке без учета регистра (т.е., jpg = JPG).
# сама регулярка достаточно простая
# ^ - начало строки
# .+ - любое количество любых символов
# \. - точка
# (jpg|jpeg) - jpg или jpeg (в самой регулярке - полный список расширений, которые мы будем отдавать прямо с диска)
# $ - конец строки
# в итоге в этой регулярке мы имеем любые урлы вида *.jpg, *.jpeg и так далее.
location ~* ^.+\.(jpg|jpeg|gif|png|rar|txt|tar|bz2|pdf|bmp|js|ico|css|zip|tgz|gz)$ {
# статические файлы ищем на диске в докруте (переменную завели раньше)
root $root_path;
# браузер уведомляем о том, что файл можно закешировать локально на 30 дней
# можно не париться о том, что файлы на сервере будут меняться - браузер всё равно будет переспрашивать (и получать либо 200 и качать файл, либо 301 и брать из кеша)
expires 30d;
# если статического файла нет, то запрос проксируем в апач.
# это полезно, если мы хотим показывать фирменную 404 там, где нет файла на диске
# некоторые CMS не будут работать без этого - они на 404й странице перехватывают запросы к превьюшкам картинок и генерируют их на лету в php (привет, drupal)
error_page 404 = @apache;
}
# для потенциально админских урлов показываем апачем 404-ку
location ~* ^/(webstat|awstats|webmail|myadmin|pgadmin|phpmyadmin)/ {
error_page 404 = @apache;
return 404;
}
# для файлов вида .htaccess/.htpasswd - тоже 404 (только уже nginx-овскую стандартную)
# по вкусу/необходимости упомяните здесь .git, .subversion или какие у вас там vcs используются.
location ~ /\.ht {
return 404;
}
# закрываем секцию server {}
}
Этот же конфиг в txt без комментариев (чуть досыпал там статических файлов в регулярку, потому что в статье не влазило в 1600px по ширине) — https://debian.pro/files/big-man/nginx-vhost.conf
Этот же конфиг в txt с раскрытыми инклудами — https://debian.pro/files/big-man/nginx-vhost-full.conf
Создаём симлинк из sites-available в sites-enabled:
Проверяем валидность конфига:
Рестартим nginx:
Ну и если что-то не работает — пишем ниже.
Возможен такой вариант ?
goto это я предположил скорей всего чтото другое
location / {
goto @apache
}
По Моему одно и тоже писать дважды не комильфо
> и тоже писать дважды не комильфо
Никогда так не думайте, когда пишете конфиг к nginx-у. А то потом весь конфиг в if-ах и try_files там, где они в зопу не уперлись.
Написать 10 раз одно и то же (как вариант — инклудом) — вполне себе способ частенько оптимизировать скорость работы конфига.
Ну а goto без лишних переключений location внутри (а это ещё пара мс) — нет, невозможно.
В 2.4 NameVirtualHost
Nov 30 12:14:43 apachectl[1863]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:5
Server version: Apache/2.4.25 (Debian)
Server built: 2017-09-19T18:58:57
The NameVirtualHost directive no longer has any effect, other than to emit a warning. Any address/port combination appearing in multiple virtual hosts is implicitly treated as a name-based virtual host.
(с) https://httpd.apache.org/docs/2.4/upgrading.html
удали мой коммент. не туда запостил. сорри
Там ссылка, его и без меня в спам отправило) Доставать не буду, ок.
ЗЫ — да, namevirtualhost начиная с apache2.4 можно уже не писать. Но пока что можно и писать.
Добрый день, Влад!
Подскажите, пожалуйста, как должна выглядеть секция «location» для того чтобы для всех URL без расширения (например /download/123) возвращался HTTP 404 ?
Гм. Никак.
location / {return 404; }
А те location, на которых 404 быть не должно — описываете отдельно.
Здравствуйте!
Огромное спасибо за такой отличный мануал!
Собираю по нему сервер. Одновременно прописываю несколько доменов. По результатам данной главы, у меня в каждом sites-available соответственно инклуд letsencrypt’a (include includes/letsencrypt;).
При проверке валидности конфига получаю
nginx: [emerg] duplicate location «/.well-known/acme-challenge/» in /etc/nginx/includes/letsencrypt:7
nginx: configuration file /etc/nginx/nginx.conf test failed
Закомментировал в /etc/nginx/includes/letsencrypt все 3 строки (т.е. вообще получается его отключил), проверка заканчивается успешно.
Либо 2 раза инклудили includes/letsencrypt, либо /.well-known/acme-challenge/ где-то ещё описана.
egrep -rni ‘(letsencrypt|acme-)’ /etc/nginx
посмотрите внимательно.
Нашел.
Он прописан в /etc/nginx/listen:
listen 80;
include includes/letsencrypt;
Это в главе 16 было: либо просто listen 80; в этом файле либо так как выше, чтобы работало на любом сайте.
Еще раз спасибо.
Ничего не понимаю. Все сделал точно по мануалу. В созданную директорию /home/тут_мой_пользователь/data/www/тут_мой_домен скопировал index.html, который apache в /var/www создал.
Пробовал зайти и по http и по https, и указывал явно /index.html и просто по имени домена — пытается минуты две, потом «504 Gateway Time-out. nginx/1.6.2».
В error-логе apacha пусто, в error-логе nginx’a только это:
2018/02/21 02:04:39 [error] 493#0: *53 upstream timed out (110: Connection timed out) while connecting to upstream, client: 185.13.112.127, server: тут_мой_домен, request: «GET / HTTP/1.1», upstream: «http://127.0.0.1:81/», host: «тут_мой_домен»
2018/02/21 02:04:39 [error] 493#0: *53 openat() «/home/тут_мой_пользователь/data/www/тут_мой_домен/favicon.ico» failed (2: No such file or directory), client: 185.13.112.127, server: тут_мой_домен, request: «GET /favicon.ico HTTP/1.1», host: «тут_мой_домен»
Причем ошибка в лог записывается уже после того, как браузер 504 выдаст.
nginx и apache показывают статус active (running).
Думал дело в правах на index.html, дал ему 777, присваивал и www-data:www-data и мой_пользователь:мой_пользователь.
Безрезультатно.
В чем может быть дело?
Прошу прощения, удалите, пожалуйста мой предыдущий комментарий.
При настройке файрвольных правил iptables случайно lo трафик запретил. Ибо нечего до пяти утра сервера настраивать.
Мануал работает на все 100%.
> Это в главе 16 было: либо просто listen 80; в этом файле либо так как выше, чтобы работало на любом сайте.
Поправил чуть статью, спасибо)