1. Введение
Когда дело доходит до Nginx, это один из самых популярных серверов. Это быстрый, легкий и ответственный за хостинг некоторых из крупнейших сайтов в Интернете. Nginx часто используется в качестве балансировщика нагрузки, обратного прокси-сервера и кэша HTTP, помимо прочего.
В этом руководстве мы сосредоточимся на том, чтобы научиться использовать его в качестве прямого прокси-сервера для любого запрошенного местоположения.
2. Мотивация для прямого прокси
Прокси-серверы — это объекты, которые действуют как посредники между клиентом и хостом запрошенного ресурса. Это означает, что трафик проходит через дополнительную машину, чтобы добраться до пункта назначения (хост-сервер). Прокси-сервер продолжает запрос от имени клиента, поэтому, когда хост-сервер принимает запрос, он видит только IP-адрес прокси-сервера. Для сравнения, обратный прокси-сервер находится прямо перед сетью и направляет запрос, поступающий от клиента, на правильный веб-сервер (внутри сети из нескольких серверов).
Единственным недостатком использования прямых прокси-серверов является то, что они работают на уровне приложений, поэтому нам нужно настроить прокси-сервер для каждого приложения, для которого мы планируем направлять трафик.
Некоторые варианты использования Forward Proxy :
- Маскировка IP-адреса и местоположения для получения доступа к сервисам с ограниченным доступом
- Для изолированных внутренних сетей, которым необходимо подключаться к определенным ресурсам в Интернете.
- Для кеширования запросов к определенным серверам редко меняющегося контента в целях экономии ресурсов
Стоит отметить, что прокси-серверы не шифруют трафик, тогда как виртуальные частные сети перенаправляют трафик через безопасные и зашифрованные туннели .
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 .