使用kcptun曲线访问Arukas容器

新版 Arukas 容器现状

2017 年我写了两篇介绍日本 Arukas 樱花容器服务的文章,那个时候主要用来跑 Shadowsocks 梯子服务。后来不知道是否因为国内用户蜂拥而至,Arukas 容器基本所有的 IP 地址都被封了,接着 Arukas 也停止提供服务,直到去年才恢复。最近住处的移动宽带不知何故连接一直使用的美国 VPS 速度很慢,因此我想着可以试试新版本 Arukas 容器的效果。

恢复后的新版 Arukas 服务直接把原来的账户都给删除了,用户都需要重新注册,实际使用还必须绑定有效的信用卡,容器配置可以参考其官网(需要爬墙):

https://arukas.io/en/#pricing

每个账户可以最多创建一个免费容器,免费容器配置如下:

  • 每个月 730 小时运行时间;
  • 0.1 vCPU;
  • 128 MB 内存;
  • 100 GB 流量;
  • 仍然不支持外部存储;
  • 支持绑定域名(针对 Endpoint);
  • 仍然只支持 Docker Hub 库,而且只支持修改 CMD 启动命令。

可以看到新版 Arukas 免费容器的配置是有点捉襟见肘,还好我也只是拿来访问 Google 服务之类的,对流量需求不大,如果你经常要看 YouTube 视频之类的,那就不用考虑 Arukas 容器咯。

按照原来写的 Arukas容器使用ge.tt替代Endpoint域名 文章重新部署 Shadowsocks 容器,我发现还算欣慰的是 Arukas 提供的 Endpoint 域名还没有被封锁,容器内 Web 服务器提供的内容可以通过 Endpoint 域名访问。

如果你只需要跑一个简单的静态网站,对资源和流量要求也不高的话,那 Arukas 容器也是挺不错的,毕竟还支持绑定自定义的域名。不过 Arukas 的 Endpoint 域名转发服务仍然只支持 HTTPS 访问,而且 Endpoint 地址应该只对容器开放的第一个内部端口有效,只支持 HTTP 协议,不支持 TCP 或者 UDP。如果用 Arukas 容器来跑动态网站,那有可能效果不太理想。

不出意料的是我准备搭梯子的时候,发现墙对 Arukas 封锁的比较彻底,测试了多个 IP 地址都无法正常连接,为此考虑修改原来的容器试试通过 kcptun 进行转发访问。

Shadowsocks 容器修改

我原来制作的 Arukas 专用 Shadowsocks 容器是基于 Baseimage-docker 镜像修改的,增加 kcptun 支持也很简单。访问 kcptun 的官方 GitHub release 页面:

https://github.com/xtaci/kcptun/releases

下载 Linux amd64 版本的 kcptun 程序,我们也只需要将服务端程序加到原来的 Shadowsocks 容器镜像中,并简单修改下 /etc/my_init.d/01_start_ss_ssh.sh 启动脚本(支持 kcptun 的修改已高亮显示):

#!/bin/bash

# Enable SSH
rm -f /etc/service/sshd/down
/etc/my_init.d/00_regen_ssh_host_keys.sh
touch /etc/service/sshd/down

