关闭

OpenWrt基于HAProxy的透明代理负载均衡和高可用部署

标签: redsocks负载均衡透明代理socks5
4371人阅读 评论(13) 收藏 举报

公司经常使用SSH或者SS进行代理加速或者科学上网,以往的方式是购买好几个VPS服务器,然后每个服务器开几个SSH或者SS的端口,在本地使用客户端转成Socks5代理端口然后通过浏览器插件使用。但是这样经常会有同事抱怨网络不稳定。因为单个远程VPS会由于各种各样的情况尤其是网络不稳定造成短暂的无法连接,但是这对于工作环境来说是非常难以接受的,于是在网上查阅了相关资料进行负载均衡和高可用的改造。

首先,如果是在windows平台上,SS客户端(github官方版本)是支持负载均衡和高可用的,如下图:

这样就实现了对外提供一个Socks5代理端口,后台实现多个SS节点负载均衡或者高可用的配置了,即使局域网全部用户都连接同一个端口,也不会觉得卡或者掉线,因为多个节点同时down掉的概率非常小


在Linux平台上,可以使用很多优秀的开源负载均衡软件,比如HAProxy和Nginx,现在以配置简单的HAProxy为例

HAProxy代理Shadowsocks的话有两种方式:

1、如果你所有节点的密码和加密方式都是一样的话,那么可以直接负载均衡各个远程代理接口,也就是在配置文件中直接填写远程服务器的IP地址和代理端口,然后在本地只需开启一个ss-local或者ss-redir服务就可以像以前一样使用,但是ss-local或者ss-redir中的server要配置成HAProxy的端口。这相当于把远程所有服务器的端口汇集到本地,实现国内代理,再挂上Shadowsocks客户端服务。这样做的好处是配置简单,而且HAProxy容易侦测哪个节点断开或者不稳定,并且最重要的是,不需要其他任何软件就可以实现透明代理。

2、要是你的每个节点密码和加密方式不一样,或者想用Shadowsocks+SSH进行负载均衡的话。就需要使用多个ss-local客户端,如果想要做透明代理,就需要我下面使用的redsocks2的方式,redsocks2可以汇集多个ss客户端和SSH客户端,ss客户端在配置的时候可以让每个节点使用不同的配置,只需开放一个socks5代理端口给redsocks即可,这样做不易于HAProxy监听那个节点down了,因为本地的ss-local服务并没有出现问题,只是远程的down了而已,HAProxy不能做出准确的判断,另外这样做需要在本地开启多个ss-local服务和一个HAProxy服务,而在第一种方法中,只需要一个ss-local和一个HAProxy就够了。在这种方式下,没法直接使用多个ss-redir进行负载均衡,而在第一种方式中,是可以使用单个ss-redir进行透明代理的负载均衡的。


第一种方法配置非常简单,下面重点讲一下第二种方法,也就是在本地开启多个ss-local或者SSH Socks5代理,然后使用HAProxy进行负载均衡和使用Redsocks进行


首先使用apt-get安装HAProxy,然后配置相应的Socks5端口,SSH和Shadowsocks均可,如1080,1081,1082,1083...多配几个用于均衡流量

然后修改HAProxy配置文件,启动一个接口2222来均衡上面的几个Socks5端口,模式选择tcp,配置文件如下

global
  log 127.0.0.1   local0           #[日志输出配置,所有日志都记录在本机,通过local0输出]
  log 127.0.0.1   local1 notice    #定义haproxy 日志级别[error warringinfo debug]
  daemon		                       #以后台形式运行harpoxy
  nbproc 1                         #设置进程数量
  pidfile /home/alex/haproxy.pid
  ulimit-n 51200                   #ulimit 的数量限制
  maxconn 8192	                   #默认最大连接数,需考虑ulimit-n限制
  #chroot /usr/local/haproxy
defaults
  log global
  mode tcp                  #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK
  retries 3                 #两次连接失败就认为是服务器不可用,也可以通过后面设置
  option abortonclose       #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
  option redispatch
  maxconn 8192              #默认的最大连接数
  timeout connect  5000ms   #连接超时
  timeout client 30000ms    #客户端超时
  timeout server 30000ms    #服务器超时
  balance roundrobin        #设置默认负载均衡方式,轮询方式
  #balance source           #设置默认负载均衡方式,类似于nginx的ip_hash
  #balnace leastconn        #设置默认负载均衡方式,最小连接数
