Перейти к основному содержимому

Использование Nginx в качестве прямого прокси

· 8 мин. чтения

1. Введение

Когда дело доходит до Nginx, это один из самых популярных серверов. Это быстрый, легкий и ответственный за хостинг некоторых из крупнейших сайтов в Интернете. Nginx часто используется в качестве балансировщика нагрузки, обратного прокси-сервера и кэша HTTP, помимо прочего.

В этом руководстве мы сосредоточимся на том, чтобы научиться использовать его в качестве прямого прокси-сервера для любого запрошенного местоположения.

2. Мотивация для прямого прокси

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

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

Некоторые варианты использования Forward Proxy :

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

./eb2f6202e1dee6f0de4d793cd1458cdd.png

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

3. Реализация прямого прокси с Nginx

Чтобы реализовать прокси-сервер для пересылки, мы будем использовать машину Linux с установленным Nginx. Для этого руководства мы будем использовать VirtualBox с запущенным и работающим дистрибутивным сервером Linux вместе с установленным Nginx, но вы можете использовать все, что вам удобнее, например, Docker или даже старый ПК, который лежал в уголок на долгие годы.

Во-первых, мы находим файл конфигурации Nginx по умолчанию и комментируем серверную часть, чтобы сохранить ее как архивную копию. Обычно мы можем найти его в /etc/nginx/sites-enabled/default :

# Default server configuration
#server {
#listen 80 default_server;
#listen [::]:80 default_server;

#root /var/www/html;

# Add index.php to the list if you are using PHP
#index index.html index.htm index.nginx-debian.html;

#server_name _;

#location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
#}
#}

Далее давайте создадим новый файл с именем forward и добавим все необходимые настройки, чтобы превратить Nginx в работающий прокси-сервер переадресации :

server {

listen 8888;

location / {

resolver 8.8.8.8;

proxy_pass http://$http_host$uri$is_args$args;

}

}

С первой конфигурацией «слушай 8888;» — мы в основном сообщаем серверу, что все запросы, идущие к этому порту, должны обрабатываться со следующими конфигурациями. Аргумент местоположения отвечает за определенные конфигурации блока подразделения сервера и в основном сообщает серверу, как обрабатывать запросы для определенных URI.

Директива resolver 8.8.8.8 указывает, какие серверы имен следует использовать для преобразования имен вышестоящих серверов в адреса, в данном случае 8.8.8.8 соответствует серверам имен Google.

Переменная $http_host содержит хост в исходном запросе, тогда как $uri содержит путь после домена или IP-адреса. Последние две переменные $is_args и $args проверяют любые дополнительные аргументы в исходном запросе и автоматически добавляют их в проксируемый запрос.

После того, как мы обновим все необходимые конфигурации, нам нужно перезапустить nginx.service, чтобы они вступили в силу:

sudo systemctl restart nginx.service

4. Использование прямого прокси

Как мы упоминали ранее, прокси-серверы пересылки работают на уровне приложения, поэтому, естественно, в зависимости от клиента существует несколько способов настройки прокси-сервера пересылки. Для этого шага мы создадим простой клиент на JavaScript и отследим запрос.

Прежде чем мы начнем, давайте удостоверимся, что на нашем локальном компьютере установлены последние версии node.js и npm. Далее мы создаем каталог и файл для клиента. Назовем директорию Proxy Test и файл proxytest.js соответственно.

Затем нам нужно инициализировать package.json NPM, чтобы мы могли установить все необходимые библиотеки. Мы делаем это, запуская команду npm init на терминале внутри каталога нашего проекта:

npm init

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

npm install request

Наконец, давайте откроем IDE и вставим приведенный ниже код в наш файл proxytest.js :

var request = require('request');

request({
'url':'http://www.google.com/',
'method': "GET",
'proxy':'http://192.168.100.40:8888'
},function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
})

Теперь давайте запустим этот фрагмент кода:

node proxytest.js

Давайте сделаем шаг назад и посмотрим на каждую строку. Первая строка импортирует библиотеку в объект запроса , который мы будем использовать позже.

Внутри объекта запроса мы указываем URL-адрес целевого сервера, метод HTTP и прокси-сервер в качестве URL-адреса и пары ключей порта. Внутри функции обратного вызова, если запрос выполнен успешно, мы записываем тело ответа в консоль.

Далее давайте посмотрим на журналы отладки Nginx:

2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: "http://"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script var: "www.google.com"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script var: "/"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script var: ""
2022/02/20 13:46:13 [debug] 1790#1790: *1 http init upstream, client timer: 0
2022/02/20 13:46:13 [debug] 1790#1790: *1 epoll add event: fd:7 op:3 ev:80002005
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: "Host"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script var: "www.google.com"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: "Connection"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: "close"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: ""
2022/02/20 13:46:13 [debug] 1790#1790: *1 http script copy: ""
2022/02/20 13:46:13 [debug] 1790#1790: *1 http proxy header:
"GET / HTTP/1.0
Host: www.google.com
Connection: close

