linux下科学上网简单搭建 linux下利用shadowsock+kcptun+udp2raw的科学上网搭建。
本文适读人群
对 linux 服务有简单了解
对科学上网稳定性有强迫,在使用 shadowsocks+kcptun+udp2raw 会让科学上网非常稳定不容易掉包
本文能够知道什么
linux 下成功使用 shadowsocks+kcptun+udp2raw 搭建科学上网
常见故障怎么定位(key 不一致、MTU 溢出、换网络后失效、TUN 冲突)
本文不知道什么
搭建工具原理
链路总览 先把数据流搞清楚,后面每一步都对得上号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 浏览器 / 终端 │ SOCKS5 127.0.0.1:9872 (TCP) ▼ sslocal (shadowsocks 客户端) │ TCP 加密流量 → 127.0.0.1:30001 ▼ kcptun client (KCP,UDP 承载) │ UDP → 127.0.0.1:30001 ▼ udp2raw client (把 UDP 伪装成假 TCP,faketcp) │ UDP 4096 → 服务器公网 IP:4096 ═══════════ 公网 ═══════════ │ udp2raw server :4096 │ TCP → 127.0.0.1:8400 ▼ kcptun server :8400 │ TCP → 127.0.0.1:39201 ▼ ssserver :39201 │ ▼ 互联网
各环节端口对应关系:
环节
协议
端口
本机 SOCKS5
TCP
9872
sslocal → kcptun client
TCP
30001
kcptun client → udp2raw client
UDP
30001
udp2raw client → udp2raw server
UDP
4096
udp2raw server → kcptun server
TCP
8400
kcptun server → ssserver
TCP
39201
30001 同时出现两次是正常的:kcptun 监听 TCP 30001 给 sslocal 连,udp2raw 监听 UDP 30001 给 kcptun 连,协议不同不冲突。
VPS 购买
我买的是 digitalocean 价格在 5 刀一个月偏贵,只要是国外服务器就行。
防火墙只要开一个口
只需要放行 UDP 4096 入站 ,其它(22 除外)全部关掉。
8400、39201 是纯本地回环,绑定 127.0.0.1 即可,不要 对外暴露。
1 2 sudo ufw allow 4096/udp sudo ufw enable
shadowsocks搭建
下载 shadowsocks 已发布的版本 https://github.com/shadowsocks/shadowsocks-rust/releases;
选 x86_64-unknown-linux-musl 那个包(静态链接,不依赖系统 glibc,扔到任何发行版都能跑):
1 2 wget https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.6.10/shadowsocks-v1.6.10-release.x86_64-unknown-linux-musl.tar.xz tar -xf shadowsocks-v1.6.10-release.x86_64-unknown-linux-musl.tar.xz
压缩包解压后我们要使用的有两个文件:ssserver(服务端)、sslocal(客户端)。
注意:新版 shadowsocks-rust 的配置文件字段改过(变成 servers / locals 数组),老版本用单个 JSON 对象的写法在新版会报错。下面统一改用命令行参数 ,跨版本最稳。
客户端配置
将 sslocal 拷贝至 /usr/local/bin/ 下
1 sudo cp sslocal /usr/local /bin/
创建开机启动服务
1 sudo vim /lib/systemd/system/ss-server.service
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =shadowsocks local client (SOCKS5)After =network-on line.target kcptun.serviceWants =network-on line.target[Service] Type =simpleExecStart =/usr/local/bin/sslocal -b 127.0 .0.1 :9872 -s 127.0 .0.1 :30001 -k "你的密码" -m aes-256 -gcmRestart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
参数含义:-b 本地 SOCKS5 监听地址;-s 上游地址,也就是 kcptun 客户端的 TCP 30001 。
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start ss-server.service sudo systemctl enable ss-server.service
服务端配置
将 ssserver 拷贝至 /usr/local/bin/ 下
1 sudo cp ssserver /usr/local /bin/
创建开机启动服务
1 sudo vim /lib/systemd/system/ss-server.service
1 2 3 4 5 6 7 8 9 10 11 12 [Unit] Description =shadowsocks serverAfter =network-on line.target[Service] Type =simpleExecStart =/usr/local/bin/ssserver -b 127.0 .0.1 :39201 -k "你的密码" -m aes-256 -gcmRestart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
**这里必须绑 127.0.0.1**。老版本照着抄 "server": "::" 会把 39201 暴露在公网,等于绕过 udp2raw + kcptun 直连 shadowsocks,既失去抗封锁效果又多一个被扫的入口。
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start ss-server.service sudo systemctl enable ss-server.service
kcptun搭建
下载 kcptun 已发布的版本 https://github.com/xtaci/kcptun/releases,选 linux-amd64 包(文件名形如 kcptun-linux-amd64-<日期>.tar.gz,日期随版本变,用最新的那个):
1 2 3 wget https://github.com/xtaci/kcptun/releases/download/v20251017/kcptun-linux-amd64-20251017.tar.gz tar -xf kcptun-linux-amd64-20251017.tar.gz
国内访问 GitHub Releases 经常失败,可以从 SourceForge 镜像拿:https://sourceforge.net/projects/kcptun.mirror/files/,文件完全一样。
解压后要用两个文件:server_linux_amd64(服务端)、client_linux_amd64(客户端)。
客户端配置
将 client_linux_amd64 拷贝至 /usr/local/bin/ 下
1 sudo cp client_linux_amd64 /usr/local /bin/
创建开机启动服务
1 sudo vim /lib/systemd/system/kcptun.service
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =kcptun clientAfter =network-on line.target udp2raw.serviceWants =network-on line.target udp2raw.service[Service] Type =simpleExecStart =/usr/local/bin/client_linux_amd64 -l :30001 -r 127.0 .0.1 :30001 --crypt salsa20 --key "你的KEY" --nocomp --mtu 1200 Restart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
三个容易踩的点:
--mtu 1200 不能省 。kcptun 默认 1350,加上 28 字节 IP/UDP 头就是 1378 字节,超过 udp2raw 单包上限 1375,日志会刷 huge packet,data len=1378 (>=1375),表现为能连上但速度很怪。
--nocomp 必须和服务端 "nocomp": true 一致。
老版本抄来的 PIDFile=/var/run/kcp-server.pid 是无效行 ——kcptun 不写 pid 文件,Type=simple 下写它只会让 systemd 打警告,删掉。
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start kcptun.service sudo systemctl enable kcptun.service
服务端配置
将 server_linux_amd64 拷贝至 /usr/local/bin/ 下
1 sudo cp server_linux_amd64 /usr/local /bin/
创建配置文件
1 sudo vim /etc/kcptun.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { "listen" : ":8400" , "target" : "127.0.0.1:39201" , "crypt" : "salsa20" , "mode" : "fast2" , "key" : "你的KEY" , "nocomp" : true , "mtu" : 1200 , "keepalive" : 10 , "nodelay" : 0 , "dscp" : 0 , "sockbuf" : 4194304 , "nc" : 1 , "resend" : 2 , "parityshard" : 3 , "rcvwnd" : 4096 , "interval" : 20 , "sndwnd" : 4096 , "datashard" : 10 }
mtu 两端必须一致,客户端 --mtu 1200 服务端就写 1200。target 指向本机 ssserver 的 39201,listen 监听 8400,两个都在回环里,不要绑 0.0.0.0。
创建开机启动服务
1 sudo vim /lib/systemd/system/kcptun.service
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =kcptun serverAfter =network-on line.target ss-server.serviceWants =network-on line.target[Service] Type =simpleExecStart =/usr/local/bin/server_linux_amd64 -c /etc/kcptun.jsonRestart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
ExecStart 里的文件名要和拷贝的文件名一致 。官方包里的二进制叫 server_linux_amd64,不是 kcptun;两者不一致会直接 status=203/EXEC 起不来。
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start kcptun.service sudo systemctl enable kcptun.service
udp2raw搭建
下载 udp2raw 已发布的版本 https://github.com/wangyu-/udp2raw-tunnel/releases;
解压后使用对应架构的 udp2raw_amd64,udp2raw 服务端客户端是同一个文件。
客户端配置
将 udp2raw_amd64 拷贝至 /usr/local/bin/ 下
1 sudo cp udp2raw_amd64 /usr/local /bin/
先看一个能跑但不够用 的版本
1 2 [Service] ExecStart =/usr/local/bin/udp2raw_amd64 -c -l 0.0 .0.0 :30001 -r 服务器IP:4096 -k "你的KEY"
实际推荐:加 --lower-level auto --source-ip --dev
udp2raw 的 faketcp 是自己在二层拼包发出去的。如果本机装了 Mihomo / Clash 之类会建 TUN 设备接管全局路由的软件,内核给它选的源地址会变成 TUN 的地址(比如 198.18.0.1),伪 TCP 的 SYN 会被对端直接 RST,日志永远是 client_tcp_handshake 反复重发 SYN。
需要显式告诉它走哪块网卡、用哪个源 IP:
1 2 sudo /usr/local /bin/udp2raw_amd64 -c -l 0.0.0.0:30001 -r 服务器IP:4096 -k "你的KEY" \ --lower-level auto --source-ip 192.168.1.23 --dev wlan0
--source-ip 必须填主路由表里的真实局域网 IP ,不是 TUN 地址;--dev 是对应网卡。手工写死的问题是换个 WiFi 就失效,所以做成启动时自动探测的 wrapper:
1 sudo vim /usr/local /bin/udp2raw-client
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 #!/bin/sh set -euSERVER=服务器IP REMOTE_PORT=4096 LOCAL_PORT=30001 KEY='你的KEY' BIN=/usr/local /bin/udp2raw_amd64 detect () { dev=$(ip -o route show table main default 2>/dev/null | awk '{for (i = 1; i <= NF; i++) if ($i == "dev") {print $(i + 1); exit}}' ) [ -n "${dev:-} " ] || return 1 src=$(ip -o -4 addr show dev "$dev " scope global 2>/dev/null | awk '{print $4; exit}' | cut -d/ -f1) [ -n "${src:-} " ] || return 1 echo "$dev $src " } tries=0 while [ "$tries " -lt 15 ]; do if info=$(detect); then DEV=${info%% *} ; SRC=${info#* } ; break ; fi tries=$((tries + 1 )); sleep 2 done [ -n "${DEV:-} " ] && [ -n "${SRC:-} " ] || { echo "未探测到默认路由/源地址" >&2; exit 1; } echo "udp2raw-client: dev=$DEV src=$SRC server=$SERVER :$REMOTE_PORT " exec "$BIN " -c -l "0.0.0.0:${LOCAL_PORT} " -r "${SERVER} :${REMOTE_PORT} " -k "$KEY " \ --lower-level auto --source-ip "$SRC " --dev "$DEV "
1 sudo chmod 755 /usr/local /bin/udp2raw-client
开机启动服务
1 sudo vim /lib/systemd/system/udp2raw.service
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =udp2raw clientAfter =network-on line.targetWants =network-on line.target[Service] Type =simpleExecStart =/usr/local/bin/udp2raw-clientRestart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start udp2raw.service sudo systemctl enable udp2raw.service
服务端配置
将 udp2raw_amd64 拷贝至 /usr/local/bin/ 下
1 sudo cp udp2raw_amd64 /usr/local /bin/
创建开机启动服务
1 sudo vim /lib/systemd/system/udp2raw.service
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =udp2raw serverAfter =network-on line.target kcptun.serviceWants =network-on line.target[Service] Type =simpleExecStart =/usr/local/bin/udp2raw_amd64 -s -l 0.0 .0.0 :4096 -r 127.0 .0.1 :8400 -a -k "你的KEY" Restart =on -abnormalRestartSec =5 [Install] WantedBy =multi-user.target
服务端 -a 会自动写 iptables 规则拦掉内核发的 RST,必须先装 iptables ,否则启动直接失败:sh: 1: iptables: not found。apt install iptables 即可。客户端不需要 -a(用 --lower-level 直达二层就没这个问题)。
启动并设置开机启动
1 2 3 sudo systemctl daemon-reload sudo systemctl start udp2raw.service sudo systemctl enable udp2raw.service
密钥必须两侧一致 这是最容易出错的地方,三组独立的值、各自成对:
位置
客户端
服务端
shadowsocks 密码
sslocal -k
ssserver -k
kcptun key / nocomp / mtu
--key --nocomp --mtu
"key" "nocomp" "mtu"
udp2raw key
-k
-k
任一处不一致的典型表现:**握手看起来成功,但一拿数据就 curl: (52) Empty reply from server**。
验证链路 1 2 3 4 5 6 7 8 9 10 11 sudo ss -lntup | grep -E '9872|30001|4096|8400|39201' sudo journalctl -u udp2raw -n 30 --no-pager curl -sS --socks5-hostname 127.0.0.1:9872 -o /dev/null -w '%{http_code}\n' https://www.google.com curl -sS --socks5-hostname 127.0.0.1:9872 https://ipinfo.io/ip
常见故障对照表
现象
原因
处理
curl: (52) Empty reply from server
key/密码两侧不一致
三组密钥逐个核对
改完 unit 但行为没变
只改了文件没重载
sudo systemctl daemon-reload && sudo systemctl restart 服务名
日志刷 huge packet,data len=1378 (>=1375)
kcptun mtu 太大
两端都设 mtu 1200
换了 WiFi / 断了重连后就不通
udp2raw 卡在死会话里,或源 IP 变了
sudo systemctl restart udp2raw
日志一直 client_tcp_handshake,反复 (re)sent tcp syn
被 TUN 接管路由,源地址选错
加 --lower-level auto --source-ip <局域网IP> --dev <网卡>
sh: 1: iptables: not found
用了 -a 但没装 iptables
apt install iptables,或去掉 -a
服务 status=203/EXEC
ExecStart 里的文件名写错
二进制实际名字是 server_linux_amd64 / client_linux_amd64
隧道通但网速极慢
热点/2.4G 空口本身就是瓶颈,或 MTU 溢出丢包
先按上面修 MTU,再换 5G 测
可选:加一个看门狗,隧道断了自动拉起 udp2raw。用 timer 每两分钟探一次 SOCKS5,不通就 restart。
谷歌设置shadowsock
首先下载谷歌插件 SwitchyOmega
auto switch 配置规则列表网址 https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt
proxy 配置代理协议 Socks5,代理服务器 127.0.0.1,代理端口为刚才 shadowsock 端口 9872
不代理列表配置
Chrome 新版本只支持 Manifest V3 扩展,SwitchyOmega 2 已从 Chrome 商店下架。Firefox 上仍可正常安装,Chrome 上可以换 SmartProxy 之类的替代品,或者直接用系统代理 / 终端方式。
终端配置科学上网 1 2 sudo apt install proxychains4 sudo vim /etc/proxychains4.conf
在 [ProxyList] 下增加(**协议名是 socks5,不是 sock4**):
几个要点:
段名是 [ProxyList],不是 [Proxylist](大小写敏感,写错整段不生效)。
默认那行 socks4 127.0.0.1 9050 是给 tor 用的,删掉或注释,保留你自己的 socks5 127.0.0.1 9872。
确认 proxy_dns 处于开启状态(新版默认就是开着的,行首没有 #),让域名也走代理解析,否则 DNS 泄漏且部分站点解析不到。
用的时候:proxychains4 curl https://www.google.com。
不想装 proxychains4 也可以单条命令指定:curl --socks5-hostname 127.0.0.1:9872 https://www.google.com。
换网络后必须做的一件事 因为 udp2raw 的源 IP 是启动时探测的,换了 WiFi、换了网段、或者从休眠唤醒之后:
1 sudo systemctl restart udp2raw
其它服务不用动(kcptun 和 sslocal 只是本地 TCP,不依赖网卡地址)。
懒人版:一键部署 deb 上面这些手工步骤可以打包成一个 deb,在任意 amd64 Debian/Ubuntu 上一条命令装完:
1 sudo dpkg -i vpn-tunnel_1.0.0_amd64.deb
包内包含三个静态二进制、自动探测网卡源 IP 的 wrapper、看门狗 timer,以及四个 systemd 单元。所有参数集中在 /etc/vpn-tunnel/tunnel.conf(权限 600,作为 conffile 在卸载时保留):
1 2 3 4 5 6 7 8 9 10 11 12 13 SERVER =服务器IPUDP2RAW_REMOTE_PORT =4096 UDP2RAW_KEY =你的KEYUDP2RAW_LOCAL_PORT =30001 KCP_LISTEN =:30001 KCP_REMOTE =127.0 .0.1 :30001 KCP_KEY =你的KEYKCP_CRYPT =salsa20KCP_MTU =1200 SS_LOCAL =127.0 .0.1 :9872 SS_SERVER =127.0 .0.1 :30001 SS_PASSWORD =你的密码SS_METHOD =aes-256 -gcm
改完配置 sudo systemctl restart udp2raw kcptun ss-server 即可。卸载用 sudo apt remove vpn-tunnel(保留配置)或 sudo dpkg --purge vpn-tunnel(连配置一起删)。