listen admin_stats
  bind *:1111               #设置Frontend和Backend的组合体,监控组的名称,按需要自定义名称
  mode http                       #http的7层模式
  option httplog                  #采用http日志格式
  maxconn 10						          #默认的最大连接数
  stats refresh 30s               #统计页面自动刷新时间
  stats uri /haproxy              #统计页面url
  stats realm Haproxy             #统计页面密码框上提示文本
  stats auth admin:root           #设置监控页面的用户和密码:admin,可以设置多个用户名
  stats hide-version              #隐藏统计页面上HAProxy的版本信息
  stats  admin if TRUE            #设置手工启动/禁用,后端服务器(haproxy-1.4.9以后版本)
frontend ss-in
	bind *:2222
	default_backend ss-out
backend ss-out
	mode tcp
	balance   roundrobin
	option tcplog
	#option allbackups
	server Google2 192.168.1.81:1080 weight 10 maxconn 8192  check inter 1500 rise 3 fall 3
	server TK3 192.168.1.81:1081 weight 10 maxconn 8192  check inter 1500 rise 3 fall 3
	

我这里实际执行代理服务的是192.168.1.81的1080,1081,1082,1083四个端口,负载均衡端口是2222,于是我只需让别人来连接我2222端口即可,比108x端口任何一个都稳定,几乎24h不掉线。

注:如果你仅使用Shadowsocks进行代理并且密码和加密方式一样,可以使用上面提到的方法一,也就是在上面配置文件中将server指定为远程的SS-server端口而不是本地的,然后将ss-local或者ss-redir的server填HAProxy监听的端口即可,下文就可以不用看了。


这样,当访问2222端口的时候,HAProxy会自动引导到1080或者1081...中的某一个,实现负载均衡,而且HAProxy会使用轮询的方式每隔1.5s检查一下端口是否好用,然后将不同的端口移出均衡列表,如果端口恢复,再加入均衡列表

局域网可以通过浏览器访问192.168.1.81:1111/haproxy 输入用户名admin,密码root来通过web页面获得HAProxy的运行情况

启动HAProxy

sudo haproxy -f /home/alex/config/haproxy_local.conf


如果哪个服务器down了,它的颜色红色的,并且Status为down,要是节点运行正常的话,应该是绿色的。

Unbuntu上的HAProxy和Openwrt的HAProxy的配置文件可以用同一个,而且都支持这种web界面的监控。

HAProxy可以负载均衡和高可用一个代理端口,但是代理端口仅能代理一部分支持配置代理程序,要想整机全局代(fan)理(qiang),把SSH或者SS当成VPN用的话,也就是我们所说的透明代理,就需要使用iptables+ss-redir/Redsocks2做端口转发了。

如果使用ss-redir这样的程序做透明代理的话,在方法二中是无法使用HAProxy的,因为此时发送到负载均衡服务器的TCP和UDP的包的目的地址已经不是HAProxy的监听地址了,如果强行使用iptables进行端口转发将这些数据包发送给HAProxy的话,HAProxy会修改这些数据包的源地址为HAProxy本地地址然后记录下每个数据包真实的源地址,然后将修改过源地址的数据包发给代理端口,等到代理端口返回数据后会直接发送给HAProxy,HAProxy会把数据发回给客户端,但是这些响应数据包的源地址都是HAProxy的监听地址,于是客户端就会拒收,导致无法获取请求的结果,比如我向外网的113.4.54.6的80端口发送一个HTTP请求,但是该请求的响应数据包不是从113.4.54.6:80发来而是从192.168.1.81:2000发出来的,客户端会把这个数据包当成别的机器的请求包然后继续等待113.4.54.6:80的响应,于是就会超时。在HAProxy的后台可以观察到IN有值,而OUT始终是0的情况。而普通的Socks5端口代理模式,由于请求数据包的目标地址就是HAProxy的端口地址,所以不会出现NAT的问题。

由于上述的NAT问题,所以不能让HAProxy直接做透明代理的端口,这时就需要一个程序来记录这些数据包的源IP和目标IP,以便在HAProxy返回数据包时,将数据包的源地址从192.168.1.81:2000修改成当初客户端真实请求的地址。而且这个程序的输入端必须是支持iptables端口转发的端口,输出端到连接负载均衡和高可用的Socks5代理端口。而我平时常用的Redsocks正好满足这个条件。可以使用Redsocks来记录这些NAT路由表。

