相信Shadowsocks(简称:SS)一定不会陌生,PC或移动设备的SS的客户端那么一定用过,但客户端总有一些不方便,比如要频繁开关,或是守护进程方式耗费性能。所以我们更希望日常使用中完全忽略掉SS的存在,同时又可以实现代理。有些基于Linux的智能路由器操作系统如Openwrt提供了解决方案,付出的代价就是牺牲部分路由器的性能和稳定性,引发了家庭中技术宅与麻瓜不必要的争吵——“怎么又断网了,你花了2000买的路由器被人坑了吧”。我的建议是,把这些折腾的功能从路由器里分出来,让路由器安安心心的做它的专业吧。Raspberry Pi(简称:RPI)是一个非常流行专为折腾而生的卡片电脑,它有完整的操作系统,完全可以当成一个服务器使用,而功耗与稳定性都与一个家用路由器相当。本文介绍如何在不改变路由器的本性的情况下,使用RPI做网关实现透明代理。

选型与原理

                                               
           Internet                            
               │                               
               │                               
            ┌──■───────────┐                   
            │    Router    │                   
            └──■──■──■──■──┘                   
               │  │  │  │      ┌──────────────┐
               │  │  │  └──────│ Raspberry Pi │
               │  │  │         └──────────────┘
      ┌────────┘  │  └───────────┐             
      │           │              │             
 ┌────┴─────┐ ┌───┴──────┐ ┌─────┴─────┐       
 │    TV    │ │    PC    │ │   Phone   │       
 └──────────┘ └──────────┘ └───────────┘       

实施方案

准备

检查一下你是否具备以下材料

  • 可用的SS服务器:无论是自己搭还是租用借用的
  • Raspberry Pi:本文使用的是3B+版本,当然性能上Zero都足够了
  • 有管理员权限的路由器:至少一个LAN口空闲

如果以上就绪就可以开启下面的旅程

准备Raspberry Pi

拿到RPI后第一件事就是要安装操作系统,毫无疑问,Raspbian作为RPI的官方操作系统,可以从官方下载链接获得,以下都是基于Stretch版本制定的。

下载好镜像后通过工具flash一张SD卡(也就是RPI的硬盘)。推荐使用官方的烧录工具Raspberry Pi Imager,当然
Linux下可以直接使用dd命令,Mac下可以使用balenaEtcher

然后安装好系统的RPI有线连接到路由器的LAN口。
最后非常关键的一步,RPI配置为静态IP,Gateway和DNS为路由器IP。因为后面我们会改DHCP的配置

安装配置Shadowsocks

最简单的方式肯定是APT安装,我们安装的Raspbian对应的Debian版本是Stretch,而apt源里带的shadowsocks-libev安装包版本是2.6.3,如果你需要更高版本的特性,比如加密方式chacha20-ietf-poly1305,那么你只能选择编译安装。

APT安装

sudo apt-get install shadowsocks-libev

编译安装

Raspbian本质上就是Debian,编译过程和Debian上没有区别
感谢teddysun贡献的一键安装脚本,使安装过程变的非常简单。
首先是,安装编译环境

sudo apt-get install build-essential

下载一键安装脚本

wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks-libev-debian.sh
chmod +x shadowsocks-libev-debian.sh

为了通过操作系统检测,把/etc/issue里面的Raspbian改成Debian,安装完成后再改回来。
运行安装脚本

./shadowsocks-libev-debian.sh

安装时会提示你配置,同样安装后也可以到/etc/shadowsocks-libev/config.json修改

配置Shadowsocks

配置文件默认为/etc/shadowsocks-libev/config.json
安装后自带的/etc/init.d/shadowsocks-libev系统服务是一个ss-server,但我们要启动的是ss-redir,ss-redir可以直接启动:

ss-redir

配置为系统服务

sudo vi /etc/systemd/system/ss-redir.service
Description=ss-redir

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
Environment=GOGC=20
ExecStart=/usr/bin/ss-redir -c /etc/shadowsocks-libev/config.json -b 0.0.0.0 -uv -l 1234 
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target
sudo systemctl enable ss-redir.service

配置远程代理模式

配置DNS代理

为什么要配置DNS代理,因为本地DNS已被污染,你解析的IP就是错的,就算代理还是没有用。由于DNS是UDP协议的,如果你的SS服务器支持UDP连接,那么只要搭建一个到SS服务器的隧道就可以了,否则只能借助于pdnsd。

DNS隧道

启动DNS隧道

ss-tunnel -b 0.0.0.0 -u -l 5353 -L 8.8.8.8:53

当然可以配置为系统服务:

sudo vi /etc/systemd/system/ss-tunnel.service
Description=ss-tunnel

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
Environment=GOGC=20
ExecStart=/usr/bin/ss-tunnel -c /etc/shadowsocks-libev/config.json -b 0.0.0.0 -u -l 5353 -L 8.8.8.8:53
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target
sudo systemctl enable ss-tunnel.service

其它方式(不建议):

sudo cp /etc/init.d/shadowsocks-libev /etc/init.d/shadowsocks-tunnel
sudo vi /etc/init.d/shadowsocks-tunnel
DESC=shadowsocks-tunnel
NAME=shadowsocks-tunnel
DAEMON=/usr/bin/ss-tunnel
DAEMON_ARGS="-b 0.0.0.0 -u -l 5353 -L 8.8.8.8:53 > /var/log/shadowsocks-tunnel.log"
CONFFILE=/etc/shadowsocks-libev/config.json
sudo update-rc.d shadowsocks-tunnel defaults
sudo systemctl enable shadowsocks-tunnel
sudo update-rc.d -f shadowsocks-tunnel remove

