Nginx руководство по настройке

Руководство для начинающих

В этом руководстве даётся начальное введение в nginx и описываются
некоторые простые задачи, которые могут быть решены с его помощью.
Предполагается, что nginx уже установлен на компьютере читателя.
Если нет, см. Установка nginx.
В этом руководстве описывается, как запустить и остановить nginx
и перезагрузить его конфигурацию,
объясняется, как устроен конфигурационный файл, и описывается,
как настроить nginx для раздачи статического содержимого, как
настроить прокси-сервер на nginx, и как связать nginx с приложением
FastCGI.

У nginx есть один главный и несколько рабочих процессов.
Основная задача главного процесса — чтение и проверка конфигурации
и управление рабочими процессами.
Рабочие процессы выполняют фактическую обработку запросов.
nginx использует
модель, основанную на событиях, и зависящие от операционной системы
механизмы для эффективного распределения запросов между рабочими процессами.
Количество рабочих процессов задаётся в конфигурационном файле и
может быть фиксированным для данной конфигурации или автоматически
устанавливаться равным числу доступных процессорных ядер (см.
worker_processes).

Как работают nginx и его модули, определяется в конфигурационном файле.
По умолчанию, конфигурационный файл называется nginx.conf
и расположен в каталоге
/usr/local/nginx/conf,
/etc/nginx или
/usr/local/etc/nginx.

Запуск, остановка, перезагрузка конфигурации

Чтобы запустить nginx, нужно выполнить исполняемый файл.
Когда nginx запущен, им можно управлять, вызывая исполняемый файл с
параметром -s.
Используйте следующий синтаксис:

nginx -s сигнал

Где сигнал может быть одним из нижеследующих:

  • stop — быстрое завершение
  • quit — плавное завершение
  • reload — перезагрузка конфигурационного файла
  • reopen — переоткрытие лог-файлов

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

nginx -s quit

Команда должна быть выполнена под тем же
пользователем, под которым был запущен nginx.

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

nginx -s reload

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

Посылать сигналы процессам nginx можно также средствами Unix,
такими как утилита kill.
В этом случае сигнал отправляется напрямую процессу с данным ID.
ID главного процесса nginx записывается по умолчанию в файл
nginx.pid в каталоге
/usr/local/nginx/logs или
/var/run.
Например, если ID главного процесса равен 1628, для отправки сигнала QUIT,
который приведёт к плавному завершению nginx, нужно выполнить:

kill -s QUIT 1628

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

ps -ax | grep nginx

Дополнительную информацию об отправке сигналов процессам nginx
можно найти в Управление nginx.

Структура конфигурационного файла

nginx состоит из модулей, которые настраиваются директивами, указанными
в конфигурационном файле.
Директивы делятся на простые и блочные.
Простая директива состоит из имени и параметров, разделённых пробелами,
и оканчивается точкой с запятой (;).
Блочная директива устроена так же, как и простая директива, но
вместо точки с запятой после имени и параметров следует набор дополнительных
инструкций, помещённых внутри фигурных скобок
({ и }).
Если у блочной директивы внутри фигурных скобок можно задавать другие
директивы, то она называется контекстом (примеры:
events,
http,
server
и
location).

Директивы, помещённые в конфигурационном файле вне любого контекста,
считаются находящимися в контексте
main.
Директивы events и http
располагаются в контексте main, server —
в http, а location — в
server.

Часть строки после символа # считается комментарием.

Раздача статического содержимого

Одна из важных задач конфигурации nginx — раздача
файлов, таких как изображения или статические HTML-страницы.
Рассмотрим пример, в котором в зависимости от запроса файлы будут
раздаваться из разных локальных каталогов: /data/www,
который содержит HTML-файлы, и /data/images,
содержащий файлы с изображениями.
Для этого потребуется отредактировать конфигурационный файл и настроить
блок
server
внутри блока http
с двумя блоками location.

Во-первых, создайте каталог /data/www и положите в него файл
index.html с любым текстовым содержанием, а также
создайте каталог /data/images и положите в него несколько
файлов с изображениями.

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

http {
    server {
    }
}

В общем случае конфигурационный файл может содержать несколько блоков
server,
различаемых по портам, на
которых они
слушают,
и по
имени сервера.
Определив, какой server будет обрабатывать запрос,
nginx сравнивает URI, указанный в заголовке запроса, с параметрами директив
location, определённых внутри блока
server.

В блок server добавьте блок location
следующего вида:

location / {
    root /data/www;
}

Этот блок location задаёт “/
в качестве префикса, который сравнивается с URI из запроса.
Для подходящих запросов добавлением URI к пути, указанному в директиве
root,
то есть, в данном случае, к /data/www, получается
путь к запрашиваемому файлу в локальной файловой системе.
Если есть совпадение с несколькими блоками location,
nginx выбирает блок с самым длинным префиксом.
В блоке location выше указан самый короткий префикс,
длины один,
и поэтому этот блок будет использован, только если не будет совпадения
ни с одним из остальных блоков location.

Далее, добавьте второй блок location:

location /images/ {
    root /data;
}

Он будет давать совпадение с запросами, начинающимися с
/images/
(location / для них тоже подходит, но указанный там префикс
короче).

Итоговая конфигурация блока server должна выглядеть
следующим образом:

server {
    location / {
        root /data/www;
    }

    location /images/ {
        root /data;
    }
}

Это уже работающая конфигурация сервера, слушающего на стандартном порту 80
и доступного на локальном компьютере по адресу
http://localhost/.
В ответ на запросы, URI которых начинаются с /images/,
сервер будет отправлять файлы из каталога /data/images.
Например, на запрос
http://localhost/images/example.png nginx отправит
в ответ файл /data/images/example.png.
Если же этот файл не существует, nginx отправит ответ, указывающий на
ошибку 404.
Запросы, URI которых не начинаются на /images/, будут
отображены на каталог /data/www.
Например, в результате запроса
http://localhost/some/example.html в ответ будет
отправлен файл /data/www/some/example.html.

Чтобы применить новую конфигурацию, запустите nginx, если он ещё не запущен,
или отправьте сигнал reload главному процессу nginx,
выполнив:

nginx -s reload

В случае если что-то работает не как ожидалось, можно попытаться выяснить
причину с помощью файлов access.log и error.log
из каталога
/usr/local/nginx/logs или
/var/log/nginx.

Настройка простого прокси-сервера

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

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

Во-первых, создайте проксируемый сервер, добавив ещё один блок
server в конфигурационный файл nginx со следующим
содержимым:

server {
    listen 8080;
    root /data/up1;

    location / {
    }
}

Это будет простой сервер, слушающий на порту 8080
(ранее директива listen не указывалась, потому что
использовался стандартный порт 80) и отображающий все
запросы на каталог /data/up1 в локальной файловой
системе.
Создайте этот каталог и положите в него файл index.html.
Обратите внимание, что директива root помещена в контекст
server.
Такая директива root будет использована, когда директива
location, выбранная для выполнения запроса, не содержит
собственной директивы root.

