Решил собирать на этой странице всяческие полезные настройки, с которыми пришлось повозиться.
Но, прежде чем приступить, хочу Вам предложить освежить знания о том, как nginx обрабатывает запрос:
Синтаксис:
location [ = | ~ | ~* | ^~ ] uri { ... }
location { } @ name { ... }
= | полное строковые совпадение, например = / исключительно для корня, и даже файлы в корне уже сюда не подходят (приоритет максимальный) |
^~ | требуется совпадение только начала строки, например ^~ /img/ считается не регулярным выражением (приоритет высокий) |
~* | регулярное выражение без учета регистра (приоритет средний) |
~ | регулярное выражение с учетом регистра (приоритет ниже среднего) |
не указан | например "location / {" или "location /data/ {" (приоритет минимальный), при этом если у вас написано сразу два данных правила, то нет уверенности в том, что отработает вначале (/ или /data/) |
Примеры специально расположенные в обратном порядке приоритетов:
# Данная конфигурация сопоставляется с любым запросом, в котором есть /data/ например /foo/data/bar
location /data/ {
return 200 "data on $uri";
}
# Совпадает с любым запросом, начинающимся с /, однако после всех регулярных выражений.
location / {
return 200 "root is $document_root on $uri";
}
# Соответствует запросам /api и /api/ но если файл doc.txt не найден, то nginx сделает
# внутренний запрос словно клиент запросил /info.gif (см. ниже регулярку с gif)
location ~ ^/api(|/)$ {
try_files /doc.txt /info.gif;
}
# Совпадает с любым запросом, начинающимся с /img/ и затем поиск прекращается,
# в этом примере нет регулярных выражений.
location ^~ /img/ {
try_files $uri =404;
}
# Совпадает с любым запросом заканчивающимся на png, ico, gif, jpgили jpeg. Однако, все
# запросы /img/ будут обработаны в предыдущем location
location ~* \.(png|ico|gif|jpg|jpeg)$ {
try_files $uri =404;
}
# Если совпадает точно с запросом /
location = / {
index README.md;
}
# Произойдет поиск файла /my.js и если его нет, заново начнется поиск, словно клиент запросил файл /my.php
location = /my.js {
try_files $uri /my.php$is_args$args;
}
Как проверить существование файла в директории и если файла нет - выдать 404
location ^~ /dir/ {
try_files $uri =404;
}
Как проверить существование файла в директории и если файла нет - показать файл по умолчанию
location ^~ /dir/ {
try_files $uri /images/default.gif;
}
*выше описанные способы можно совместить:
location ^~ /dir/ {
try_files $uri /images/default.gif =404;
}
Проксируем запросы на site.ru
location ^~ /img/ {
resolver 8.8.8.8;
proxy_pass http://site.ru$uri;
# если site.ru ответит кодом ответа > 300, то что делать с таким ответом решит директива error_page
proxy_intercept_errors on;
# например: при 400 показать 200 https://nginx.org/ru/docs/http/ngx_http_core_module.html#error_page
error_page 404 =200 /empty.gif;
}
или без dns-resolver:
location ^~ /img/ {
proxy_pass http://1.9.107.167:80;
proxy_redirect http://1.9.107.167:80/ /;
proxy_set_header Host $host;
}
Проксируем запросы на site.ru
location ^~ /outer/office/users/ {
proxy_pass http://site.ru:80;
# подменяем заголовок 'Location' словно ответил текущий сайт (а не site.ru)
proxy_redirect default;
}
Проксируем yapro.ru/backend/page
-> http://127.0.0.1:80/page
(обрезая начало URL /backend/
):
location ^~ /backend/ {
# если не указать, то в $_SERVER['HTTP_HOST'] будет содержаться 'yapro.backend:8888'
proxy_set_header Host yapro.backend;
# т.к. в конце указал слэш, то запрос на yapro.front/backend/page будет перенаправлен на yapro.backend/page
proxy_pass http://127.0.0.1:80/;
}
Проксируем yapro.ru/backend/page
-> http://
yapro.backend/backend/page
:
location ^~ /backend/ {
proxy_set_header Host yapro.backend;
proxy_pass http://127.0.0.1:80/backend/;
}
Проксируем yapro.ru/article/page
-> http://yapro.backend/backend/article/page
:
location ^~ /article/ {
proxy_set_header Host yapro.backend;
proxy_pass http://127.0.0.1:80/backend/article/;
}
Проксируем запрос на yapro.ru/v1/chat/completions
-> https://api.openai.com/v1/chat/completions
location = /v1/chat/completions {
proxy_pass https://api.openai.com;
proxy_pass_request_headers on;
proxy_ssl_name api.openai.com;
proxy_ssl_server_name on;
}
Проверяем существование файла в директории, а и если файла нет - ищем на другом сайте, и если там нет - выдаем 404
location ^~ /dir/ {
try_files $uri @static_svr1;
}
location @static_svr1 {
resolver 8.8.8.8;
proxy_pass http://site.ru$uri;
}
Как подгружать файлы определенной директории с директории другого проекта
location ^~ /dir/ {
root /var/www/yandex.ru/;
}
* переопределять root параметр является единственным верным и рабочим способом и никакие try_file не помогут (и не нужны).
Как использовать динамичный роутинг с ограничением (например по расширению файла)
location ~* ^/mobile/(.+)\.(ettf|svg) {
try_files /$1.$2 @rewrite;
}
Как вернуть код 500 с содержимым
location /500.html {
return 500 "Whoa! Internal Server Error";
}
Как обработать GET-переменные
location = /my/page.html {
if ($query_string = "id=15&category=8") {
return 403;
}
}
Как изменить количество секунд, которое будет ждать Nginx от PHP-fpm
location ^~ /my/page {
fastcgi_read_timeout 55s;
include php-fpm.conf;
}
server {
listen 80;
server_name www.yapro.ru yapro.ru;
return 301 https://yapro.ru$request_uri;
}
server {
listen 443 ssl http2;
server_name yapro.ru;
# . . . SSL files paths and other code
return 301 https://yapro.ru$request_uri;
}
server {
listen 443 ssl http2;
server_name yapro.ru;
# . . . SSL files paths and other code
}
server {
server_name www.yapro.ru;
rewrite ^(.*) http://yapro.ru$1 permanent;
}
Дебагинг
Чтобы убедиться, что поддержка отладки сконфигурирована, необходимо в консоле выполнить команду:
nginx -V | grep "--with-debug"
если результат есть, значит nginx скомпилен с возможностью отладки и теперь для error-лога можно просто указать примечание debug:
server {
error_log /var/log/nginx/site.ru.error debug;
}
Anti-hotlinking – защита файлов вашего сайта от прямого доступа с других сайтов или сервисов. По этому вопросу у меня отдельная статья »
Не проверялось: Autoindex
Autoindex — это функция, которая включает листинг директорий по http, средствами веб-сервера (конечно, если в директории нет настоящего index-файла).
location /testing {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
Не проверялось: как проксировать на нужный сервер, используя переменные из Cookies
Ситуация: приложение кладет в куку JSESSIONID значение k3t2, где 3 это номер сервера, 2 это порт 8020. Следовательно необходимо заворачивать клиентов по этим данным.
if ( $cookie_JSESSIONID ~ k(\d)t(\d)$ ) {
set $i $1;
set $p $2;
proxy_pass "http://10.0.0.${i}:80${p}0";
}
*есть мнение, что в proxy_pass надо задавать url полностью. Т.е. нужно записать все в переменную и только потом proxy_pass http://$my_var
Не проверялось: под-директории и фронт-контроллеры в них
location /nested {
alias /var/www/nested/public;
try_files $uri $uri/ @nested;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
}
location @nested {
rewrite /nested/(.*)$ /nested/index.php?/$1 last;
}
Однако вот пример работы вложенного location-a (проверено - работает).
Не проверялось: перенаправляем udp в http
server {
listen 80 udp;
proxy_pass http://elasticsearch:9200;
}
или так
listen 80 udp;
location ^~ / {
proxy_pass http://elasticsearch:9200;
}
или так
listen 80 udp;
location ^~ / {
# proxy_bind $remote_addr transparent;
# proxy_bind 1.0.0.0;
proxy_pass http://2.0.0.0:2555;
}
server {
listen 80 default;
root /var/www/public;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location ~ ^/fpm_(status|ping)$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass localhost:9000;
}
location ^~ /my/api {
fastcgi_pass localhost:9000;
# GLOBAL-переменные, будут доступны в PHP https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass localhost:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
Nginx имеет возможность декодировать URI, в реальном времени. Например, для того, чтобы найти соответствия “/app/%20/images” вы можете использовать “/app/ /images” для определения местоположения.
Для понимания ситуации, я использую nginx переменные:
Таким образом: $time_local - $request_time = дата времени начала запроса.
nginx.conf:
http {
log_format my_format '"$time_local - $request_time"';
access_log /var/log/nginx/access.log my_format;
server {
access_log /var/log/nginx/access.log my_format;
}
}
Для этого в nginx есть (встроенный в бесплатную версию) модуль limit_req_zone, правда который показал себя странно при тестировании (или я его неправильно настроил). Я специально задрал значения в nginx-конфиге, сделал нагрузочный тест, но limit_req_zone отбросил тебе запросы, которые не должен был:
http {
limit_req_zone $request_uri zone=by_uri:10m rate=2000r/s;
server {
location / {
limit_req zone=by_uri burst=5 nodelay;
Планирую этот модуль подвергнуть дальнейшему исследованию.
Официальный CORS-конфиг у меня работает, только если во все три места добавить:
add_header "Access-Control-Allow-Origin" $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
плюс указав нужные HTTP-методы, например PUT:
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT';
Но как Вы заметили, в официальном конфиге используются if-ы, но if-ы это зло, и я решил в этом убедиться, написав:
set $baseCorsHeaders 0;
set $additionalCorsHeaders 0;
if ($request_method = 'OPTIONS') {
set $baseCorsHeaders 1;
}
if ($request_method = 'GET') {
set $baseCorsHeaders 1;
set $additionalCorsHeaders 1;
}
if ($request_method = 'POST') {
set $baseCorsHeaders 1;
set $additionalCorsHeaders 1;
}
if ($baseCorsHeaders = 1) {
add_header 'Access-Control-Allow-Origin' $http_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Allow-Credentials' 'true';
}
# Wide-open CORS config for nginx - https://enable-cors.org/server_nginx.html
if ($request_method = 'OPTIONS') {
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Allow-Credentials' 'true';
return 204;
}
if ($additionalCorsHeaders) {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
Как Вы наверное поняли, я убедился, что if-ы это зло (в примере выше отрабатывает только последний if).
CORS-вывод: nginx не очень удобный инструмент для написания конфигов с if-ами, к тому же если вы все же написали if, то конфиг может неожиданно переставать работать или работать неожиданно (что еще хуже).
Для этого в файле nginx.conf добавляем параметр server_tokens off;
server_tokens off;
server {
listen 80;
server_name site.com;
Debian-путь: /etc/nginx/nginx.conf
FreeBSD-путь: /usr/local/etc/nginx/nginx.conf
После этого нужно перезапустить nginx.
Надеюсь Вам пригодятся данные настройки, удачки!
api.openai.com
(не проверено)server {
listen 80;
server_name openai-api.xxx.link;
error_log /var/log/nginx/openai-api/nginx-error.log;
access_log /var/log/nginx/openai-api/nginx-access.log main;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name openai-api.xxx.link;
error_log /var/log/nginx/openai-api/nginx-error-ssl.log;
access_log /var/log/nginx/openai-api/nginx-access-ssl.log main;
ssl_certificate /data/acme.sh/xxx.link/fullchain.cer;
ssl_certificate_key /data/acme.sh/xxx.link/bi83.link.key;
include /etc/nginx/ssl/options-ssl-nginx.conf;
ssl_dhparam /etc/nginx/ssl/ssl-dhparam.pem;
ignore_invalid_headers off;
client_max_body_size 0;
proxy_buffering off;
location /v1/audio/speech {
proxy_pass https://api.openai.com/v1/audio/speech;
proxy_ssl_name api.openai.com;
proxy_ssl_server_name on;
# Forward all headers
proxy_pass_request_headers on;
# proxy_http_version 1.1;
}
}
Следующий код:
map $arg_one $var_two {
"one" "two";
}
означает:
if ($arg_one = "one") {
set $var_two "two";
}
Можно даже писать сразу несколько условий:
map $arg_one $var_two {
"one" "two";
"three" "four";
}
что будет означать:
if ($arg_one = "one") {
set $var_two "two";
}
if ($arg_one = "three") {
set $var_two "four";
}
А если переменная не совпала ни с одним значением, то можно указать значение по-умолчанию:
map $arg_one $var_two {
"one" "two";
"three" "four";
default "five";
}
Балансировщик | Веб-сервис |
|
|
Нужно поправить:
Что отличается и это правильно:
Источники: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15