“工匠精神” 精心打造一个代理服务器
首先,本文会涉及众多代理软件的名字,但因为本人是在国外,用代理软件是回国的,是一名爱国青年。所以请大家不要把代理的方向反转来用。
在国外很多时候打开国内的网站非常缓慢,而且时不时有境外 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 一下。
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:
{
"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:
{
"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 端口。
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 和 动态端口。
国内服务器配置文件:
{
"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 。
国外服务器配置文件:
{
"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 的性能。
ipset
在这里推荐大家用这个项目来获取中国的 IP 地址,每月更新的。
这里我只转发了 TCP 流量:
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 地址,推荐大家用脚本来添加,这样可以设置成每月任务,自动更新。
更新前,通常需要先移除旧规则:
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 。
截止 2017-11-15 ,IOS 客户端就只有 Surge 支持直接打开 IPv6 地址,Shadowrocket 和 ShadowRay 均失败。
去广告 & 境外受限
自建 DNS 服务器除了能达到去广告的目的外,还能解决部分国内服务商将域名在国外解析成 127.0.0.1
的问题(如网易云音乐)。
关于如何更好的解除境外受限,大家可以参考一下以下项目。
DNS 去广告的效果也是非常好的,因为是从根源上返回一个 fake IP ,无论是 HTTP 和 HTTPS 都支持。
但域名列表是需要经常更新的,大家可以写个脚本来定期更新。
这里推荐一下这个更新广告域名的项目:
还有个小问题是,大多数的去广告 hosts 文件都是把 IP 指向了 127.0.0.1
或者 0.0.0.0
,但我服务器上是有 WEB Server 的,这会造成浏览器在尝试连接时,会等待结果而不是立即断开连接。我也试过把 IP 地址改成美国国防部的保留 IP 地址,然后通过 iptables 把所有出去的包 drop 了,效果也是不理想。推荐大家把 IP 指向 224.0.0.0
等特殊 IP 地址,实测不会拖慢网页加载速度。(以上结论暂时还没有进行过详细的测试,仅凭实测,如有错误,欢迎指出)
dnsmasq 配置
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 --