Далее, используйте конфигурацию сервера из предыдущего раздела
и видоизмените её, превратив в конфигурацию прокси-сервера.
В первый блок location добавьте директиву
proxy_pass,
указав протокол, имя и порт проксируемого сервера в качестве параметра
(в нашем случае это http://localhost:8080):

server {
    location / {
        proxy_pass http://localhost:8080;
    }

    location /images/ {
        root /data;
    }
}

Мы изменим второй блок
location, который на данный момент отображает запросы
с префиксом /images/ на файлы из каталога
/data/images так, чтобы он подходил для запросов изображений
с типичными расширениями файлов.
Изменённый блок location выглядит следующим образом:

location ~ .(gif|jpg|png)$ {
    root /data/images;
}

Параметром является регулярное выражение, дающее совпадение со всеми
URI, оканчивающимися на .gif, .jpg или
.png.
Регулярному выражению должен предшествовать символ ~.
Соответствующие запросы будут отображены на каталог /data/images.

Когда nginx выбирает блок location,
который будет обслуживать запрос, то вначале он проверяет
директивы location,
задающие префиксы, запоминая location с самым
длинным подходящим префиксом, а затем проверяет регулярные выражения.
Если есть совпадение с регулярным выражением, nginx выбирает соответствующий
location, в противном случае берётся запомненный ранее
location.

Итоговая конфигурация прокси-сервера выглядит следующим образом:

server {
    location / {
        proxy_pass http://localhost:8080/;
    }

    location ~ .(gif|jpg|png)$ {
        root /data/images;
    }
}

Этот сервер будет фильтровать запросы, оканчивающиеся на
.gif, .jpg или .png,
и отображать их на каталог /data/images (добавлением URI к
параметру директивы root) и перенаправлять все остальные
запросы на проксируемый сервер, сконфигурированный выше.

Чтобы применить новую конфигурацию, отправьте сигнал reload
nginx’у, как описывалось в предыдущих разделах.

Существует множество
других директив для дальнейшей настройки прокси-соединения.

Настройка проксирования FastCGI

nginx можно использовать для перенаправления запросов на FastCGI-серверы.
На них могут исполняться приложения, созданные с использованием
разнообразных фреймворков и языков программирования, например, PHP.

Базовая конфигурация nginx для работы с проксируемым FastCGI-сервером
включает в себя использование директивы
fastcgi_pass
вместо директивы proxy_pass,
и директив fastcgi_param
для настройки параметров, передаваемых FastCGI-серверу.
Представьте, что FastCGI-сервер доступен по адресу
localhost:9000.
Взяв за основу конфигурацию прокси-сервера из предыдущего раздела,
замените директиву proxy_pass на директиву
fastcgi_pass и измените параметр на
localhost:9000.
В PHP параметр SCRIPT_FILENAME используется для
определения имени скрипта, а в параметре QUERY_STRING
передаются параметры запроса.
Получится следующая конфигурация:

server {
    location / {
        fastcgi_pass  localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param QUERY_STRING    $query_string;
    }

    location ~ .(gif|jpg|png)$ {
        root /data/images;
    }
}

Таким образом будет настроен сервер, который будет перенаправлять
все запросы, кроме запросов статических изображений, на проксируемый
сервер, работающий по адресу localhost:9000,
по протоколу FastCGI.

This guide gives a basic introduction to nginx and describes some
simple tasks that can be done with it.
It is supposed that nginx is already installed on the reader’s machine.
If it is not, see the Installing nginx page.
This guide describes how to start and stop nginx, and reload its
configuration, explains the structure
of the configuration file and describes how to set up nginx
to serve out static content, how to configure nginx as a proxy
server, and how to connect it with a FastCGI application.

nginx has one master process and several worker processes.
The main purpose of the master process is to read and evaluate configuration,
and maintain worker processes.
Worker processes do actual processing of requests.
nginx employs event-based model and OS-dependent mechanisms to efficiently
distribute requests among worker processes.
The number of worker processes is defined in the configuration file and
may be fixed for a given configuration or automatically adjusted to the
number of available CPU cores (see
worker_processes).

The way nginx and its modules work is determined in the configuration file.
By default, the configuration file is named nginx.conf
and placed in the directory
/usr/local/nginx/conf,
/etc/nginx, or
/usr/local/etc/nginx.

Starting, Stopping, and Reloading Configuration

To start nginx, run the executable file.
Once nginx is started, it can be controlled by invoking the executable
with the -s parameter.
Use the following syntax:

nginx -s signal

Where signal may be one of the following:

  • stop — fast shutdown
  • quit — graceful shutdown
  • reload — reloading the configuration file
  • reopen — reopening the log files

For example, to stop nginx processes with waiting for the worker processes
to finish serving current requests, the following command can be executed:

nginx -s quit

This command should be executed under the same user that
started nginx.

Changes made in the configuration file
will not be applied until the command to reload configuration is
sent to nginx or it is restarted.
To reload configuration, execute:

nginx -s reload

Once the master process receives the signal to reload configuration,
it checks the syntax validity
of the new configuration file and tries to apply the configuration provided
in it.
If this is a success, the master process starts new worker processes
and sends messages to old worker processes, requesting them to
shut down.
Otherwise, the master process rolls back the changes and
continues to work with the old configuration.
Old worker processes, receiving a command to shut down,
stop accepting new connections and continue to service current requests until
all such requests are serviced.
After that, the old worker processes exit.

A signal may also be sent to nginx processes with the help of Unix tools
such as the kill utility.
In this case a signal is sent directly to a process with a given process ID.
The process ID of the nginx master process is written, by default, to the
nginx.pid in the directory
/usr/local/nginx/logs or
/var/run.
For example, if the master process ID is 1628, to send the QUIT signal
resulting in nginx’s graceful shutdown, execute:

kill -s QUIT 1628

For getting the list of all running nginx processes, the ps
utility may be used, for example, in the following way:

ps -ax | grep nginx

For more information on sending signals to nginx, see
Controlling nginx.

Configuration File’s Structure

nginx consists of modules which are controlled by directives specified
in the configuration file.
Directives are divided into simple directives and block directives.
A simple directive consists of the name and parameters separated by spaces
and ends with a semicolon (;).
A block directive has the same structure as a simple directive, but
instead of the semicolon it ends with a set of additional instructions
surrounded by braces ({ and }).
If a block directive can have other directives inside braces,
it is called a context (examples:
events,
http,
server,
and
location).

Directives placed in the configuration file outside
of any contexts are considered to be in the
main context.
The events and http directives
reside in the main context, server
in http, and location in
server.

The rest of a line after the # sign is considered a comment.

Serving Static Content

An important web server task is serving out
files (such as images or static HTML pages).
You will implement an example where, depending on the request,
files will be served from different local directories: /data/www
(which may contain HTML files) and /data/images
(containing images).
This will require editing of the configuration file and setting up of a
server
block inside the http
block with two location
blocks.

First, create the /data/www directory and put an
index.html file with any text content into it and
create the /data/images directory and place some
images in it.

Next, open the configuration file.
The default configuration file already includes several examples of
the server block, mostly commented out.
For now comment out all such blocks and start a new
server block:

http {
    server {
    }
}

Generally, the configuration file may include several
server blocks
distinguished by ports on which
they listen to
and by
server names.
Once nginx decides which server processes a request,
it tests the URI specified in the request’s header against the parameters of the
location directives defined inside the
server block.

Add the following location block to the
server block:

location / {
    root /data/www;
}

This location block specifies the
/” prefix compared with the URI from the request.
For matching requests, the URI will be added to the path specified in the
root
directive, that is, to /data/www,
to form the path to the requested file on the local file system.
If there are several matching location blocks nginx
selects the one with the longest prefix.
The location block above provides the shortest
prefix, of length one,
and so only if all other location
blocks fail to provide a match, this block will be used.

Next, add the second location block:

location /images/ {
    root /data;
}

It will be a match for requests starting with /images/
(location / also matches such requests,
but has shorter prefix).

The resulting configuration of the server block should
look like this:

server {
    location / {
        root /data/www;
    }

    location /images/ {
        root /data;
    }
}

This is already a working configuration of a server that listens
on the standard port 80 and is accessible on the local machine at
http://localhost/.
In response to requests with URIs starting with /images/,
the server will send files from the /data/images directory.
For example, in response to the
http://localhost/images/example.png request nginx will
send the /data/images/example.png file.
If such file does not exist, nginx will send a response
indicating the 404 error.
Requests with URIs not starting with /images/ will be
mapped onto the /data/www directory.
For example, in response to the
http://localhost/some/example.html request nginx will
send the /data/www/some/example.html file.

To apply the new configuration, start nginx if it is not yet started or
send the reload signal to the nginx’s master process,
by executing:

nginx -s reload

In case something does not work as expected, you may try to find out
the reason in access.log and
error.log files in the directory
/usr/local/nginx/logs or
/var/log/nginx.

Setting Up a Simple Proxy Server

One of the frequent uses of nginx is setting it up as a proxy server, which
means a server that receives requests, passes them to the proxied servers,
retrieves responses from them, and sends them to the clients.

We will configure a basic proxy server, which serves requests of
images with files from the local directory and sends all other requests to a
proxied server.
In this example, both servers will be defined on a single nginx instance.

First, define the proxied server by adding one more server
block to the nginx’s configuration file with the following contents:

server {
    listen 8080;
    root /data/up1;

    location / {
    }
}

This will be a simple server that listens on the port 8080
(previously, the listen directive has not been specified
since the standard port 80 was used) and maps
all requests to the /data/up1 directory on the local
file system.
Create this directory and put the index.html file into it.
Note that the root directive is placed in the
server context.
Such root directive is used when the
location block selected for serving a request does not
include its own root directive.

Next, use the server configuration from the previous section
and modify it to make it a proxy server configuration.
In the first location block, put the
proxy_pass
directive with the protocol, name and port of the proxied server specified
in the parameter (in our case, it is http://localhost:8080):

server {
    location / {
        proxy_pass http://localhost:8080;
    }

    location /images/ {
        root /data;
    }
}

We will modify the second location
block, which currently maps requests with the /images/
prefix to the files under the /data/images directory,
to make it match the requests of images with typical file extensions.
The modified location block looks like this:

location ~ .(gif|jpg|png)$ {
    root /data/images;
}

The parameter is a regular expression matching all URIs ending
with .gif, .jpg, or .png.
A regular expression should be preceded with ~.
The corresponding requests will be mapped to the /data/images
directory.

When nginx selects a location block to serve a request
it first checks location
directives that specify prefixes, remembering location
with the longest prefix, and then checks regular expressions.
If there is a match with a regular expression, nginx picks this
location or, otherwise, it picks the one remembered earlier.

The resulting configuration of a proxy server will look like this:

server {
    location / {
        proxy_pass http://localhost:8080/;
    }

    location ~ .(gif|jpg|png)$ {
        root /data/images;
    }
}

This server will filter requests ending with .gif,
.jpg, or .png
and map them to the /data/images directory (by adding URI to the
root directive’s parameter) and pass all other requests
to the proxied server configured above.

To apply new configuration, send the reload signal to
nginx as described in the previous sections.

There are many more
directives that may be used to further configure a proxy connection.

Setting Up FastCGI Proxying

nginx can be used to route requests to FastCGI servers which run
applications built with various frameworks and programming languages
such as PHP.

The most basic nginx configuration to work with a FastCGI server
includes using the
fastcgi_pass
directive instead of the proxy_pass directive,
and fastcgi_param
directives to set parameters passed to a FastCGI server.
Suppose the FastCGI server is accessible on localhost:9000.
Taking the proxy configuration from the previous section as a basis,
replace the proxy_pass directive with the
fastcgi_pass directive and change the parameter to
localhost:9000.
In PHP, the SCRIPT_FILENAME parameter is used for
determining the script name, and the QUERY_STRING
parameter is used to pass request parameters.
The resulting configuration would be:

server {
    location / {
        fastcgi_pass  localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param QUERY_STRING    $query_string;
    }

    location ~ .(gif|jpg|png)$ {
        root /data/images;
    }
}

This will set up a server that will route all requests except for
requests for static images to the proxied server operating on
localhost:9000 through the FastCGI protocol.

Время на прочтение
5 мин

Количество просмотров 276K

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

Неплохой начальной точкой для настройки nginx является конфиг, который идёт в комплекте с дистрибутивом, но очень многие возможности этого сервера в нём даже не упоминаются. Значительно более подробный пример есть на сайте Игоря Сысоева: sysoev.ru/nginx/docs/example.html. Однако, давайте лучше попробуем собрать с нуля свой конфиг, с бриджем и поэтессами. :)

Начнём с общих настроек. Сначала укажем пользователя, от имени которого будет работать nginx (от рута работать плохо, все знают :) )

