如何玩轉(zhuǎn)Nginx正反向代理
一、場景
1、場景描述
- 在客戶的場景中,有兩臺測試服務(wù)windows server系統(tǒng),無法訪問外網(wǎng)。
- 測試服務(wù)器中運行的業(yè)務(wù)程序,需要訪問有幾個公網(wǎng)域名。
- 場景中還有一臺代理服務(wù)器 ,它可以訪問外網(wǎng),也可以通兩臺測試服務(wù)器;
系統(tǒng)架構(gòu)圖如下。
2、需求
兩臺不能訪問外網(wǎng)的測試服務(wù)器里面的程序,需要訪問外網(wǎng)的幾個固定域名。
3、解決方法
- 正向代理:代理服務(wù)器的nginx配置正向代理,為后面的測試服務(wù)器代理全部訪問【限制條件是程序需要支持識別代理】。
- 反向代理:代理業(yè)務(wù)程序所使用到的域名,使訪問請求通過代理出去。
二、反向代理配置
1、公共域名http的反向代理
- 反向代理公共域名,將內(nèi)網(wǎng)服務(wù)器的http請求,代理轉(zhuǎn)發(fā)至原本的域名中。
- 例如 www.tyun.cn 代理轉(zhuǎn)發(fā)至www.tyun.cn。
nginx配置
# cat default.conf
server {
listen 80;
server_name _;
location / {
resolver 114.114.114.114;
set $backend_host $host; #將原始域名存儲到變量中
proxy_pass http://$backend_host$request_uri; #使用變量保持原始域名
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2、公共域名https的反向代理
- 由于這次需要代理轉(zhuǎn)發(fā)是其他公共域名,所以代理服務(wù)器沒有這些公共域名的https證書,公共域名的IP也是會變動的,需要能夠不提示證書問題,并且能夠根據(jù)域名對應(yīng)代理轉(zhuǎn)發(fā)。
- 所以通過4層轉(zhuǎn)發(fā),并且4層代理通過使用域名的形式,轉(zhuǎn)發(fā)至原本的域名中。
- 例如 www.tyun.cn代理轉(zhuǎn)發(fā)至www.tyun.cn。
(1)nginx的ssl_preread
nginx的ssl_preread介紹:
Nginx 開始支持 SSL 的 ssl_preread 功能是在版本 1.9.0 中引入的。
ssl_preread 是 Nginx 的 Stream 模塊中的一個指令,用于在 SSL 握手之前讀取客戶端發(fā)送的數(shù)據(jù),通常用于提前獲取客戶端發(fā)送的信息,比如域名,從而根據(jù)這些信息做出代理或路由決策。這在反向代理和負載均衡的場景中特別有用。
以下是關(guān)于 ssl_preread 的詳細描述:
功能介紹: ssl_preread 允許 Nginx 在 SSL/TLS 握手的早期階段讀取客戶端發(fā)送的數(shù)據(jù),包括 ClientHello 消息。這樣做的目的是為了從握手的預(yù)讀取數(shù)據(jù)中獲取一些信息,以便在接下來的代理和路由過程中做出更明智的決策。
使用場景: ssl_preread 常用于以下場景:
- 根據(jù)客戶端發(fā)送的域名(SNI)將流量代理到不同的后端服務(wù)器。
- 根據(jù)不同的協(xié)議或應(yīng)用層協(xié)議(如 HTTP、SMTP、POP3 等)將流量路由到不同的后端服務(wù)器。
(2)nginx配置
安裝nginx配置:
nginx編譯安裝需要添加特定模塊。
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module
nginx配置文件
這里需要業(yè)務(wù)系統(tǒng)中使用了幾個域名就要配置幾個upstream。
#user nobody;
worker_processes 1;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
include conf.d/*.conf;
}
#配置https反向代理
stream {
map $ssl_preread_server_name $backend_hosthttps {
www.tyun.cn tyun;
www.tyun2.cn tyun2;
}
upstream tyun {
server www.tyun.cn:443;
}
upstream tyun2 {
server www.tyun2.cn:443;
}
server {
listen 443;
ssl_preread on;
resolver 114.114.114.114;
proxy_pass $backend_hosthttps;
proxy_connect_timeout 5s;
proxy_timeout 15s;
}
}
(3)無外網(wǎng)win server服務(wù)器配置
需要配置hosts文件將域名指向代理服務(wù)器中。
C:\Windows\System32\drivers\etc\hosts。
192.168.1.100 www.tyun.cn
192.168.1.100 www.tyun2.cn
三、正向代理解決方案
1、正向代理存在的一些問題
正向代理配置之后,需要業(yè)務(wù)程序中本身支持讀取系統(tǒng)中的代理配置。
2、配置正向代理
nginx正向代理,默認的nginx的無法支持https的訪問,需要添加github上開源的proxy_connect模塊,模塊的鏈接如下 https://github.com/chobits/ngx_http_proxy_connect_module/。
編譯安裝nginx1.23 并添加開源的模塊。
wget https://github.com/chobits/ngx_http_proxy_connect_module/archive/refs/heads/master.zip
unzip master.zip
yum install -y patch
#在nginx源碼目錄執(zhí)行
cd /root/nginx-1.23.3
patch -p1 < /root/ngx_http_proxy_connect_module-master/patch/proxy_connect_rewrite_102101.patch
#nginx編譯
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gzip_static_module \
--with-threads \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_realip_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_v2_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--add-module=/root/ngx_http_proxy_connect_module-master
make && make install
配置nginx
server {
listen 8080;
resolver 114.114.114.114;
proxy_connect;
proxy_connect_allow 80 443;
proxy_connect_connect_timeout 10s;
proxy_connect_data_timeout 10s;
location / {
proxy_pass http://$host;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
3、無外網(wǎng)win server服務(wù)器配置
- 配置完成后,經(jīng)過驗證服務(wù)器上的瀏覽器是可以正常代理http https類型都是沒有問題的。
- 業(yè)務(wù)系統(tǒng)無法走代理,因為程序不會自動使用系統(tǒng)設(shè)置的代理,而需要單獨進行代理配置。
4、使用ptyhon獲取系統(tǒng)代理配置示例
以下展示了一段Python的代碼,來展示如何獲取Windows server系統(tǒng)的代理,并使用該代理,訪問公網(wǎng)。
import os
import requests
import winreg
# 獲取 Windows 系統(tǒng)代理配置
internet_settings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Internet Settings')
proxy_enabled, _ = winreg.QueryValueEx(internet_settings, 'ProxyEnable')
proxy_server, _ = winreg.QueryValueEx(internet_settings, 'ProxyServer')
if proxy_enabled and proxy_server:
proxies = {
'http': 'http://' + proxy_server,
'https': 'https://' + proxy_server,
}
os.environ['http_proxy'] = 'http://' + proxy_server
os.environ['https_proxy'] = 'https://' + proxy_server
else:
proxies = None
# 使用代理請求
response = requests.get('http://www.tyun.cn', proxies=proxies)
print(response.text)