“工匠精神” 精心打造一个代理服务器

前言

首先,本文会涉及众多代理软件的名字,但因为本人是在国外,用代理软件是回国的,是一名爱国青年。所以请大家不要把代理的方向反转来用。

在国外很多时候打开国内的网站非常缓慢,而且时不时有境外 IP 受限的问题。而代理软件的 obfs 或者 Websocks 能让我冒认成其他软件的服务器干些嘿嘿嘿的事情之外,还能帮助我突破一些的网络限制,比如我们学校的 Wi-Fi ,除了 443 和 80 端口,其他端口很多都是不通的。经过代理后就不会有域名和端口被限制的问题,还能保障安全,随便连各种 Wi-Fi 。

从而有了这篇文章,整个代理实现了:obfs + 服务器 IP 分流 + UDP 转发 + 去广告 + IPv6 支持 。

代理入口

Shadowsocks

之所以选择 Shadowsocks 作为代理入口是因为 Shadowsocks 都发展有一段时间了,各平台的客户端也比较完善,用起来比较顺手。而目前 V2ray 的手机客户端目前还不稳定,如果直接用 V2ray 作为入口的话,就可以直接在 V2ray 实现 UDP 转发和 IP 分流,也能用 Caddy 和 Nginx 直接代理它的 Websocks 不需要再套 SNIPROXY,整个过程更加简洁。但截止目前 2017-11-15 ,IOS 端的 ShadowRay 还是很不稳定,丢失 VPN 图标经常发生,而且 IPv6 支持并不完美(不支持直接打开 IPv6 地址),也不支持 UDP 转发。综合以上的考虑,决定使用 Shadowsocks 作为代理的入口。

配置 Shadowsocks

相信大家对于这个已经不陌生了,我也不过多介绍。

推荐使用 秋水逸冰 的一键安装脚本,Shadowsocks-libev 版
https://teddysun.com/

Shadowsocks 优化

除了基本的安装,当然还要有一些其他的优化,比如打开 BBR 和 TCP Fast Open ,还有一些 sysctl 的优化,我直接放上来。

原本我是参考小数派里面一篇很好的文章的,里面有详细写到每一项的作用,但 “不知道为什么” ,这文章后来被删除了。

所以如果大家要了解以下 sysctl 设置的作用的话,可以 Google 一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
net.ipv6.conf.all.accept_ra = 2
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
fs.file-max = 1024000
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.core.rmem_max = 12582912
net.core.wmem_max = 12582912
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912
net.ipv4.ip_forward = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_mtu_probing = 1
net.ipv4.conf.all.accept_source_route = 1n
et.ipv4.conf.default.accept_source_route = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.lo.send_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv6.conf.all.accept_source_route = 1
net.ipv6.conf.default.accept_source_route = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.autoconf = 1
net.ipv6.conf.all.forwarding = 1

Shadowsocks 配置文件

因为我们需要兼容到 WEB 服务器的运行,然后用 443 端口来做代理 TCP 和 UDP 的 Shadowsocks 流量。我们要分别跑两个 Shadowsocks 服务,一个是 TCP + obfs server 的,另一个是 UDP Only 的,因为 SNIPROXY 不代理 UDP 流量。

TCP SERVER:

1
2
3
4
5
6
7
8
9
{
"server":["[::1]","127.0.0.1"],
"server_port":8988,
"local_address":"127.0.0.1",
"local_port":1080,
"password":"stevenkwan.me",
"timeout":600,
"method":"chacha20-ietf-poly1305"
}

因为服务还需要经过 SNIPROXY 代理,所以监听 IPv4 的 127.0.0.1 即可,顺带提一下 IPv6 里是 [::1]

在运行的时候,还需要加上以下的参数:

-6 -c /xxxxxx/ss-tls.conf -d 127.0.0.1:53 --plugin obfs-server --plugin-opts "obfs=tls;fast-open"

-6 优先使用 IPv6 地址。

-d 指定 DNS 服务器,这里指定为本机的 dnsmasq 服务器,下面去广告会用到。

UDP Only SERVER:

1
2
3
4
5
6
7
8
9
{
"server":["[::0]","0.0.0.0"],
"server_port":443,
"local_address":"127.0.0.1",
"local_port":443,
"password":"stevenkwan.me",
"timeout":600,
"method":"chacha20-ietf-poly1305"
}