透明代理的负载均衡原理如下:首先像普通Socks5代理一样,开启多个代理服务端口,如1080,1081,1082...然后使用HAProxy负载均衡这些端口,HAProxy监听为2222。然后使用Redsocks代理2222端口,并开放12345端口用于iptables端口转发。这样当HAProxy在收到子代理端口返回的数据包时,不是自己把这些数据包直接发给客户端,而是发给Redsocks,Redsocks收到HAProxy发来的数据包后会查询之前记录的路由表,将响应数据的源地址修改成客户端真实请求的地址,这样客户端就不会发觉自己发送的数据包经过了代理。这样就完成了透明代理的完整流程,同时实现了负载均衡和高可用。同样还适用于HTTP代理和HTTPS代理。Redsocks的部署方法可以参考我之前的一篇文章《Ubuntu编译运行Redsocks2实现透明代理》。

整个透明代理的过程是这样的,有一个客户端假设是192.168.1.2,要访问某网站于是发出了一个tcp握手包,这个包的源IP是192.168.1.2:56565,目的IP是113.4.54.6:80,然后把这个数据包发送到了网关192.168.1.81,网关在PREROUTING时截获了这个数据包,并把数据包发送到了Redsocks监听的端口12345,然后Redsocks收到这个数据包之后,找张纸记录下这个数据包的源IP 192.168.1.2:56565,和目标IP 113.4.54.6:80,然后将这个数据包封装到一个新的数据包中,新包的源IP改成自己的IP如192.168.1.81:7898,目的IP为HAProxy监听的端口192.168.1.81:2222,HAProxy接收到这个数据包后,记录下源IP,也就是192.168.1.81:7898,然后发送给下面的子端口,代理子端口会将这个IP数据包先拆包记录下源IP(HAProxy的IP),然后封装在另一个IP数据包里面发送到代理服务器,代理服务器拆开外层数据包,然后把里面HTTP握手数据包的源IP改成自己的IP,然后向目的IP发送该数据包并接收相应,收到网站响应包后将它封在一个新的IP包里面发回代理子端口,代理子端口收到远程代理服务器的响应后拆开外层的IP包获得代理数据包,然后把这个代理数据包发送给HAProxy,注意此时该代理数据包的目的IP为HAProxy的IP,源IP子代理的IP,里面其实还有一个真实的握手数据的包,然后HAProxy收到数据包后将该数据包的目的IP修改为Redsocks的请求IP192.168.1.81:7898,源IP改成自己的IP 192.168.1.81:2222,然后发送给Redsocks,Redsocks收到这个数据包之后进行拆包,取出里面的握手数据包,根据之前记录的源IP和目标IP修改这个数据包,也就是把这个响应数据包的源IP修改为网站IP 113.4.54.6:80,目标IP修改为客户端的IP 192.168.1.2:56565,这样一次透明代理就完美的结束了

然后我们把部署了负载均衡的Openwrt路由器或者Ubuntu电脑设置为网关,其实Ubuntu 16.04默认状态下就是一个网关,理论上你直接把当前电脑的网关设置为内网的某台Ubuntu机器,然后拔插网线就可以上网了,如果没有成功,那么下面介绍一个方法将Ubuntu或Openwrt系统打造成一个局域网网关。

首先Ubuntu的iptables filter表的FORWARD默认策略是ACCEPT而OpenWrt默认是DROP,所以如果你发现不能把局域网内的某台电脑设置为网关的话,就打通FORWARD表就行,方法如下

sudo iptables -I FORWARD -j ACCEPT


打通FORWARD表后还需要让linux内核支持ip转发,方法如下

打开/etc/sysctl.conf这个文件,取消掉 net.ipv4.ip_forward=1 这一行的注释.
然后执行
sudo sysctl -p
使修改后的文件配置立即生效。
这样只要你的Ubuntu电脑配置正确,那么局域网的其他电脑就可以指定你这台电脑当网关上网,你就可以在你的电脑上写防火墙协议来改变流量走向了。
同样,我还能发现ss-redir和redsocks的一个妙用,就是做NAT功能,可以把不同网段甚至同一个网段的ip都NAT成本机的IP,这个使用SNAT是很麻烦的一件事。

这样局域网中的随便某台Ubuntu电脑或者Openwrt路由器就可以当成网关或者防火墙使用,当然前提是该台电脑的默认网关配置的是真实的默认网关。