user nobody;

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

worker_processes 2;

Уточним, куда писать логи ошибок. Потом, для отдельных виртуальных серверов, этот параметр можно переопределить, так что в этот лог будут сыпаться только «глобальные» ошибки, например, связанные со стартом сервера.

error_log /spool/logs/nginx/nginx.error_log notice; # уровень уведомлений "notice", конечно, можно менять

Теперь идёт очень интересная секция «events». В ней можно задать максимальное количество соединений, которые одновременно будет обрабатывать один процесс-воркер, и метод, который будет использоваться для получения асинхронных уведомлений о событиях в ОС. Конечно же, можно выбрать только те методы, которые доступны на вашей ОС и были включены при компиляции.

Эти параметры могут оказать значительное влияние на производительность вашего сервера. Их надо подбирать индивидуально, в зависимости от ОС и железа. Я могу привести только несколько общих правил.

Модули работы с событиями:
— select и poll обычно медленнее и довольно сильно нагружают процессор, зато доступны практически везде, и работают практически всегда;
— kqueue и epoll — более эффективны, но доступны только во FreeBSD и Linux 2.6, соответственно;
— rtsig — довольно эффективный метод, и поддерживается даже очень старыми линуксами, но может вызывать проблемы при большом числе подключений;
— /dev/poll — насколько мне известно, работает в несколько более экзотических системах, типа соляриса, и в нём довольно эффективен;

Параметр worker_connections:
— Общее максимальное количество обслуживаемых клиентов будет равно worker_processes * worker_connections;
— Иногда могут сработать в положительную сторону даже самые экстремальные значения, вроде 128 процессов, по 128 коннектов на процесс, или 1 процесса, но с параметром worker_connections=16384. В последнем случае, впрочем, скорее всего понадобится тюнить ОС.

events {
worker_connections 2048;
use kqueue; # У нас BSD :)
}

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

http {
# Весь код ниже будет внутри этой секции %)
# ...
}

Внутри этой секции могут находиться несколько довольно интересных параметров.

Системный вызов sendfile появился в Linux относительно недавно. Он позволяет отправить данные в сеть, минуя этап их копирования в адресное пространство приложения. Во многих случаях это существенно повышает производительность сервера, так что параметр sendfile лучше всегда включать.

sendfile on;

Параметр keepalive_timeout отвечает за максимальное время поддержания keepalive-соединения, в случае, если пользователь по нему ничего не запрашивает. Обдумайте, как именно на вашем сайте посылаются запросы, и исправьте этот параметр. Для сайтов, активно использующих AJAX, соединение лучше держать подольше, для статических страничек, которые пользователи будут долго читать, соединение лучше разрывать пораньше. Учтите, что поддерживая неактивное keepalive-соединение, вы занимаете коннекшн, который мог бы использоваться по-другому. :)

keepalive_timeout 15;

Отдельно стоит выделить настройки проксирования nginx. Чаще всего, nginx используется именно как сервер-прокси, соответственно они имеют довольно большое значение. В частности, размер буфера для проксируемых запросов имеет смысл устанавливать не менее, чем ожидаемый размер ответа от сервера-бэкенда. При медленных (или, наоборот, очень быстрых) бэкендах, имеет смысл изменить таймауты ожидания ответа от бэкенда. Помните, чем больше эти таймауты, тем дольше будут ждать ответа ваши пользователе, при тормозах бэкенда.

proxy_buffers 8 64k;
proxy_intercept_errors on;
proxy_connect_timeout 1s;
proxy_read_timeout 3s;
proxy_send_timeout 3s;