"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http cleanup add: 0000560CE3CF5E30
2022/02/20 13:46:13 [debug] 1790#1790: *1 http finalize request: -4, "/?" a:1, c:2
2022/02/20 13:46:13 [debug] 1790#1790: *1 http request count:2 blk:0
2022/02/20 13:46:13 [debug] 1790#1790: *1 http run request: "/?"
2022/02/20 13:46:13 [debug] 1790#1790: *1 http upstream check client, write event:1, "/"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http upstream resolve: "/?"
2022/02/20 13:46:14 [debug] 1790#1790: *1 name was resolved to 142.250.184.100
2022/02/20 13:46:14 [debug] 1790#1790: *1 name was resolved to 2a00:1450:4002:406::2004
2022/02/20 13:46:14 [debug] 1790#1790: *1 get rr peer, try: 2
2022/02/20 13:46:14 [debug] 1790#1790: *1 get rr peer, current: 0000560CE3CF5EB8 -1
2022/02/20 13:46:14 [debug] 1790#1790: *1 stream socket 12
2022/02/20 13:46:14 [debug] 1790#1790: *1 epoll add connection: fd:12 ev:80002005
2022/02/20 13:46:14 [debug] 1790#1790: *1 connect to 142.250.184.100:80, fd:12 #3

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

2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy status 200 "200 OK"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Date: Sun, 20 Feb 2022 12:46:15 GMT"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Expires: -1"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Cache-Control: private, max-age=0"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Content-Type: text/html; charset=ISO-8859-1"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info.""
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Server: gws"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "X-XSS-Protection: 0"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "X-Frame-Options: SAMEORIGIN"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Set-Cookie: 1P_JAR=2022-02-20-12; expires=Tue, 22-Mar-2022 12:46:15 GMT; path=/; domain=.google.com; Secure"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Set-Cookie: NID=511=IkyJTmMt6I2b3fHpGNUwdfCkv1q9cjzyeUaxC-cxMZWcbmSi4sVlRlwXJUTRA9ujqQnK2v6DNyhitL3zPRSf7RSIHDCv8aYcUD7jp3vX4sE7ZkiprAWmJo9FlnUJtV9H0IzOFyPck15Jfs0zb1VeOMOjKZk0BZ0XRQ3gNptMOl8; expires=Mon, 22-Aug-2022 12:46:15 GMT; path=/; domain=.google.com; HttpOnly"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Accept-Ranges: none"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header: "Vary: Accept-Encoding"
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy header done
2022/02/20 13:46:14 [debug] 1790#1790: *1 xslt filter header
2022/02/20 13:46:14 [debug] 1790#1790: *1 HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Sun, 20 Feb 2022 12:46:14 GMT
Content-Type: text/html; charset=ISO-8859-1
Transfer-Encoding: chunked
Connection: close
Expires: -1
Cache-Control: private, max-age=0
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2022-02-20-12; expires=Tue, 22-Mar-2022 12:46:15 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=511=IkyJTmMt6I2b3fHpGNUwdfCkv1q9cjzyeUaxC-cxMZWcbmSi4sVlRlwXJUTRA9ujqQnK2v6DNyhitL3zPRSf7RSIHDCv8aYcUD7jp3vX4sE7ZkiprAWmJo9FlnUJtV9H0IzOFyPck15Jfs0zb1VeOMOjKZk0BZ0XRQ3gNptMOl8; expires=Mon, 22-Aug-2022 12:46:15 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding

2022/02/20 13:46:14 [debug] 1790#1790: *1 write new buf t:1 f:0 0000560CE3CF7AD0, pos 0000560CE3CF7AD0, size: 760 file: 0, size: 0
2022/02/20 13:46:14 [debug] 1790#1790: *1 http write filter: l:0 f:0 s:760
2022/02/20 13:46:14 [debug] 1790#1790: *1 http cacheable: 0
2022/02/20 13:46:14 [debug] 1790#1790: *1 http proxy filter init s:200 h:0 c:0 l:-1
2022/02/20 13:46:14 [debug] 1790#1790: *1 http upstream process upstream

Когда запрос успешно отправлен по назначению, мы видим в логах ответ «200 OK», означающий, что запрос принят и ответ успешно возвращен. Из наших журналов мы также можем видеть все HTTP-заголовки, возвращенные ответом, перечисленные построчно. Какие бы заголовки HTTP ни возвращал конечный сервер, они автоматически добавляются в возвращаемый объект прокси.

5. Вывод

В этом руководстве мы узнали, как настроить простой и легкий прокси-сервер пересылки с использованием сервера Nginx. Мы узнали важную разницу между прямым прокси-сервером и VPN. Наконец, мы также узнали, как подключить клиент на основе JavaScript к нашему недавно созданному прямому прокси.

Полный исходный код можно найти на GitHub .