[Хд] logo

Правильная конфигурация Nginx

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

Root внутри секции location

Нет ничего плохого в размещении root-директории внутри location. Но если location не соответствует, то у нее не будет доступа к корневому каталогу. Правильнее делать так:

server {
    server_name www.somesite.com;
    root /var/www/nginx-default/;
    location / {
        # [...]
    }
    location /foo {
        # [...]
    }
    location /bar {
        # [...]
    }
}

# Указание root внутри секции server

Несколько директив index

Не нужно плодить большое количество директив index. Пропишите ее один раз в блоке http:

http {
    index index.php index.htm index.html;
    server {
        server_name www.somesite.com;
        location / {
            # [...]
        }
    }
    server {
        server_name somesite.com;
        location / {
            # [...]
        }
        location /foo {
            # [...]
        }
    }
}

# Index будет автоматически наследоваться в всех секциях

Использование if

Вы же в курсе, что if = зло? При использовании директивы нужно быть осторожным, ошибиться несложно. Так что по возможности избегайте использования if.

Имя сервера

Предположим, ваш сайт лежит на домене somesite.com и вы перенаправляете на него пользователей, которые идут на www.somesite.com:

server {
    server_name somesite.com *.somesite.com;
        if ($host ~* ^www\.(.+)) {
            set $raw_domain $1;
            rewrite ^/(.*)$ $raw_domain/$1 permanent;
        }
        # [...]
    }
}

# Проверяет и перенаправляет хост

Здесь несколько проблем. Главная — if. Вне зависимости от запроса хоста (с www или без), Nginx все равно проверяет if. Для каждого запроса. Взамен можно сделать так:

server {
    server_name www.somesite.com;
    return 301 $scheme://somesite.com$request_uri;
}
server {
    server_name somesite.com;
    # [...]
}

# Используется $scheme, которая подходит для http и https

Проверка наличия файла

Не используйте if для проверки наличия файла:

server {
    root /var/www/somesite.com;
    location / {
        if (!-f $request_filename) {
            break;
        }
    }
}

# Подход как минимум не эффективен

Взамен у Nginx есть директива try_files:

server {
    root /var/www/somesite.com;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

# Проверка последовательности на наличие файла, если не существует, то отправляет на index.html

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

Передача запросов на PHP

Если Nginx перенаправляет все запросы, заканчивающиеся на .php, напрямую на интерпретатор PHP, то для злоумышленников открываются возможности для выполнения стороннего кода. PHP по умолчанию пытается догадаться, куда должен вести неправильный запрос. Так что в первую очередь необходимо подправить php.ini, указав:

cgi.fix_pathinfo=0

# Интерпретатор будет обрабатывать только корректные запросы

Обратите внимание на правильную конфигурацию Nginx:

 # Перенаправляет запросы только для указанных файлов
location ~* (file_a|file_b|file_c)\.php$ {
    fastcgi_pass backend;
    # [...]
}

 # Отключить выполнение скриптов в пользовательских загрузках
location /uploaddir {
    location ~ \.php$ {return 403;}
    # [...]
}

 # Фильтрация при помощи try_files
location ~* \.php$ {
    try_files $uri =404;
    fastcgi_pass backend;
    # [...]
}

 # Использует вложенное расположение для фильтрации
location ~* \.php$ {
    location ~ \..*/.*\.php$ {return 404;}
    fastcgi_pass backend;
    # [...]
}

# Параметры можно комбинировать

Путь FastCGI

Неправильное указание путей размещения скриптов FastCGI часть приводит к ошибке "Primary script unknown", которая легко решается.

Перезапись (rewrite)

Используйте переменную $request_uri для изменения URI запроса:

rewrite ^ http://somesite.com$request_uri? permanent;

# Или так
return 301 http://somesite.com$request_uri;

# Перенаправляет на страницу 301

Отсутствующий http://

Добавить отсутствующий http:// очень просто:

rewrite ^ http://somesite.com permanent;

# Автоматически дополняет запрос

Проксирование

Не перенаправляйте все запросы на PHP в таком виде:

server {
    server_name _;
    root /var/www/site;
    location / {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

# Передает все на phpcgi.socket

Используйте все те же директиву try_files:

server {
    server_name _;
    root /var/www/site;
    location / {
        try_files $uri $uri/ @proxy;
    }
    location @proxy {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

# Передает только нужные запросы на proxy

Или так:

server {
    server_name _;
    root /var/www/site;
    location / {
        try_files $uri $uri/ /index.php;
    }
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

# Если Nginx не может обработать запрашиваемый URI самостоятельно, то проверяет директории на наличие, затем передает на proxy

Самое главное

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

  read in english
[Хд]

Подписывайтесь на отборные материалы по продвинутой разработке

Google Email

Esc, чтобы подписаться позже