然后,在把该电脑配制成网关之后,发到这台电脑的数据包就都会到PREROUTING表中。我们就可以在PREROUTING中使用iptables进行端口转发,把来自局域网其他电脑的数据包发送给redsocks,然后redsocks发送给HAProxy进行代理均衡。这样就完成代理。当然这只能代理TCP流量。网关192.168.1.81 的iptables的规则如下

如果使用luci界面,就不用自己手动配置iptables的端口转发了

iptables -t nat -A PREROUTING -d 127.0.0.0/24 -j RETURN  
iptables -t nat -A PREROUTING -d 192.168.0.0/16 -j RETURN  
iptables -t nat -A PREROUTING -d 10.42.0.0/16 -j RETURN  
iptables -t nat -A PREROUTING -d 0.0.0.0/8 -j RETURN  
iptables -t nat -A PREROUTING -d 10.0.0.0/8 -j RETURN  
iptables -t nat -A PREROUTING -d 172.16.0.0/12 -j RETURN  
iptables -t nat -A PREROUTING -d 224.0.0.0/4 -j RETURN  
iptables -t nat -A PREROUTING -d 240.0.0.0/4 -j RETURN  
iptables -t nat -A PREROUTING -d 169.254.0.0/16 -j RETURN  
  
iptables -t nat -A PREROUTING -p tcp -s 192.168.0.0/16 -j REDIRECT --to-ports 12345


redsocks2 0.65的配置文件如下

base {  
    // debug: connection progress & client list on SIGUSR1  
    log_debug = off;//log记录连接进度和客户端列表  
    daemon = on;//on就在后台执行,off就占用当前终端来显示log,关闭终端redsocks也关闭,所以推荐后台执行on  
    redirector = iptables;//转发工具,Ubuntu使用iptables即可  
}  
  
redsocks {  
    local_ip = 192.168.1.1;//本地监听的地址,为了是iptables的端口转发生效,必须填写0.0.0.0  
    local_port = 12345;//本地监听端口,如果12345被别的程序占了就换一个   
 
    ip = 192.168.1.1;//socks5服务器的ip和端口,可以是SSH或者Shadowsocks的  
    port = 1080;   
    type = socks5;//协议,一般SSH和Shadowsocks填socks5  
    autoproxy = 0;//是否开启自动代理,0为不开启,推荐不要开启  
    timeout = 10;//自动代理超时  

}  
ipcache {  
    // Configure IP cache  
    cache_size = 4;   // Maximum number of IP's in 1K.   
    stale_time = 900; // Seconds to stale an IP in cache since it is added  
                      // into cahce.  
                      // Set it to 0 to disable cache stale.  
    port_check = 1;   // Whether to distinguish port number in address  
    cache_file = "/tmp/ipcache.txt"; // File used to store blocked IP's in cache.  
    autosave_interval = 3600; // Interval for saving ip cache into file.  
                              // Set it to 0 to disable autosave.  
  
}  


这样,局域网中任意一台电脑把默认网关修改为192.168.1.81,就可以转发给redsocks实现透明代理了

同理,无线路由器也可以通过修改默认网关来实现Wifi的透明代理,于是就分享了一个可以自动代理的科学上网Wifi

OpenWrt下HAProxy在安装完成之后会默认重启,重启后会加载默认的配置文件,如果我们不想使用默认的配置文件,可以修改/etc/init.d/haproxy中的HAPROXY_CONFIG变量

#!/bin/sh /etc/rc.common
# Copyright (C) 2009-2010 OpenWrt.org

START=99
STOP=80

SERVICE_USE_PID=1

HAPROXY_BIN="/usr/sbin/haproxy"
HAPROXY_CONFIG="/root/config/haproxy_local.conf"
HAPROXY_PID="/var/run/haproxy.pid"

start() {
	service_start $HAPROXY_BIN -q -D -f "$HAPROXY_CONFIG" -p "$HAPROXY_PID"
}

stop() {
	kill -9 $(cat $HAPROXY_PID | tr "\n" " ")
	service_stop $HAPROXY_BIN
}

reload() {
	$HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID | tr "\n" " ")	
	#$HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID)
}

附:我编译打包的内置redsocks2+HAProxy+pdnsd的 华为HG255d的OpenWrt固件下载地址

http://www.right.com.cn/FORUM/thread-198649-1-1.html

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:431461次
    • 积分:5039
    • 等级:
    • 排名:第6160名
    • 原创:143篇
    • 转载:0篇
    • 译文:1篇
    • 评论:188条
    最新评论