这里的 UDP 是需要直接暴露在公网的 443 端口。

在运行的时候,还需要加上以下的参数:

-6 -U -c /xxxx/udp-443.conf -d 127.0.0.1:53

-U 大写的 U 代表只开启 UDP 转发不开启 TCP 转发,如果写成小写的话,是两个同时开始。有 WEB Server 的话就会提示端口已经被占用。

兼容 WEB

SNIPROXY

SNIPROXY 的设置非常简单,直接上配置文件。

需要注意的是,启用前,要先将 WEB Server 改成非 443 端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
user daemon

pidfile /tmp/sniproxy.pid

error_log {
syslog daemon
priority notice
}

listen 443 {
protocol tls
reuseport no
table https
fallback [::1]:445
}

table https {
www.google.com [::1]:8988
}

fallback 指向你的 WEB Server 端口即可。

table https 里面写你 Shadowsoks 里使用的 obfs 域名。

中转服务器

V2ray

除了我上面说的 V2ray 客户端不足,V2ray 还是有很多优势的,适合用来 “长距离” “翻山越岭” 。它支持 mkcp 和 mux 。

我曾经用过 Shadowsocks 作为中转服务器,那速度真的太慢了。

这里我用到了 mkcp 和 动态端口。

国内服务器配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{
"inbound": {
"port": 8888,
"protocol": "vmess",
"streamSettings": {
"network": "kcp"
},
"settings": {
"clients": [
{
"id": "xxxxxxxxxx",
"level": 1,
"alterId": 32
}
],
"detour": {
"to": "detour-kcp"
}
}
},
"inboundDetour": [
{
"protocol": "vmess",
"port": "8889-9999",
"tag": "detour-kcp",
"settings": {},
"allocate": {
"strategy": "random",
"concurrency": 2,
"refresh": 5
},
"streamSettings": {
"network": "kcp"
}
}
],
"outbound": {
"protocol": "freedom",
"settings": {}
},
"outboundDetour": [
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"type": "field",
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"::1/128",
"fc00::/7",
"fe80::/10"
],
"outboundTag": "blocked"
}
]
}
},
"transport": {
"kcpSettings": {
"mtu": 1400,
"tti": 20,
"uplinkCapacity": 10,
"downlinkCapacity": 10,
"congestion": false,
"readBufferSize": 2,
"writeBufferSize": 2,
"header": {
"type": "none"
}
}
}
}

请自行修改配置文件的端口、动态端口范围、客户 ID 。

国外服务器配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
"inbound": {
"protocol": "dokodemo-door",
"port": 1080,
"settings": {
"network": "tcp,udp",
"timeout": 30,
"followRedirect": true
}
},
"outbound": {
"protocol": "vmess",
"streamSettings": {
"network": "kcp"
},
"mux": {
"enabled": true,
"concurrency": 8
},
"settings": {
"vnext": [
{
"address": "8.8.8.8",
"port": 8888,
"users": [
{
"id": "xxxxxxxxxx",
"alterId": 32,
"security": "aes-128-gcm"
}
]
}
]
}
},
"transport": {
"kcpSettings": {
"mtu": 1400,
"tti": 20,
"uplinkCapacity": 100,
"downlinkCapacity": 100,
"congestion": false,
"readBufferSize": 2,
"writeBufferSize": 2,
"header": {
"type": "none"
}
}
}
}

这里我们将 V2ray 的 inbound 设置为透明代理,这样 iptables 就能把国内流量转发到 V2ray 上。

更详细的设置 V2ray 设置可以参考他们家的官网 https://www.v2ray.com

IP 分流

iptables

要根据 IP 来分流,除了 iptables 之外,也没其他什么软件能做到了。但是单纯靠 iptables 来分流的话,会造成性能低下,这时候我们需要 ipset 。

下面这篇文章测试了在使用 ipset 和不使用 ipset 时 iptables 的性能。

http://blog.csdn.net/dog250/article/details/41171643

ipset

在这里推荐大家用这个项目来获取中国的 IP 地址,每月更新的。

https://github.com/17mon/china_ip_list

这里我只转发了 TCP 流量:

