nginx (Русский)
nginx (произносится "э́нжин-э́кс" или "э́нжин-и́кс") — это свободный высокопроизводительный HTTP-сервер с открытым исходным кодом, а также обратный прокси и IMAP/POP3 прокси-сервер, написанный Игорем Сысоевым в 2005 году. nginx получил широкое распространение благодаря своей стабильности, богатой функциональности, простой настройке и низкому потреблению ресурсов.
Данная статья описывает установку nginx и интеграцию с PHP через #FastCGI.
Установка
Установите один из пакетов:
- nginx-mainline - основная ветка: новые возможности, обновления и исправления ошибок.
- nginx - стабильная ветка; только исправления серьёзных ошибок.
- angieAUR - форк, предполагает подмену nginx на месте без переработки конфигурации с расширением возможностей.
Рекомендуется использовать основную (mainline) ветку. Основная причина для использования стабильной ветки — возможная несовместимость со сторонними модулями или непреднамеренное появление ошибок при реализации новых функций.
Если для обеспечения дополнительной безопасности вы хотите установить nginx в chroot-окружении, смотрите раздел #Установка в chroot.
Запуск
Запустите/включите службу nginx.service
или angie.service
, если вы используете Angie.
Страница по умолчанию, доступная по адресу http://127.0.0.1 располагается в /usr/share/nginx/html/index.html
.
Настройка
Первые шаги по настройке и использованию nginx описаны в официальном руководстве для начинающих. Вы можете настроить сервер, редактируя файлы в /etc/nginx/
; главный файл настроек расположен в /etc/nginx/nginx.conf
.
Более подробную информацию можно прочитать на странице Nginx Configuration Examples[устаревшая ссылка 2024-07-30 ⓘ] и в официальной документации.
Приведенные далее примеры покрывают большинство типичных потребностей. Предполагается, что вы используете стандартное место расположения веб-документов (/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 пользователь [группа];
Если группа не указана, будет использоваться группа, совпадающая с указанным именем пользователя.
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
, чтобы изменения вступили в силу.
Управление блоками 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
Если же вам нужно создать 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
.
Если вы продолжаете получать ошибку 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-devls -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.
/etc/systemd/system/nginx.service
[Unit] Description=A high performance web server and a reverse proxy server After=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, установленный вне 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
После этого нужно убедиться, что пользователь
имеет доступ ко всем необходимым ресурсам. Следуйте инструкциям, описанным в следующих разделах, и затем запустите nginx.
Порт
По умолчанию Linux запрещает не-root процессам слушать порты ниже 1024. Можно использовать порт выше 1024:
/etc/nginx/nginx.conf
server { listen 8080; }
Или можно выдать процессу 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=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
.