# Setup SSH key
if [ "x$SSH_AUTHORIZED_KEYS" = "x" ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo "$SSH_AUTHORIZED_KEYS" | sed 's/\\n/\n/g' > ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' > /home/wwwroot/default/marathon.conf
if [ "x$MARATHON_HOST" != "x" ]; then
	getent hosts $MARATHON_HOST | awk '{print "MARATHON_HOST_IP="$1; exit;}' >> /home/wwwroot/default/marathon.conf
fi

start-stop-daemon -S -b -n tmp-httpd -d /home/wwwroot/default -x /usr/bin/python3 -- -m http.server 80

# Start ShadowSocks
env | grep '^SHADOWSOCKS_CFGS_' | awk -F '=' '{print $1;}' | while read T_NAME; do
	SS_NAME="${T_NAME:17}"
	echo "${!T_NAME}" > /etc/shadowsocks-libev/${SS_NAME}.json
	start-stop-daemon -n ss-$SS_NAME -x /usr/bin/ss-server -b -S -- -c /etc/shadowsocks-libev/${SS_NAME}.json -u --fast-open
done

# Start kcptun
env | grep '^KCPTUN_CFGS_' | awk -F '=' '{print $1;}' | while read T_NAME; do
	KCP_NAME="${T_NAME:12}"
	echo "${!T_NAME}" > /etc/kcptun/${KCP_NAME}.json
	start-stop-daemon -n kcp-$KCP_NAME -x /usr/bin/kcptun_server -b -S -- -c /etc/kcptun/${KCP_NAME}.json
done

if [ "x$GETT_TOKEN" != "x" ]; then
	if [ "x$HOME" = "x" ]; then
		export HOME="/root"
	fi
	echo -n "$GETT_TOKEN" > ~/.gett-token
	if [ "x$GETT_SHARE_NAME" != "x" ]; then
		python3 /usr/local/gett/uploader.py -l http://ge.tt/$GETT_SHARE_NAME | awk '{if (substr($5,1,13)=="http://ge.tt/") {print $5;}}' | xargs python3 /usr/local/gett/uploader.py --delete
		python3 /usr/local/gett/uploader.py -s http://ge.tt/$GETT_SHARE_NAME /home/wwwroot/default/marathon.conf
	fi
fi

exec /usr/sbin/sshd -D -e -u 0

新版支持 kcptun 访问 Shadowsocks 的 Arukas 专用容器安装包下载地址,仍然支持 SSH 登录以及通过 Endpoint 地址或者 ge.tt 分享获取容器当前地址和端口:

https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz

原有的 CMD 启动命令以及以 SHADOWSOCKS_CFGS_ 开头的 Shadowsocks 配置变量和 SSH_AUTHORIZED_KEYS SSH 证书变量配置都没有变化。

此次增加了以 KCPTUN_CFGS_ 开头的 kcptun 配置变量,当然别忘了容器端口配置中也得指定一个新的 UDP 端口给 kcptun 服务使用。

例如我现有的 Shadowsocks 服务配置变量:

SHADOWSOCKS_CFGS_xxx={ "server":"0.0.0.0", "server_port":17374, "local_port":1080, "password":"arukas-ss-svr", "timeout":30, "method":"aes-256-cfb" }

现在需要在 Arukas 容器中运行 kcptun 服务器进行 UDP 转发,可以添加一个 kcptun 配置变量(仍然是 JSON 格式,需要写成一行):

KCPTUN_CFGS_xxx = { "listen": ":29900", "target": "127.0.0.1:17374", "key": "arukas-kcp-svr", "crypt": "xor", "mode": "fast2", "mtu": 1350, "sndwnd": 128, "rcvwnd": 128, "datashard": 0, "parityshard": 0, "dscp": 46, "nocomp": true, "acknodelay": false, "nodelay": 0, "interval": 40, "resend": 2, "nc": 1, "sockbuf": 4194304, "keepalive": 10, "log": "/var/log/kcptun.log" }

这里我指定 kcptun 服务器绑定默认的 29900 UDP 端口(Arukas 容器端口配置中即需要开放 29900 UDP 端口),转发地址即指向本地的 Shadowsocks 服务器端口。

提示

上面贴出来的我使用的 kcptun 配置并不是最佳配置,只是由于我的 OpenWRT 路由器运算能力比较孱弱,避免出现路由器上的 kcptun 客户端导致 CPU 占用过高的问题。

kcptun 的配置稍微有点复杂,需要根据用户实际网络环境修改,这里我就不详细介绍了,请参考 GitHub 项目主页的说明。

Android kcptun 测试

我们可以首先用 Android 手机测试通过 kcptun 连接 Arukas 容器的 Shadowsocks 服务,在手机上安装 Shadowsocks App 和专用的 kcptun 插件。

安装完成之后 Shadowsocks 配置文件中就可以选择 kcptun 插件,需要注意你如果使用的是像我的 Nubia Z17 这种魔改版手机,可能需要在 手机管家 之类的系统设置中开启 kcptun 的自启动权限,防止出现 Shadowsocks App 无法启动 kcptun 的问题。

Shadowsocks App 连接的服务器地址也需要更换为 Arukas 容器实际地址和 kcptun 服务的外部访问端口,kcptun 插件的配置则保持与服务端一致即可,我的配置如下:

dscp=46;nocomp;mtu=1350;datashard=0;parityshard=0;mode=fast2;key=arukas-kcp-svr;crypt=xor

Android kcptun 插件的配置使用 key=value 的格式,中间以分号隔开,如果只有 key 没有 value 则表示启用该参数(true),具体配置参数可以点击 kcptun 插件的 ? 按钮查看详细说明。

OpenWRT 自动更新配置脚本

使用 kcptun 之后,OpenWRT 路由器上的 Shadowsocks 配置也不太一样了,例如我的 /etc/shadowsocks-arukas.json 配置文件就可以保持不变了(固定连接本地 kcptun 地址和端口):

{
	"server" : "127.0.0.1",
	"server_port" : "17374",
	"password": "arukas-ss-svr",
	"local_port": "1080",
	"timeout" : "30",
	"method": "aes-256-cfb"
}

相应的增加 kcptun 客户端的配置文件 /etc/kcptun-arukas.jsonkey 密码与容器中 kcptun 服务器密码一致,remoteaddr 就是容器 kcptun 服务 UDP 监听的外部访问地址和端口:

{
"localaddr": ":17374",
"remoteaddr": "",
"key": "arukas-kcp-svr",
"crypt": "xor",
"mode": "fast2",
"mtu": 1350,
"sndwnd": 128,
"rcvwnd": 128,
"datashard": 0,
"parityshard": 0,
"dscp": 46,
"nocomp": true,
"acknodelay": false,
"nodelay": 0,
"interval": 40,
"resend": 2,
"nc": 1,
"sockbuf": 4194304,
"keepalive": 10
}

为了支持 kcptun,我也稍微改了下 OpenWRT 路由器的 arukas-ss.sh 自动更新配置脚本,为了使用方便我把 kcptun 客户端的启动和停止操作也放到 /etc/init.d/shadowsocks 服务脚本中了,其它路由器请自行修改此脚本:

#!/bin/sh
ARUKAS_ENDPOINT=""
GETT_SHRNAME=""
RESTART_SHADOWSOCKS="no"

[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] && mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 5 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] && rm -f /tmp/.marathon.conf
	if [ "x$GETT_SHRNAME" != "x" ]; then
		T_FILEID=`curl -s -k -f http://api.ge.tt/1/shares/$GETT_SHRNAME | sed -e 's/^.*"fileid"[^:]*:[^"]*"//' -e 's/".*$//'`
		if [ "x$T_FILEID" != "x" ]; then
			curl -s -k -f -o /tmp/.marathon.conf -L -e "http://ge.tt/$GETT_SHRNAME" "http://api.ge.tt/1/files/$GETT_SHRNAME/$T_FILEID/blob?download"
			[ $? -eq 0 ] && break
		fi
	fi
	curl -s -k -f -o /tmp/.marathon.conf https://$ARUKAS_ENDPOINT.arukascloud.io/marathon.conf
	[ $? -eq 0 ] && break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo "Fetch server config after $IND tries."