1
2
3
4
5
ipset -N chnroute hash:net maxelem 65536
ipset add chnroute $IP
iptables -t nat -N V2RAY
iptables -t nat -A V2RAY -p tcp -m set --match-set chnroute dst -j REDIRECT --to-port 1080
iptables -t nat -A OUTPUT -p tcp -j V2RAY

将上面的 $IP 换成你需要添加的 IP 地址,推荐大家用脚本来添加,这样可以设置成每月任务,自动更新。

更新前,通常需要先移除旧规则:

1
2
3
4
iptables -t nat -D OUTPUT -p tcp -j V2RAY
iptables -t nat -F V2RAY
iptables -t nat -X V2RAY
ipset destroy chnroute

UDP

在上面配置 Shadowsocks 服务端的时候,我们已经做好了完整的 UDP 转发支持。但客户端支不支持,却又是另一回事,我们可以通过以下方法来测试。

测试 UDP

我们在服务器上打开一个 screen 运行 nc -lu 20000 来监听 20000 端口的 UDP 。

然后在需要测试的设备上,发一个 UDP 包到你的服务器上。

如果服务器能收到这个 UDP 包,那么就可以再新开一个 screen 运行 netstat -nu | grep 20000 来查看来源 IP ,通过来源 IP 来判断是否走了代理。

截止 2017-11-15 ,IOS 客户端就只有 Shadowrocket 支持 UDP 转发,Surge 和 ShadowRay 均为直连。

IPv6 支持

在上面配置 Shadowsocks 服务端的时候,已经做好了完整的 IPv6 支持,大家可以打开一下网站里面的 “技术信息” 来测试 IPv6 。

http://test-ipv6.com

截止 2017-11-15 ,IOS 客户端就只有 Surge 支持直接打开 IPv6 地址,Shadowrocket 和 ShadowRay 均失败。

去广告 & 境外受限

自建 DNS 服务器除了能达到去广告的目的外,还能解决部分国内服务商将域名在国外解析成 127.0.0.1 的问题(如网易云音乐)。

关于如何更好的解除境外受限,大家可以参考一下以下项目。

https://github.com/uku/Unblock-Youku

DNS 去广告的效果也是非常好的,因为是从根源上返回一个 fake IP ,无论是 HTTP 和 HTTPS 都支持。

但域名列表是需要经常更新的,大家可以写个脚本来定期更新。

这里推荐一下这个更新广告域名的项目:

https://github.com/StevenBlack/hosts

还有个小问题是,大多数的去广告 hosts 文件都是把 IP 指向了 127.0.0.1 或者 0.0.0.0 ,但我服务器上是有 WEB Server 的,这会造成浏览器在尝试连接时,会等待结果而不是立即断开连接。我也试过把 IP 地址改成美国国防部的保留 IP 地址,然后通过 iptables 把所有出去的包 drop 了,效果也是不理想。推荐大家把 IP 指向 224.0.0.0 等特殊 IP 地址,实测不会拖慢网页加载速度。(以上结论暂时还没有进行过详细的测试,仅凭实测,如有错误,欢迎指出)

dnsmasq 配置

1
2
3
4
5
6
7
8
9
port=53
no-resolv
server=2001:4860:4860::8888
server=8.8.8.8
server=2620:0:ccc::2
server=208.67.222.222
all-servers
listen-address=127.0.0.1,::1
addn-hosts=/etc/dnsmasq_host/hosts

这里我设置了 4 个 DNS 上有地址,是 Google Public DNS 和 OpenDNS 的 IPv4 和 IPv6 地址,用了 all-servers 选项去并发查询这 4 个服务器,取最先返回结果的。

如果 Shadowsocks 开启了 IPv6 优先的话,hosts 文件也要加入 IPv6 的地址,推荐使用 ‘FF00::’ 。

因为 DNS 服务器只是给本机使用的,安全起见可以只监听 127.0.0.1

addn-hosts 则为去广告所用的 hosts 文件。

大功告成~!

至此为此,安全性和各种功能都有了,可以无拘无束的安心上网了。

原文链接:https://stevenkwan.me/post/perfect-proxy-server.html

– EOF –

您的支持将鼓励我继续坚持技术分享!
0%