安装KCPTUN

安装KCPTUN

set KCP_VER 20200701
set ARM_VER 6
set KCP_URL https://github.com/xtaci/kcptun/releases/download/v$KCP_VER/kcptun-linux-arm$ARM_VER-$KCP_VER.tar.gz
wget $KCP_URL 
tar -zxvf kcptun-linux-arm$ARM_VER-$KCP_VER.tar.gz
sudo mv client_linux_arm$ARM_VER /usr/local/bin/kcptun_client

配置为服务

参考官方Demo配置

sudo vi /etc/systemd/system/kcptun.service
Description=kcptun

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
Environment=GOGC=20
ExecStart=/usr/local/bin/kcptun_client -c /etc/kcptun/config.json
Restart=on-failure
RestartSec=10
KillMode=process
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
sudo systemctl enable kcptun.service

配置NAT代理

ss-redir启动后,本地1234端口(默认配置)的流量,你可以直接配置一条iptables把所有的流量都NAT到ss-redir的端口,但是这样的问题就是本来不需要走SS的流量也耗费了RPI的CPU加解密以前SS服务器本就不充足的带宽和流量。现在流行的有两种配置方式:一个是ChinaDNS模式,这种方式把访问非中国的IP的流量都NAT到SS;另一个是GFWList模式,这种方式只把因GFW不能正常访问的流量NAT到SS。

配置方式:

配置本地终端路由模式

此时,只要本地终端设备的网关和DNS指向到RPI就可以实现透明代理了,如果没有特别要求,那么可以让所有设备的网关和DNS指向到RPI,而如果要实现隔离以保护部分设备的稳定性,那么可以配置指定设备。

所有设备使用代理

配置路由器的DHCP指定:

  • Gateway:RPI的IP
  • DNS:RPI的IP

指定设备使用代理

考虑到有些设备不能配置静态IP(如:部分智能家居设备),我们还是使用DHCP的方式指定IP,由于路由器的DHCP都比较简单,很多配置不够灵活,所以我们关闭路由器的DHCP功能,让RPI提供DHCP服务,首先安装dhcp-server:

sudo apt-get install isc-dhcp-server

配置/etc/dhcp/dhcpd.conf
修改默认网络,并添加一个subnet用于怎么分配IP。

option domain-name "myhome";
option domain-name-servers $rpi_ip;
option routers $route_ip;

subnet 192.168.0.0 netmask 255.255.255.0 {
  range 192.168.0.40 192.168.0.254;
  option domain-name "myhome";
  option domain-name-servers $rpi_ip;
  default-lease-time 600;
  max-lease-time 7200;
}

$route_ip替换为路由器的IP,$rpi_ip替换为RPI的IP

配置需要代理的设备,添加一个host

host my_device {
  hardware ethernet $device_mac;
  option routers $rpi_ip;
}

$device_mac替换为需要代理的设备的MAC地址,$rpi_ip替换为RPI的IP

启动dhcp:

service isc-dhcp-server start

后续计划

虽然写了教程,但实际操作还有比较复杂的,后续计划把以上环境做了Docker Image,让技术宅更轻松。
另外,虽然Raspberry Pi是一款不错的卡片PC,但是到目前为止最先进的版本3B+仍然使用的是百兆网卡,在等新款更新之前也会尝试一些带有千兆网卡的山寨派。

多说一点点

为了让大家少走一些弯路,总结一下我踩过的坑,给大家一些推荐,因为很难照顾所有人的需求,所以基于以下假设

  • 你是一个喜欢折腾的技术宅,而且收入足够你折腾
  • 有非常多的需要上网的电子设备
  • 有网络基本知识但不是专家

那么,这些原则应该考虑

  • 需要一个原厂的稳定的主路由,无论何时都能提供Internet,因为你需要折腾坏了局域网时也能查资料
  • 把网络划分为稳定区与折腾区
    • 稳定区:首先为了家庭和谐,除了你专用的设备都应该在稳定区,另外你的主PC也应该在这个区。
    • 折腾区:把如果这个区挂了不会造成你抓狂的设备放在这个区。
  • 设备选购原则:
    • 入户光猫:运营商标配,光猫设置为桥接
    • 路由器:选择带机量大且稳定性强的一线大厂,不推荐国产各种概念智能路由

小户型(单AP覆盖)推荐

路由器选择无线路由,推荐:

RPI挂在路由下

为什么推荐WRT1900ACS?因为这个路由器就是为折腾而生的,那不是说要稳定吗?可你都单身了还怕什么?就算网断了不是还有手机吗?不带MU-MIMO有什么影响?就你一个人上网好吧,MU-MIMO是提升并行传输的,没有MU-MIMO并不影响接多少设备,你又不会分身,同一时间你同时操作20多个设备?

大户型(多AP覆盖)推荐

主路由器选择可放到弱电箱的高性能有线路由器,推荐:

无线方案首先要考虑的是稳定性,然后是无缝漫游,在AP集中管理与Mesh之间,我选择Mesh,推荐:

RPI挂在主路由器下,AP挂在主路由下,关闭路由功能使用switch模式,保持所有设备与主路由在同一网络