if [ -f /tmp/.marathon.conf.bak ]; then
	cmp -s /tmp/.marathon.conf /tmp/.marathon.conf.bak
	if [ $? -eq 0 ]; then
		rm -f /tmp/.marathon.conf
		exit 0
	fi
fi

. /tmp/.marathon.conf 2>/dev/null
if [ "x$MARATHON_HOST" = "x" ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

if [ "x$MARATHON_HOST_IP" != "x" ]; then
	MARATHON_HOST="$MARATHON_HOST_IP"
fi

while [ $# -gt 2 ]; do
	CMD="echo \${MARATHON_PORT_$2}"
	TMP_PORT=`eval $CMD`

	if [ -f $1 -a "x$TMP_PORT" != "x" ]; then
		if [ "x$3" = "xshadowsocks" ]; then
			sed -i -e 's/"server"[^:]*:[^,]*,/"server" : "'$MARATHON_HOST'",/' -e 's/"server_port"[^:]*:[^,]*,/"server_port" : "'$TMP_PORT'",/' $1
			grep -q '^CONFIG.*=$1' /etc/init.d/shadowsocks
			[ $? -eq 0 ] && RESTART_SHADOWSOCKS="yes"
		elif [ "x$3" = "xkcptun" ]; then
			sed -i 's/"remoteaddr"[^:]*:[^,]*,/"remoteaddr" : "'$MARATHON_HOST':'$TMP_PORT'",/' $1
			grep -q '^KCPTUN_CONFIG.*=$1' /etc/init.d/shadowsocks
			[ $? -eq 0 ] && RESTART_SHADOWSOCKS="yes"
		fi
	fi
	shift
	shift
	shift
done

if [ "x$RESTART_SHADOWSOCKS" = "xyes" ]; then
	/etc/init.d/shadowsocks restart
fi

使用之前请修改脚本最上面的 ARUKAS_ENDPOINTGETT_SHRNAME 变量,分别为 Arukas 容器的 Endpoint 名(Arukas Endpoint 地址可访问的情况下建议优先使用)和 ge.tt 分享名。

为了区分 Shadowsocks 和 kcptun 配置文件,我对脚本调用方式也做了修改,增加了指定配置类型的参数(shadowsockskcptun),例如我的 crontab 配置:

30 * * * * /etc/arukas-ss.sh /etc/kcptun-arukas.json 29900 kcptun

这样路由器就可以自动更新 kcptun 客户端配置文件中的 remoteaddr 项了。

我的渣渣移动宽带环境下电脑通过路由器 kcptun 爬墙看 YouTube 视频效果如下:

Arukas 容器 Shadowsocks kcptun 速度

受限于路由器硬件的性能,Arukas 网络的 kcptun 速度并没有完全发挥出来,不过还是比原先的美国 VPS 要好多了,最后祝大家在开会的特殊阶段也能把梯子搭的开心。

发表评论





*