Небольшой трюк. В случае, если nginx обслуживает более чем один виртуальный хост, имеет смысл создать «виртуальный хост по-умолчанию», который будет обрабатывать запросы в тех случаях, когда сервер не сможет найти другой альтернативы по заголовку Host в запросе клиента.

# default virtual host
server {
listen 80 default;
server_name localhost;
deny all;
}

Далее может следовать одна (или несколько) секций «server». В каждой из них описывается виртуальный хост (чаще всего, name-based). Для владельцев множества сайтов на одном хостинге, или для хостеров здесь может быть что-то, типа директивы

include /spool/users/nginx/*.conf;

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

server {
listen 80;

# Обратите внимание, в директиве server_name можно указать несколько имён одновременно.
server_name myserver.ru myserver.com;
access_log /spool/logs/nginx/myserver.access_log timed;
error_log /spool/logs/nginx/myserver.error_log warn;
# ...


Установим кодировку для отдачи по-умолчанию.

charset utf-8;

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

client_max_body_size 1m;

Включим для сервера SSI и попросим для SSI-переменных резервировать не более 1 килобайта.

ssi on;
ssi_value_length 1024;

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

set $www_root "/data/myserver/root";

location / {
proxy_pass 127.0.0.1:9999;
proxy_set_header X-Real-IP $remote_addr;
proxy_intercept_errors off;
proxy_read_timeout 5s; # Обратите внимание, здесь мы переопределили глобальную настройку, заданную выше
proxy_send_timeout 3s;
# ...


Отдельный блок в корневом локейшне посвящён компрессии получаемого результата в gzip. Это позволит вам, и вашим пользователям сэкономить на трафике. Nginx можно указать, какие типы файлов (или, в нашем случае, ответов от бэкенда) стоит сжимать, и каким должен быть минимальный размер файла для того, чтобы использовать сжатие.

# ...
gzip on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml;
}

location /i/ {
root $www_root/static/;
}
}


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

В данной статье описана установка и настройка высокопроизводительного современного веб-сервера nginx на примере облачной платформы Selectel. Все действия актуальны для ОС Ubuntu 20.04 LTS 64-bit. Nginx — это веб-сервер с открытым исходным кодом, созданный работать под высокой нагрузкой, чаще всего используемый для отдачи статического контента, например, html страниц, медиафайлов, документов, архивов, картинок и т.д. Подготовка […]

Изображение записи

В данной статье описана установка и настройка высокопроизводительного современного веб-сервера nginx на примере облачной платформы Selectel. Все действия актуальны для ОС Ubuntu 20.04 LTS 64-bit.

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

Подготовка сервера

Для начала установим сам сервер. После прохождения регистрации, необходимо войти в панель управления. Далее в меню «Облачная платформа» — «Создать сервер».

Откроется оснастка создания сервера, где необходимо задать понятное для дальнейшей работы имя сервера, в примере это «WebSrv01». Регион и зону можно оставить без изменения. Для выбора операционной системы необходимо нажать кнопку «Выбрать другой источник».

Откроется меню «Выбор источника».

В поле «Операционные системы», выбираем Ubuntu, в левом поле появится список всех доступных образов операционных систем на базе данной ОС, выбираем «Ubuntu 20.04 LTS 64-bit» и нажимаем кнопку «Выбрать».

Перемещаемся вниз по странице. В нашем примере используется только «Локальный диск», флажок установлен, в поле «Сетевые диски» нажимаем кнопку «Удалить диск».

В поле «Сеть», поскольку это наш первый сервер выбираем «Приватная подсеть + 1 плавающий IP», после выбора значение в поле сменится на «Новый плавающий IP адрес».

Необходимо скопировать «Пароль для root», он понадобиться для первоначальной настройки сервера через SSH протокол.

Нажимаем кнопку «Создать», сервер будет доступен примерно через 1 минуту. Переходим в меню «Облачная платформа» — «Серверы».

В списке появится сервер с именем, что задали ранее, его IP адрес, который будем использовать для удаленного подключения, на скриншоте в области с цифрой 3, статус сервера ALIVE, означает готовность сервера. Подключаемся к серверу, используя любой SSH-клиент.

Проведем небольшую первоначальную настройку сервера. Обновим информацию о доступных пакетах из подключенных репозиториев:

apt update

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

adduser webuser

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

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

usermod -aG sudo webuser

Открываем конфигурационный файл SSH-сервера:

nano /etc/ssh/sshd_config

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

Port 22100

Переходим к строке PermitRootLogin yes, меняем значение на no, тем самым запретив вход пользователя root напрямую:

PermitRootLogin no

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

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

service sshd restart

Установка nginx

Установка сервера nginx может быть выполнена как непосредственно на машину, так и в виде docker контейнера. У каждого метода есть свои преимущества и недостатки, описание которых выходит за рамки данной статьи. Мы посмотрим оба варианта.

Начнем с непосредственной установки на сервер:

apt install nginx

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

Дожидаемся окончания процесса установки.

Разрешим автозапуск сервера:

systemctl enable nginx

Проверяем результат:

systemctl is-enabled nginx

Если в ответ получили «enabled», значит nginx успешно добавлен в автозагрузку.

Запуск nginx

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

service nginx start

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

service nginx status

Если в статусе присутствует строка Active: active (running), значит сервер работает. Также в этом можно убедиться, набрав в адресной строке браузера IP адрес сервера, будет отображено приветственное сообщение от 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

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

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

Настройка 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/*;
}

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

Директивы

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

  • 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 в качестве бэкэнда:

apt install php-fpm php-mysql

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

После установки сервис будет автоматически запущен и добавлен в автозагрузку. Создаем файл пула для конкретного сайта 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 для выхода из редактора.

Перезагружаем сервис 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/

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

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

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

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

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

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

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

usermod -aG webuser www-data

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

service nginx restart

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

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

Команды 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

Настройка 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 уведомит о приближающимся конце срока действия сертификата по электронной почте, указанной при первом запросе.

Редирект с 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/. Однако, у начинающего администратора возникают сложности с интерпретацией, содержащейся в них информации.

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

Состояние перевода: На этой странице представлен перевод статьи nginx. Дата последней синхронизации: 18 июля 2022. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

nginx (произносится «э́нжин-э́кс» или «э́нжин-и́кс») — это свободный высокопроизводительный HTTP-сервер с открытым исходным кодом, а также обратный прокси и IMAP/POP3 прокси-сервер, написанный Игорем Сысоевым в 2005 году. nginx получил широкое распространение благодаря своей стабильности, богатой функциональности, простой настройке и низкому потреблению ресурсов.

Данная статья описывает установку nginx и интеграцию с PHP через #FastCGI.

Установка

Установите пакет nginx-mainline (основная ветка: новые возможности, обновления и исправления ошибок) или nginx (стабильная ветка; только исправления серьёзных ошибок).

Рекомендуется использовать основную (mainline) ветку. Основная причина для использования стабильной ветки — возможная несовместимость со сторонними модулями или непреднамеренное появление ошибок при реализации новых функций.

Примечание: Все модули nginx, доступные в официальных репозиториях, в качестве зависимости требуют пакет nginx (а не nginx-mainline). Возможно, стоит просмотреть список модулей на наличие тех, которые вам могут понадобиться, прежде чем принимать решение о выборе между nginx и nginx-mainline. Модули для nginx-mainline можно найти в пользовательском репозитории Arch.

Если для обеспечения дополнительной безопасности вы хотите установить nginx в chroot-окружении, смотрите раздел #Установка в chroot.

Запуск

Запустите/включите службу nginx.service.

Страница по умолчанию, доступная по адресу http://127.0.0.1 располагается в /usr/share/nginx/html/index.html.

Настройка

Первые шаги по настройке и использованию nginx описаны в официальном руководстве для начинающих. Вы можете настроить сервер, редактируя файлы в /etc/nginx/; главный файл настроек расположен в /etc/nginx/nginx.conf.

Более подробную информацию можно прочитать на странице Nginx Configuration Examples и в официальной документации.

Приведенные далее примеры покрывают большинство типичных потребностей. Предполагается, что вы используете стандартное место расположения веб-документов (/usr/share/nginx/html). Если это не так, замените путь на свой.

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

/etc/nginx/nginx.conf
user http;
worker_processes auto;
worker_cpu_affinity auto;

events {
    multi_accept on;
    worker_connections 1024;
}

http {
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 4096;
    client_max_body_size 16M;

    # MIME
    include mime.types;
    default_type application/octet-stream;

    # журналы
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # загрузка дополнительных файлов конфигурации
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Основные настройки

Процессы и соединения

Вы должны выбрать подходящее значение для worker_processes. Этот параметр определяет сколько одновременных соединений сможет принимать nginx и сколько процессоров он сможет при этом использовать. Как правило, это значение устанавливают равным количеству аппаратных потоков в системе. Однако, начиная с версий 1.3.8 и 1.2.5, в качестве значения worker_processes вы также можете задать auto, при этом nginx попытается автоматически подобрать оптимальное значение (источник).

Максимальное количество одновременных соединений, которое nginx сможет принимать, вычисляется как max_clients = worker_processes * worker_connections.

Запуск под другим пользователем

По умолчанию запускается мастер-процесс nginx от имени root, а он в свою очередь запускает рабочие процессы от имени пользователя http. Для запуска рабочих процессов от имени другого пользователя измените значение директивы user в файле nginx.conf:

/etc/nginx/nginx.conf
user пользователь [группа];

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

Совет: Можно запустить nginx без прав root через systemd. Смотрите #Запуск без привилегий через systemd.

Блоки server

Посредством добавления блоков server в файл настроек возможно обслуживать сразу несколько доменов одновременно. Эти блоки работают аналогично «VirtualHosts» в Apache.
Смотрите также примеры в официальной документации.

В этом примере сервер принимает запросы для двух доменов: domainname1.dom и domainname2.dom:

/etc/nginx/nginx.conf
...
server {
    listen 80;
    listen [::]:80;
    server_name domainname1.dom;
    root /usr/share/nginx/domainname1.dom/html;
    location / {
        index index.php index.html index.htm;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name domainname2.dom;
    root /usr/share/nginx/domainname2.dom/html;
    ...
}

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

Примечание: Убедитесь, что указанные домены существуют и указывают на IP-адрес устройства, на котором запущен nginx. Вы можете настроить DNS-сервер, например BIND или dnsmasq, или посмотрите варианты разрешения имён в локальной сети.

Управление блоками server

Для удобства можно поместить разные блоки server в разные файлы. Это также позволит включать и отключать отдельные сайты.

Создайте следующие каталоги:

# mkdir /etc/nginx/sites-available
# mkdir /etc/nginx/sites-enabled

Внутри каталога sites-available создайте файл, содержащий один или несколько блоков server:

/etc/nginx/sites-available/example.conf
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ...
}

В файле nginx.conf конце блока http добавьте строку include sites-enabled/*;:

/etc/nginx/nginx.conf
http {
    ...
    include sites-enabled/*;
}

Чтобы включить сайт, в каталоге sites-enabled создайте символическую ссылку на связанный с ним файл:

# ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/example.conf

А чтобы отключить сайт, удалите её:

# unlink /etc/nginx/sites-enabled/example.conf

Перезапустите службу nginx.service или перезагрузите конфигурацию (reload), чтобы изменения вступили в силу.

TLS

openssl предоставляет поддержку TLS/SSL и установлен по умолчанию на установленных Arch.

Совет:

  • Перед тем как настраивать SSL, вы можете почитать документацию ngx_http_ssl_module
  • Let’s Encrypt — это бесплатный, автоматизированный и открытый центр сертификации. Есть плагин для получения доверенных SSL-сертификатов прямо из командной строки и автоматической настройки.
  • На сайте Mozilla есть полезная статья про TLS, а также инструмент, помогающий составить безопасную конфигурацию.

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

# cd /etc/nginx/
# openssl req -new -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 1095
# chmod 400 nginx.key
# chmod 444 nginx.crt

Примечание: Опция -days является необязательной, а RSA keysize можно уменьшить до 2048 (по умолчанию).

Если же вам нужно создать CSR, то следуйте данным инструкциям по созданию ключа, вместо приведённых выше:

# openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out nginx.key
# chmod 400 nginx.key
# openssl req -new -sha256 -key nginx.key -out nginx.csr
# openssl x509 -req -days 1095 -in nginx.csr -signkey nginx.key -out nginx.crt

В качестве отправкой точки для создания конфигурации TLS в /etc/nginx/nginx.conf можно использовать генератор настроек SSL от Mozilla.

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

Пользовательские каталоги

Чтобы сделать Apache-подобные адреса вида ~пользователь, указывающие на пользовательские каталоги ~/public_html, используйте подобную конфигурацию. (Примечание: если вы планируете использовать PHP, то связанный с ним location должен стоять первым.)

/etc/nginx/nginx.conf
...
server {
    ...
    # Обработка файлов PHP в пользовательских каталогах, например http://example.com/~user/test.php
    location ~ ^/~(.+?)(/.+.php)$ {
        alias          /home/$1/public_html$2;
        fastcgi_pass   unix:/run/php-fpm/php-fpm.sock;
        fastcgi_index  index.php;
        include        fastcgi.conf;
    }

    # Пользовательские каталоги, например http://example.com/~user/
    location ~ ^/~(.+?)(/.*)?$ {
        alias     /home/$1/public_html$2;
        index     index.html index.htm;
        autoindex on;
    }
    ...
}
...

Подробнее о настройке PHP в nginx смотрите в разделе #Реализация PHP.

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

FastCGI

FastCGI или просто FCGI — это протокол, являющийся интерфейсом между веб-сервером и интерактивными программами. Это модифицированный CGI (Common Gateway Interface), главная цель которого — снизить накладные расходы, связанные со взаимодействием веб сервера и CGI программ, тем самым позволяя серверу обрабатывать большее количество запросов одновременно.

Технология FastCGI встроена в nginx для работы со многими внешними инструментами, например, Perl, PHP и Python.

Реализация PHP

В качестве FastCGI-сервера для PHP рекомендуется использовать PHP-FPM.

Установите пакет php-fpm и проверьте корректность настроек PHP.
Основным конфигурационным файлом PHP-FPM является /etc/php/php-fpm.conf. Включите и запустите systemd службу php-fpm.

Примечание:

  • Если вы запускаете nginx под другим пользователем, убедитесь, что Unix-сокет PHP-FPM доступен этому пользователю, или используйте TCP-сокет.
  • Если вы запускаете nginx в изолированном окружении (к примеру, chroot находится в /srv/nginx-jail, веб-документы расположены в /srv/nginx-jail/www), то вы должны в /etc/php/php-fpm.conf добавить опции chroot /srv/nginx-jail и listen = /srv/nginx-jail/run/php-fpm/php-fpm.sock внутри секции пула (по умолчанию это [www]). Создайте каталог для файла сокета, если его нет. Более того, для модулей, которые динамически связаны с зависимостями, вам нужно будет скопировать эти зависимости в chroot (например, для php-imagick вам нужно будет скопировать в chroot библиотеки ImageMagick, но не сам imagick.so).
Настройка nginx

Внутри каждого блока server, который обслуживает веб-приложение PHP, должен находиться блок location [1], например:

/etc/nginx/sites-available/example.conf
server {
    root /usr/share/nginx/html;

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

    location ~ .php$ {
        # 404
        try_files $fastcgi_script_name =404;

        # default fastcgi_params
        include fastcgi_params;

        # fastcgi settings
        fastcgi_pass			unix:/run/php-fpm/php-fpm.sock;
        fastcgi_index			index.php;
        fastcgi_buffers			8 16k;
        fastcgi_buffer_size		32k;

        # fastcgi params
        fastcgi_param DOCUMENT_ROOT	$realpath_root;
        fastcgi_param SCRIPT_FILENAME	$realpath_root$fastcgi_script_name;
        #fastcgi_param PHP_ADMIN_VALUE	"open_basedir=$base/:/usr/lib/php/:/tmp/";
    }
}

Если требуется обрабатывать другие расширения наряду с PHP (например .html и .htm):

location ~ [^/].(php|html|htm)(/|$) {
    ...
}

Все расширения, обрабатываемые в php-fpm должны быть также явно добавлены в
/etc/php/php-fpm.d/www.conf:

security.limit_extensions = .php .html .htm

Примечание: Аргумент fastcgi_pass должен быть определен как TCP-сокет или сокет Unix выбранным FastCGI сервером в его конфигурационном файле. По умолчанию для php-fpm используется сокет

fastcgi_pass unix:/run/php-fpm/php-fpm.sock;

Вы можете использовать также общий TCP-сокет:

fastcgi_pass 127.0.0.1:9000;

Однако, доменные сокеты Unix должны работать быстрее.

Совет: Если несколько блоков server используют одну и ту же конфигурацию PHP-FPM, можно вынести общие настройки в отдельный файл для удобства, например php_fastcgi.conf:

/etc/nginx/php_fastcgi.conf
location ~ .php$ {
    # 404
    try_files $fastcgi_script_name =404;

    # default fastcgi_params
    include fastcgi_params;

    # fastcgi settings
    ...
}

И затем подключать этот файл в тех блоках server, в которых нужна обработка PHP:

/etc/nginx/sites-available/example.conf
server {
    server_name example.com;
    ...

    include /etc/nginx/php_fastcgi.conf;
}
Проверка конфигурации

Перезапустите службы php-fpm и nginx после изменения настроек, чтобы изменения вступили в силу.

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

<?php
  phpinfo();
?>

При открытии файла в браузере должна отобразиться информационная страница с текущими настройками PHP.

Реализация CGI

Эта реализация нужна для CGI-приложений.

fcgiwrap

Установите fcgiwrap. Настроить его можно путём редактирования юнита fcgiwrap.socket. Включите и запустите fcgiwrap.socket.

Несколько рабочих потоков

Если вы хотите породить несколько рабочих потоков, вам рекомендуется использовать multiwatchAUR, который умеет отслеживать упавшие подпроцессы и перезапускать их. Вам нужно использовать spawn-fcgi, чтобы создать доменный сокет Unix, так как multiwatch не может обрабатывать сокеты, созданные systemd, однако, fcgiwrap сама по себе не вызывает никаких проблем, если вызывается непосредственно из юнит-файла.

Сделайте замещение файла юнита fcgiwrap.service (и юнита fcgiwrap.socket, если он есть), и отредактируйте строку ExecStart в соответствии с вашими нуждами. В примере показан юнит файл, который использует multiwatchAUR. Убедитесь, что fcgiwrap.socket не включен и не запущен, потому что он будет конфликтовать с этим юнитом:

/etc/systemd/system/fcgiwrap.service
[Unit]
Description=Simple CGI Server
After=nss-user-lookup.target

[Service]
ExecStartPre=/bin/rm -f /run/fcgiwrap.socket
ExecStart=/usr/bin/spawn-fcgi -u http -g http -s /run/fcgiwrap.sock -n -- /usr/bin/multiwatch -f 10 -- /usr/sbin/fcgiwrap
ExecStartPost=/usr/bin/chmod 660 /run/fcgiwrap.sock
PrivateTmp=true
Restart=on-failure

[Install]
WantedBy=multi-user.target

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

Важно: Строка ExecStartPost требуется из-за странного поведения, которое я наблюдаю при использовании опции -M 660 для spawn-fcgi. Устанавливается неправильный режим. Может это баг?

Настройка nginx

В каталоге /etc/nginx скопируйте файл fastcgi_params в fcgiwrap_params. В файле fcgiwrap_params удалите строки, которые устанавливают SCRIPT_NAME и DOCUMENT_ROOT.

Внутри каждого блока server CGI-приложения должен находиться вложенный блок location:

location ~ .cgi$ {
     include       fcgiwrap_params;
     fastcgi_param DOCUMENT_ROOT /srv/www/cgi-bin/;
     fastcgi_param SCRIPT_NAME   myscript.cgi;
     fastcgi_pass  unix:/run/fcgiwrap.sock;
}

Сокетом по умолчанию для fcgiwrap является /run/fcgiwrap.sock.

Вместо параметров DOCUMENT_ROOT и SCRIPT_NAME можно использовать более короткую альтернативу fastcgi_param SCRIPT_FILENAME /srv/www/cgi-bin/myscript.cgi. При её использовании не понадобится копировать fastcgi_params в fcgiwrap_params и удалять строки DOCUMENT_ROOT and SCRIPT_NAME.

Важно: Если используются SCRIPT_NAME и DOCUMENT_ROOT, fcgiwrap будет отклонять любые другие fastcgi_param, установленные в nginx. Вы должны использовать SCRIPT_FILENAME для того, чтобы другие параметры (например, PATH_INFO) могли быть установлены через конфигурацию Nginx. Подробнее на GitHub.

Если вы продолжаете получать ошибку 502 - bad Gateway, проверьте, передаёт ли ли ваше CGI-приложение mime-тип содержимого. Для html это должно быть Content-type: text/html.

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

Установка в chroot

Установка nginx в chroot добавляет дополнительный уровень безопасности. Для максимальной безопасности chroot должен включать только файлы, необходимые для запуска сервера nginx, при этом все файлы должны иметь по возможности максимально ограниченные права доступа. Например, как можно больше файлов должно принадлежать пользователю root, а таким каталогам, как /usr/bin должен быть установлен запрет на чтение и запись.

Arch поставляется с пользователем http и группой по умолчанию, от имени которых запускается сервер. Измененный корневой каталог будет находиться в /srv/http.

Существует perl-скрипт для создания chroot-окружения, который доступен в jail.pl gist. Вы можете либо использовать его, либо следовать дальнейшим инструкциям из этой статьи. Скрипт требует прав суперпользователя для работы. Вам нужно будет раскомментировать строку, перед тем, как он сможет выполнять какие-либо изменения.

Создание необходимых устройств

Для nginx нужны /dev/null, /dev/random и /dev/urandom. Чтобы установить их в chroot мы создадим каталог /dev и добавим устройства с помощью mknod. Избегайте монтирования всех устройств в /dev: тогда, даже если chroot будет скомпрометирован, атакующий должен будет выбраться из chroot-окружения чтобы добраться до важных устройств, например /dev/sda1.

Совет: Убедитесь, что /src/http примонтирован без опции no-dev

Совет: Смотрите mknod(1) и ls -l /dev/{null,random,urandom}, чтобы лучше понять опции mknod.

# export JAIL=/srv/http
# mkdir $JAIL/dev
# mknod -m 0666 $JAIL/dev/null c 1 3
# mknod -m 0666 $JAIL/dev/random c 1 8
# mknod -m 0444 $JAIL/dev/urandom c 1 9

Создание необходимых каталогов

Для работы nginx требует определенный набор файлов. Перед тем, как их копировать, создайте для них соответствующие каталоги. Предполагается, что ваш корневой каталог веб-документов nginx находится в /srv/http/www.

# mkdir -p $JAIL/etc/nginx/logs
# mkdir -p $JAIL/usr/{lib,bin}
# mkdir -p $JAIL/usr/share/nginx
# mkdir -p $JAIL/var/{log,lib}/nginx
# mkdir -p $JAIL/www/cgi-bin
# mkdir -p $JAIL/{run,tmp}
# cd $JAIL; ln -s usr/lib lib
# cd $JAIL; ln -s usr/lib lib64
# cd $JAIL/usr; ln -s lib lib64

Затем смонтируйте $JAIL/tmp и $JAIL/run как tmpfs-ы. Размер должен быть ограничен, чтобы быть уверенным, что атакующий не сможет занять всю доступную RAM.

# mount -t tmpfs none $JAIL/run -o 'noexec,size=1M'
# mount -t tmpfs none $JAIL/tmp -o 'noexec,size=100M'

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

/etc/fstab
 tmpfs   /srv/http/run   tmpfs   rw,noexec,relatime,size=1024k   0       0
 tmpfs   /srv/http/tmp   tmpfs   rw,noexec,relatime,size=102400k 0       0

Заполнение chroot

Сначала скопируйте простые файлы.

# cp -r /usr/share/nginx/* $JAIL/usr/share/nginx
# cp -r /usr/share/nginx/html/* $JAIL/www
# cp /usr/bin/nginx $JAIL/usr/bin/
# cp -r /var/lib/nginx $JAIL/var/lib/nginx

Теперь скопируйте нужные библиотеки. Используйте ldd, чтобы отобразить их и скопируйте все файлы в правильное место. Копирование предпочтительнее, чем создание жестких ссылок, потому, что даже если атакующий получит права записи в файлы, они не смогут уничтожить или изменить системные файлы вне chroot-окружения.

$ ldd /usr/bin/nginx
linux-vdso.so.1 (0x00007fffc41fe000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f57ec3e8000)
libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007f57ec1b1000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f57ebead000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f57ebbaf000)
libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f57eb94c000)
libssl.so.1.0.0 => /usr/lib/libssl.so.1.0.0 (0x00007f57eb6e0000)
libcrypto.so.1.0.0 => /usr/lib/libcrypto.so.1.0.0 (0x00007f57eb2d6000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f57eb0d2000)
libz.so.1 => /usr/lib/libz.so.1 (0x00007f57eaebc000)
libGeoIP.so.1 => /usr/lib/libGeoIP.so.1 (0x00007f57eac8d000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f57eaa77000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f57ea6ca000)
/lib64/ld-linux-x86-64.so.2 (0x00007f57ec604000)

Для файлов, находящихся в /usr/lib, вы можете воспользоваться следующей командой:

# cp $(ldd /usr/bin/nginx | grep /usr/lib | sed -sre 's/(.+)(/usr/lib/S+).+/2/g') $JAIL/usr/lib

А для ld-linux-x86-64.so — следующей командой:

# cp /lib64/ld-linux-x86-64.so.2 $JAIL/lib

Примечание: Не пытайтесь скопировать linux-vdso.so — это не настоящая библиотека и ее не существует в /usr/lib.

Копируйте другие необходимые библиотеки и системные файлы.

# cp /usr/lib/libnss_* $JAIL/usr/lib
# cp -rfvL /etc/{services,localtime,nsswitch.conf,nscd.conf,protocols,hosts,ld.so.cache,ld.so.conf,resolv.conf,host.conf,nginx} $JAIL/etc

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

$JAIL/etc/group
http:x:33:
nobody:x:99:
$JAIL/etc/passwd
http:x:33:33:http:/:/bin/false
nobody:x:99:99:nobody:/:/bin/false
$JAIL/etc/shadow
http:x:14871::::::
nobody:x:14871::::::
$JAIL/etc/gshadow
http:::
nobody:::
# touch $JAIL/etc/shells
# touch $JAIL/run/nginx.pid

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

# chown -R root:root $JAIL/

# chown -R http:http $JAIL/www
# chown -R http:http $JAIL/etc/nginx
# chown -R http:http $JAIL/var/{log,lib}/nginx
# chown http:http $JAIL/run/nginx.pid

# find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod -rw
# find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod +x
# find $JAIL/etc -gid 0 -uid 0 -type f -print | xargs chmod -x
# find $JAIL/usr/bin -type f -print | xargs chmod ug+rx
# find $JAIL/ -group http -user http -print | xargs chmod o-rwx
# chmod +rw $JAIL/tmp
# chmod +rw $JAIL/run

Если ваш сервер будет принимать входящие соединения на 80 порту (или любому другому порту в диапазоне [1-1023]), дайте исполняемому файлу внутри chroot права на использование этих портов без прав суперпользователя.

# setcap 'cap_net_bind_service=+ep' $JAIL/usr/bin/nginx

Отредактируйте nginx.service для запуска chroot

Сделайте замещение файла юнита nginx.service — тогда обновление nginx не изменит ваш файл .service.

Юнит systemd должен быть настроен так, чтобы запускать nginx в chroot от имени пользователя http и хранить pid-файл в chroot.

Примечание: Я не уверен, нужно ли хранить pid-файл в chroot.

/etc/systemd/system/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
After=syslog.target network.target

[Service]
Type=forking
PIDFile=/srv/http/run/nginx.pid
ExecStartPre=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -t -q -g 'pid /run/nginx.pid; daemon on; master_process on;'
ExecStart=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;'
ExecReload=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' -s reload
ExecStop=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid;' -s quit

[Install]
WantedBy=multi-user.target

Примечание: Обновление nginx с помощью pacman не обновит установленную в chroot копию. Вы должны вручную выполнять обновления, повторяя указанные выше шаги по переносу файлов. Не забудьте также обновить библиотеки, которые использует nginx.

Теперь вы можете спокойно удалить nginx, установленный вне chroot.

# pacman -Rsc nginx

Если вы не удалили nginx, установленный вне chroot, проверьте, что работающий процесс nginx — это действительно именно тот, что в находится chroot. Для этого посмотрите, куда указывает символическая ссылка /proc/PID/root: она должна указывать на /srv/http, а не на /.

# ps -C nginx | awk '{print $1}' | sed 1d | while read -r PID; do ls -l /proc/$PID/root; done

Советы и рекомендации

Запуск без привилегий через systemd

Создайте drop-in файл для службы nginx.service и пропишите в нём секцию [Service] с опцими User и (опционально) Group, чтобы запустить службу от имени указанного вами непривилегированного пользователя:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
User=пользователь
Group=группа

Также можно запретить повышение привилегий:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
...
NoNewPrivileges=yes

Совет: Подробнее о повышающих безопасность опциях можно почитать в systemd.exec(5).

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

Совет: Аналогичные настройки можно применить и для сервера FastCGI.

Порт

По умолчанию Linux запрещает не-root процессам слушать порты ниже 1024. Можно использовать порт выше 1024:

/etc/nginx/nginx.conf
server {
        listen 8080;
}

Совет: Если вы хотите, чтобы nginx всё равно был доступен на порту 80 или 443, можно настроить межсетевой экран для перенаправления запросов с порта 80 или 444 на порт, который использует nginx.

Или можно выдать процессу nginx привилегию CAP_NET_BIND_SERVICE, которая позволит ему использовать порты ниже 1024:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
...
CapabilityBoundingSet=
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=
AmbientCapabilities=CAP_NET_BIND_SERVICE

Или можно использовать активацию сокетов systemd. В этом случае systemd будет прослушивать порты и, когда будет установлено соединение, запустит nginx, передав сокет в качестве дескриптора файла. Это означает, что процессу nginx не нужны особые привилегии, так как сокет уже существует на момент запуска. Этот подход опирается на использование внутренней переменной окружения, которую nginx использует для передачи сокетов [2], и поэтому официально не поддерживается. Вместо установки CapabilityBoundingSet и AmbientCapabilities переопределите переменную окружения NGINX, чтобы сообщить процессу nginx, какие файловые дескрипторы будут передаваться сокетам:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
...
Environment=NGINX=3:4;

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

/etc/systemd/system/nginx.socket
[Socket]
ListenStream=0.0.0.0:80
ListenStream=0.0.0.0:443
After=network.target
Requires=network.target

[Install]
WantedBy=sockets.target

Сокеты будут передаваться в порядке, определённом в этом юните, поэтому порт 80 будет файловым дескриптором 3, а порт 443 — файловым дескриптором 4. Если вы ранее включали или запускали службу nginx.service, вам нужно остановить её и включить вместо неё nginx.socket. При запуске системы nginx не будет запущен, но запустится, когда вы зайдете на сайт в браузере. Благодаря этому можно дополнительно защитить службу; например, во многих случаях вы можете установить PrivateNetwork=True в файле службы, блокируя nginx от внешней сети, поскольку сокета, созданного systemd, достаточно для обслуживания веб-сайта. Обратите внимание, что при этом в журналы службы nginx будет выведено предупреждение: 2020/08/29 19:33:20 [notice] 254#254: using inherited sockets from "3:4;"

PID-файл

По умолчанию nginx использует /run/nginx.pid. Нужно будет создать каталог, в котором пользователь будет иметь право записи, и перенастроить запись PID-файла туда. Например, можно использовать systemd-tmpfiles:

/etc/tmpfiles.d/nginx.conf
d /run/nginx 0775 root группа - -

Примените изменения:

# systemd-tmpfiles --create

Отредактируйте параметры службы, связанные с PID-файлом:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
...
PIDFile=/run/nginx/nginx.pid
ExecStart=
ExecStart=/usr/bin/nginx -g 'pid /run/nginx/nginx.pid; error_log stderr;'
ExecReload=
ExecReload=/usr/bin/nginx -s reload -g 'pid /run/nginx/nginx.pid;'

/var/lib/nginx/*

Некоторые каталоги в каталоге /var/lib/nginx должны быть инициализированы путём запуска nginx от имени root. Для этого не обязательно запускать весь сервер, nginx сделает это при проверке конфигурации. Так что просто запустите её — и готово.

Права каталогов и файлов журналов

После запуска проверки конфигурации будет создан журнал, принадлежащий root. Удалите журналы в /var/log/nginx.

Пользователю, от имени которого будет работать служба, nginx нужно выдать разрешение на запись в /var/log/nginx. Для этого может понадобиться изменить права и/или владельца каталога.

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

В systemd есть встроенная возможность запуска через chroot. [3]. Для примера используем такие настройки пользователя, группы и pid:

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

Абсолютный путь к файлу настроек будет /srv/http/etc/nginx/nginx.conf.

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

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

[Install]
WantedBy=multi-user.target

Указывать стандартный путь к файлу настроек необязательно, nginx по умолчанию использует -c /etc/nginx/nginx.conf, но, возможно, явное прописывание является хорошей идеей.

Также можно запускать только ExecStart внутри chroot с параметром RootDirectoryStartOnly заданным как yes (смотрите systemd.service(5)) или запустить его до того, как точка монтирования станет эффективной или будет доступен путь systemd (смотрите systemd.path(5)).

/etc/systemd/system/nginx.path
[Unit]
Description=nginx (Chroot) path
[Path]
PathExists=/srv/http/site/Public_html
[Install]
WantedBy=default.target

Включите созданный юнит nginx.path и в юните nginx.service измените строку WantedBy=default.target на WantedBy=nginx.path.

Параметр PIDFile в файле юнита позволяет systemd следить за процессом (требуется абсолютный путь). Если это нежелательно, вы можете изменить тип на oneshot и удалить упоминание pid-файла из файла юнита.

Nginx beautifier

nginxbeautifierAUR — это инструмент командной строки, используемый для улучшения и форматирования конфигурационных файлов nginx.

Более удобное управление заголовками

Nginx имеет довольно неинтуитивную систему управления HTTP-заголовками: они могут быть определены только в одном контексте, любые другие заголовки игнорируются. Чтобы исправить это, можно установить модуль headers-more-nginx.

Установите пакет nginx-mod-headers-more. Модуль будет установлен в каталог /usr/lib/nginx/modules.

Чтобы загрузить модуль, добавьте следующее в начало основного конфигурационного файла nginx.

/etc/nginx/nginx.conf
load_module "/usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so";
...

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

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

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

Ошибка: Страница, которую вы ищете, временно недоступна. Пожалуйста, попробуйте позже. (502 Bad Gateway)

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

Попробуйте этот ответ, чтобы исправить 502 ошибку.

В Arch Linux, файлом настройки, упомянутом по ссылке выше, является /etc/php/php-fpm.conf.

Ошибка: No input file specified

1. Убедитесь, что переменная open_basedir в /etc/php/php.ini содержит путь, который соответствует аргументу root в nginx.conf (обычно /usr/share/nginx/). Если в качестве FastCGI-сервера используется PHP-FPM, можно попробовать добавить fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/"; в тот блок location, который используется для обработки php-файлов.

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

3. Проверьте права доступа: например, пользователь/группа http, биты разрешений 755 для каталогов и 644 для файлов. Имейте в виду, что все родительские каталоги тоже должны иметь корректные права доступа. Как массово изменить права всего дерева каталогов, описано в разделе Разрешения и атрибуты файлов#Массовое изменение разрешений.

4. Возможно, у вас не установлена переменная SCRIPT_FILENAME, содержащая полный путь до ваших скриптов. Если конфигурация nginx (fastcgi_param SCRIPT_FILENAME) правильная, то эта ошибка означает, что 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

5. Если вы используете chroot, убедитесь, что опция chroot в файле /etc/php-fpm/php-fpm.d/www.conf имеет корректное значение.

Warning: Could not build optimal types_hash

Если при запуске nginx.service в журнале появляется такое сообщение:

[warn] 18872#18872: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size

то попробуйте увеличить значения этих параметров в блоке http [4] [5]:

/etc/nginx/nginx.conf
http {
    types_hash_max_size 4096;
    server_names_hash_bucket_size 128;
    ...
}

Cannot assign requested address

Полный текст ошибки в статусе юнита nginx.service:

[emerg] 460#460: bind() to A.B.C.D:443 failed (99: Cannot assign requested address)

Даже если файл юнита nginx настроен на запуск после network.target с помощью systemd, nginx может попытаться прослушивать адрес, который настроен, но ещё не добавлен ни к одному интерфейсу. Убедиться, что проблема именно в этом, можно, попытавшись запустить nginx вручную (тем самым показав, что IP-адрес настроен правильно). Настройка nginx на прослушивание всех адресов решит эту проблему. Если же в вашем случае обязательно требуется прослушивание конкретного адреса, одним из возможных решений является перенастройка systemd.

Чтобы запустить nginx только после того, как все настроенные сетевые устройства будут запущены и получат IP-адреса, добавьте network-online.target к строке After= в файле nginx.service и запустите/включите systemd-networkd-wait-online.service.

Смотрите также

  • Использование WebDAV с nginx
  • nginx configuration pitfalls
  • Very good in-depth 2014 look at nginx security and Reverse Proxying
  • Installing LEMP (nginx, PHP, MySQL with MariaDB engine and PhpMyAdmin) in Arch Linux
  • Certbot (Русский)#Nginx

Понравилась статья? Поделить с друзьями:
  • Эклипс лекарство цена инструкция по применению
  • Терафлекс инструкция по применению капсулы взрослым цена отзывы
  • Куриная фазенда инструкция на русском языке к китайскому инкубатору
  • Руководство по эксплуатации паз 32053 70 школьный автобус
  • Молочная продукция для руководства