summaryrefslogtreecommitdiff
path: root/LINUX/NGINX.md
diff options
context:
space:
mode:
Diffstat (limited to 'LINUX/NGINX.md')
-rw-r--r--LINUX/NGINX.md538
1 files changed, 538 insertions, 0 deletions
diff --git a/LINUX/NGINX.md b/LINUX/NGINX.md
new file mode 100644
index 0000000..21e9380
--- /dev/null
+++ b/LINUX/NGINX.md
@@ -0,0 +1,538 @@
+## Настройка перенаправлений
+
+Настройки необходимо вносить в файлах конфигураций виртуальных доменов. В [Linux](https://www.dmosk.ru/terminus.php?object=linux) на основе RPM (CentOS, Red Hat), как правило, они расположены в директории /etc/nginx/conf.d/. В Linux на основе Deb (Ubuntu, Debian) — в директории /etc/nginx/sites-enabled/. Во [FreeBSD](https://www.dmosk.ru/terminus.php?object=freebsd) все в одном файле — /usr/local/etc/nginx/nginx.conf.
+
+Саму настройку на перенаправление в NGINX можно прописать несколькими способами.
+
+1. Первый:
+
+rewrite ^ https://$host$request_uri? <флаг>;
+
+_* **$host** — имя хоста из запроса, если отсутствует — имя в поле «Host» заголовка, если тоже отсутствует — имя сервера; **$request_uri** — первоначальный запрос с аргументами (все, что идет после доменного имени).
+** где флаги могут быть следующие:_
+
+- _permanent — перенаправление с кодом 301._
+- _redirect — перенаправить с кодом 302._
+- _last — закончить обработку с переходом в новый location._
+- _break — закончить обработку и остаться в текущем location._
+
+2. Второй: 
+
+return <код> https://$host$request_uri;
+
+_* где коды могут использоваться любые, но чаще всего — 301, 302, 404._
+
+Есть различные мнения, какой из методов лучше и безопаснее, поэтому каким воспользоваться — решать по ситуации. В данных примерах используются оба варианта.
+
+После внесения изменений, необходимо проверить их корректность:
+
+nginx -t
+
+И для их применения перезапустить веб-сервер:
+
+systemctl restart nginx
+
+service nginx restart
+
+_* в первом примере перезапуск выполняется на новых системах Linux. Второй пример — на устаревших или FreeBSD._
+
+Проверяя редиректы в [браузере](https://www.dmosk.ru/terminus.php?object=brouser), следует учесть, что настройки могут [кэшироваться](https://www.dmosk.ru/terminus.php?object=cache). Для обновления кэша используйте комбинацию Ctrl + F5. Если и это не помогает, закрывайте вкладку и открывайте новую.
+
+## С HTTP на HTTPS (другой порт)
+
+Пример конфигурации для перенаправления запросов на другой порт — с 80 (http) на 443 (https):
+
+server {
+    listen 80;
+    server_name domain.ru www.domain.ru;
+    return 301 https://$host$request_uri;
+}
+
+_* в данном примере для всех обращений к сайту domain.ru по 80 порту ([http](https://www.dmosk.ru/terminus.php?object=http)) будет работать редирект на 443 порт ([https](https://www.dmosk.ru/terminus.php?object=https)) с кодом 301 (для склеивания [доменов](https://www.dmosk.ru/terminus.php?object=domain))._
+
+Также мы можем добавить условие, чтобы не перенаправлять на https для определенных ссылок, например:
+
+server {
+    listen 80;
+    server_name domain.ru www.domain.ru;
+    if ($uri !~ /page.html){
+        return 301 https://$host$request_uri;
+    }
+}
+
+_* в данном примере запрос на страницу **/page.html** будет открыт по http._
+
+Есть еще способ настройки директивы **server** сразу для http и https. При этом, если зайти по 80 порты, нас перекинет на 443:
+
+server {
+    listen       80;
+    listen       443 ssl;
+    server_name  domain.ru www.domain.ru;
+
+    if ($scheme = 'http') {
+        return 301 https://$host$request_uri;
+    }
+
+    ssl_certificate     /etc/nginx/ssl/cert.pem;
+    ssl_certificate_key /etc/nginx/ssl/cert.key;
+
+    ...
+}
+
+_* данный способ удобен, чтобы не создавать несколько секций server со своими настройками._
+
+## С одного домена на другой
+
+server {
+        ...
+        server_name domain1.ru;
+        return 302 http://domain2.ru$request_uri;
+}
+
+## C домена без www на домен с www
+
+server {
+        ...
+        server_name domain.ru;
+        return 301 http://www.$host$request_uri;
+}
+
+## С www на без www
+
+Конкретный домен:
+
+server {
+        ...
+        server_name www.domain.ru;
+        return 301 $scheme://domain.ru$request_uri;
+}
+
+Все домены, которые обслуживает nginx:
+
+server {
+        ...
+        server_name "~^www\.(.*)$";
+        return 301 $scheme://$1$request_uri;
+}
+
+Или с использованием if:
+
+server {
+        ...
+        if ($host ~ "^www\.(.*)$") {
+                return 301 $scheme://$1$request_uri;
+        }
+        ...
+}
+
+## C index.php на / (корень)
+
+Данная настройка позволит перевести все запросы с /index.php на корневой адрес /:
+
+server {
+        ...
+        if ($request_uri ~ "^(.*)index\.(?:php|html)") {
+                return 301 $1;
+        }
+}
+
+## Перенаправление запросов для отсутствующих доменов (перенаправление по умолчанию)
+
+Если обращение к веб-серверу идет по [IP-адресу](https://www.dmosk.ru/terminus.php?object=ipaddr) или домену, который не прописан в конфигурационном файле, можно перенаправить весь трафик на домен по умолчанию:
+
+server {
+        listen 80 default_server;
+        return 302 https://welcome.domain.ru$request_uri;
+}
+
+или независимо от протокола:
+
+server {
+        listen 80 default_server;
+        return 302 $scheme://welcome.domain.ru$request_uri;
+}
+
+server {
+        listen 443 ssl default_server;
+        return 302 $scheme://welcome.domain.ru$request_uri;
+
+        ssl_certificate /etc/nginx/ssl/cert.pem;
+        ssl_certificate_key /etc/nginx/ssl/cert.key;
+}
+
+_* **$scheme** позволяет перевести запрос на тот же протокол (http или https), по которому он был инициирован.
+* если nginx должен слушать и обрабатывать запросы по https, необходимо указывать в настройках пути к сертификатам._
+
+## С IP-адреса на домен
+
+В данном случае мы переводим все запросы по IP-адресу на конкретный домен:
+
+server {
+        listen 80;
+        server_name 192.168.1.15;
+        return 301 http://site.ru$request_uri;
+}
+
+_* при отправке http-запроса на сервер **192.168.1.15** по IP-адресу, он будет переведен на домен **site.ru**._
+
+## Редирект домена и всех его поддоменов
+
+server {
+        ...
+        server_name  domain domain.*;
+        return 301 https://$host$request_uri;
+}
+
+## На другой файл
+
+Это скорее не перенаправление, а алиас или rewrite. Позволяет по запросу одного из файлов, отдать другой:
+
+server {
+        ...
+        location = /robots.txt {
+            rewrite ^/robots.txt$ /robots2.txt;
+        }
+}
+
+_* в данном примере по запросу **robots.txt**, сервер отдаст содержимое **robots2.txt**._
+
+## Часть url на другой сервер
+
+Перенаправить запрос на другой сервер при обращении по url page1:
+
+server {
+        ...
+        server_name  domain1.ru;
+        location  ~ ^/page1/(.*)$ {
+            return 301 $scheme://domain2.ru/$1;
+        }
+}
+
+_* в данном примере для всех запросов, начинающихся на **/page1/...** будет работать перенаправление на другой домен **domain2.ru**._
+
+## Редирект со слешем
+
+**1. Убрать слеш в конце url**
+
+server {
+    ...
+    if (!-f $request_filename ) {
+        rewrite ^/(.*)/$ /$1 permanent;
+    }
+}
+
+**2. Добавить слеш в конце url**
+
+server {
+    ...
+    if (!-f $request_filename ) {
+        rewrite ^(.*[^/])$ $1/ permanent;
+    }
+}
+
+## Удаляем расширение
+
+Для перенаправления запроса, где в URL есть полное название файла скрипта (с расширением) используем конфигурацию:
+
+server {
+    ...
+    if ($request_uri ~ "^(.*)\.(?:php|html)") {
+        return 301 $1;
+    }
+}
+
+_* в данном случае все запросы, которые заканчиваются на **.php** или **.html**, будут перенаправляться на страницы без данных расширений._
+
+Для примера, запрос http://site-example.ru/page.php будет переведен на http://site-example.ru/page.
+
+## На другую страницу
+
+Нам может понадобиться перенаправлять запросы с одной страницы сайта на другую. Приведем примеры, как это сделать с помощью return и rewrite.
+
+а) с помощью rewrite:
+
+server {
+        ...
+        rewrite ^/page1$ /page2 permanent;
+}
+
+б) с помощью return:
+
+server {
+        ...
+        location = /page1 {
+            return 301 /page2;
+        }
+}
+
+## Удалить часть URL
+
+Иногда нужно удалять часть url. Это можно сделать следующими способами:
+
+server {
+        ...
+        rewrite /deleted-url/(.*) /$1 permanent;
+}
+
+или:
+
+server {
+        ...
+        if ($request_uri ~ "/deleted-url/(.*)") {
+                return 301 $1;
+        }
+}
+
+_* в данном примере из url мы удалим **deleted-url/**._
+
+## Перенаправить запрос в случае обращения к несуществующим файлам
+
+Предположим, что нам нужно обращаться к скриптам на сервере, но без прописывания в URL .php на конце. Запрос будет выглядеть, примерно, http://url/. Чтобы nginx перекинул запрос на url.php вставляем следующее:
+
+server {
+    ...
+    location / {
+       root /var/www;
+       try_files $uri $uri/ $uri.php $uri.html /404.php =404;
+    }
+}
+
+_* в данном примере мы проверим наличие скрипта по пути **$uri**, затем **$uri/**. И уже после мы добавим к запросу **.php** и **.html**. Если ни одного скрипта не будет найдено, запрос будет перенаправлен на страницу **404.php**, которая вернет код 404._
+
+Также можно решить задачу с помощью **if** и **rewrite**:
+
+server {
+        ...
+        if (!-e $request_filename){
+                rewrite ^(.*)$ /$1.php;
+        }
+}
+
+_* в данном примере мы проверяем наличие файла, к которому идет обращение. И если его нет, то происходит замена адреса на такое же имя файла с .php на конце._
+
+## Перевод запросов, если файла не существует
+
+Данное действие не является редиректом, но близко по смыслу — NGINX проверяет наличие файла скрипта, к которому идет обращение, и если его нет, переводит запрос на другой файл. Как правило, это используется для того, чтобы перевести все обращения на файл index.php.
+
+server {
+    ...
+    location / {
+        try_files $uri $uri/ /index.php?$query_string;
+    }
+    ...
+}
+
+_* в данном примере мы скажем веб-серверу сначала проверить наличие скрипта по пути **$uri**, затем **$uri/** и если ответ будет 404, запросы будут обрабатываться с помощью файла **index.php** в корневой директории._
+
+## Проксирование
+
+Проксирование, в отличие от редиректа, не передает инструкции браузеру перейти на другой url — NGINX сам выполняет http-запрос по другому адресу и возвращает готовый ответ. Эта возможность может применяться для внутреннего распределения серверных ресурсов.
+
+Хоть это и не совсем редирект, рассмотрим примеры его настройки, так как очень часто нужно не перенаправление, а, как раз, обратное проксирование.
+
+### 1. На другой сервер
+
+Пример внутреннего перенаправления http-запроса на другой веб-сервер:
+
+location / {
+        proxy_pass          http://192.168.0.15:8080/;
+        proxy_redirect      off;
+        proxy_http_version  1.1;
+
+        proxy_set_header  Host               $host;
+        proxy_set_header  Upgrade            $http_upgrade;
+        proxy_set_header  Connection         "upgrade";
+        proxy_set_header  X-Real-IP          $remote_addr;
+        proxy_set_header  X-Forwarded-For    $proxy_add_x_forwarded_for;
+        proxy_set_header  X-Forwarded-Proto  http;
+}
+
+* в данном случае, принимать запросы от браузера и отвечать на них будет NGINX, а сама обработка будет выполняться на сервере с IP-адресом 192.168.0.15 на порту 8080. Рассмотрим все директивы:
+
+- **proxy_pass —** схема, узел и порт. По сути, это как и куда будет перенаправлен запрос.
+- **proxy_redirect —** позволяет отловить редиректы или определенные адреса и заменить их на другие. Пример работы с данной директивой [описан ниже](https://www.dmosk.ru/miniinstruktions.php?mini=nginx-redirects#proxypass-redirects).
+- **proxy_http_version —** задает версию протокола http. По умолчанию имеет значение 1.0.
+- **proxy_set_header —** добавляет http-заголовки:
+ - **Host —** сообщяет принимающей стороне, какой виртуальный хост использовать. Важный заголовок, если данная принимающая сторона обслуживает разные домены и требуется точная передача имени.
+ - **Upgrade —** действует только для http версии 1.1. Позволяет обновить протокол или его версию для уже созданного соединения. Например, с HTTP 1.1 до HTTP 2.0 или в WebSocket.
+ - **Connection —** определяет, останется ли сетевое соединение открытым после завершения текущей транзакции.
+ - **X-Real-IP —** позволяет передать принимающей стороне реальный IP-адрес посетителя. В противном случае, принимающая сторона получить адрес самого nginx.
+ - **X-Forwarded-For —** второй заголовок, с помощью которого передается реальный IP-адрес посетителя.
+ - **X-Forwarded-Proto —** определяет протокол, по которому клиент подключился к nginx. По возможности, стоит использовать https, но все зависит от принимающей стороны — она может отказаться принимать https или наоборот, требовать только его.
+
+Использование NGINX в качестве http-прокси:
+
+server {
+        ...
+        server_name site1.ru www.site1.ru;
+        location / {
+            proxy_pass http://192.168.1.21/;
+            proxy_redirect     off;
+            proxy_set_header   Host             $host;
+            proxy_set_header   X-Real-IP        $remote_addr;
+            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
+        }
+}
+
+server {
+        ...
+        server_name site2.ru www.site2.ru;
+        location / {
+            proxy_pass http://192.168.1.22/;
+            proxy_redirect     off;
+            proxy_set_header   Host             $host;
+            proxy_set_header   X-Real-IP        $remote_addr;
+            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
+        }
+}
+
+_* в данном примере запросы на **site1.ru** будут перекинуты на сервер **192.168.1.21**, а запросы на **site2.ru** — **192.168.1.22**._
+
+HTTP proxy с авторизацией (если удаленный веб-сервер требует аутентификации):
+
+server {
+    ...
+    location / {
+        proxy_pass http://10.10.10.10/page/;
+        proxy_set_header Authorization "Basic dGVzdDp0ZXN0";
+        ...
+    }
+}
+
+_* где **10.10.10.10/page** — страница, на которую будут перекинуты запросы; **dGVzdDp0ZXN0** — логин:пароль test:test, закодированные в формате base64._
+
+### 2. Часть url на другой сервер
+
+Выше мы рассмотрели пример перенаправления запроса по части веб-адреса. По схожему сценарию мы можем делать проксирование:
+
+server {
+    ...
+    location  ~ ^/page1/(.*)$ {
+        proxy_pass   $scheme://10.10.10.10/$1$is_args$args;
+    }
+}
+
+_* и так, в данном примере при обращении по адресу **site.ru/page1/<что-то еще>**, nginx сделает внутренний запрос на сервер **10.10.10.10** по адресу **10.10.10.10/<что-то еще>** и вернет готовый ответ.
+** обратите внимание, что мы добавили **$is_args$args —** если строка запроса имеет аргументы, то их также нужно передать._
+
+### 3. На другой сайт
+
+Мы можем сделать так, что при переходе по одному адресу у нас будет открываться совершенно другой сайт:
+
+server {
+    ...
+    server_name dmosk.local;
+    location / {
+        proxy_pass https://www.dmosk.ru;
+        proxy_set_header   Host             www.dmosk.ru;
+        proxy_set_header   X-Real-IP        $remote_addr;
+        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
+    }
+}
+
+_* в данном случае мы при обращении к нашему серверу (до доменному имени **dmosk.local**) будем попадать на сайт **https://www.dmosk.ru**. Обратите внимание, что в **proxy_set_header** мы передаем хосту его имя — в противном случае, как правило, другой сервер вернет ошибку. Также мы не указываем **proxy_redirect**, иначе, nginx будет переводить запросы на реальный сайт (отправлять инструкции браузеру перейти на него), а не тот, что мы используем за http-прокси._
+
+### 4. На другой сайт по части URL
+
+Если нам нужно настроить проксирование на другой сайт при обращении к определенной странице сайта, настраиваем NGINX так:
+
+server {
+    ...
+    server_name www.dmosk.ru;
+    location /page {
+        rewrite /page/(.*) /$1  break;
+        proxy_pass https://www.site.ru;
+        proxy_set_header   Host             www.site.ru;
+        proxy_set_header   X-Real-IP        $remote_addr;
+        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
+    }
+}
+
+_* в данном примере, если мы перейдем на страницу **www.dmosk.ru/page**, то мы попадем на сайт **www.site.ru**._
+
+### 5. Редиректы при проксировании
+
+Если при проксировании хост возвращает инструкцию браузеру для выполнения редиректа, обозреватель может сменить адрес сайта. Это особенно не удобно, когда проксирование мы выполняем на другой сайт. Чтобы отловить редиректы и заменить их своими значениями, мы должны воспользоваться опцией **proxy_redirect**. Рассмотрим ее применение для предыдущего примера, когда мы проксировали запрос на сайт www.dmosk.ru:
+
+server {
+    listen 80;
+    server_name dmosk.local www.dmosk.local;
+    location / {
+        proxy_pass https://www.dmosk.ru;
+        proxy_set_header   Host             www.dmosk.ru;
+        proxy_set_header   X-Real-IP        $remote_addr;
+        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
+
+        proxy_redirect https://www.dmosk.ru/url1 http://dmosk.local/url2;
+        proxy_redirect https://www.dmosk.ru/ http://dmosk.local/;
+    }
+}
+
+_* в конкретном случае мы проксируем запросы **http://dmosk.local** на сайт **www.dmosk.ru**, но если он вернет инструкцию для редиректа **https://www.dmosk.ru/url1**, в браузере он должен быть заменен на **http://dmosk.local/url2**. А также любое перенаправление для **https://www.dmosk.ru/** будет заменено на **http://dmosk.local/**._
+
+### 6. Таймауты
+
+Сервер может генерировать, довольно, долго ответ. Если за определенное время nginx не получит ответ, он вернет ошибку с кодом 504. Мы можем задать свои значения таймаутов, если приложение должно отвечать долго, например:
+
+    location / {
+        ...
+        proxy_connect_timeout  30;
+        proxy_send_timeout     30;
+        proxy_read_timeout     300;
+        ...
+    }
+
+* где:
+
+- **proxy_connect_timeout —** время соединения с удаленным сервером.
+- **proxy_send_timeout —** время ожидания для отправки запроса на сервер.
+- **proxy_read_timeout —** время ожидания ответа от сервера.
+
+** время указывается в секундах.
+
+## Работа с location
+
+Обратите внимание, что мы часто использовали в качестве условия запроса его URN (Unifrorm Resource Name или унифицированное имя ресурса). Поэтому важно понимать, как мы можем работать с ними при помощи nginx, когда будем обрабатывать запросы для редиректов или проксирований.
+
+### Типы location
+
+Выше мы применяли различные ваианты написания location. Рассмотрим их чуть подробнее:
+
+- **= —** явное указание на точное название адреса запроса.
+- **^~ —** регулярное выражение. Требует совпадения в начале строки.
+- **/ или /path —** строковое выражение. Требует совпадения в начале строки. Сильно напоминает **^~**, но не позволяет применять регулярные выражения.
+- **~ —** регулярное выражение. С учётом регистра.
+- **~* —** регулярное выражение. Без учёта регистра.
+
+### Приоритеты
+
+В конфигурации nginx мы можем создать много конструкций на подобие:
+
+location /api {
+}
+
+location /news {
+}
+
+location /newstest {
+}
+
+Они начнут обрабатываться сверху вниз, пока не будет найден первый подходящий вариант. Таким образом, в нашем примере, содержимое страницы **newstest** не сможет загрузиться, так как будет загружено содержимое страницы **news** (ее location выше в конфигурации).
+
+Приоритеты при выборе, какой location будет грузиться раньше, работают не только по принципу "сверху вниз". Также учитывается тип обработки (выше мы уже их рассмотрели):
+
+**1. location = /path.** Точное совпадение. Самый высокий приоритет. Сначала будут обрабатываться все локейшены данного типа.
+
+**2. location ^~ /path.** Регулярное выражение с совпадением в начале строки.
+
+**3. location ~ /path/ , location ~* .(api|test).** Регулярные выражения.
+
+**4. location /path.** Строковое выражение. Самый низкий приоритет.
+
+## Немного о 301 и 302
+
+В чем принципиальная разница между ответом с кодом 301 и 302? Для обычного посетителя сайта разницы нет. А вот для поискового робота разница огромная.
+
+301-й редирект говорит о склеивании страниц. Это означает для поисковика то, что старая и новая страницы — это одно и то же. Таким образом, результаты ранжирования необходимо сохранить для новой страницы.
+
+302-о перенаправление просто говорит о том, что нужно перейти по другому адресу. Поисковый робот не сохраняет результат выдачи для новой страницы, индексируя его с нуля. \ No newline at end of file