<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Soul Of Free Loop &#187; Shadowsocks</title>
	<atom:link href="https://zohead.com/archives/tag/shadowsocks/feed" rel="self" type="application/rss+xml" />
	<link>https://zohead.com</link>
	<description>Uranus Zhou&#039;s Blog</description>
	<lastBuildDate>Sat, 19 Jul 2025 15:42:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>使用kcptun曲线访问Arukas容器</title>
		<link>https://zohead.com/archives/arukas-kcptun/</link>
		<comments>https://zohead.com/archives/arukas-kcptun/#comments</comments>
		<pubDate>Wed, 06 Mar 2019 17:08:16 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[网络]]></category>
		<category><![CDATA[Arukas]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Endpoint]]></category>
		<category><![CDATA[kcptun]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[樱花]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1573</guid>
		<description><![CDATA[新版 Arukas 容器现状 2017 年我写了两篇介绍日本 Arukas 樱花容器服务的文章，那个时候主要用来跑 Shadowsocks 梯子服务。后来不知道是否因为国内用户蜂拥而至，Arukas 容器基本所有的 IP 地址都被封了，接着 Arukas 也停止提供服务，直到去年才恢复。最近住处的移动宽带不知何故连接一直使用的美国 VPS 速度很慢，因此我想着可以试试新版本 Arukas 容器的效果。 恢复后的新版 Arukas 服务直接把原来的账户都给删除了，用户都需要重新注册，实际使用还必须绑定有效的信用卡，容器配置可以参考其官网（需要爬墙）： https://arukas.io/en/# [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="new-arukas">新版 Arukas 容器现状</h2>
<p>2017 年我写了两篇介绍日本 <a href="https://zohead.com/archives/tag/arukas/">Arukas</a> 樱花容器服务的文章，那个时候主要用来跑 Shadowsocks 梯子服务。后来不知道是否因为国内用户蜂拥而至，Arukas 容器基本所有的 IP 地址都被封了，接着 Arukas 也停止提供服务，直到去年才恢复。最近住处的移动宽带不知何故连接一直使用的美国 VPS 速度很慢，因此我想着可以试试新版本 Arukas 容器的效果。</p>
<p>恢复后的新版 Arukas 服务直接把原来的账户都给删除了，用户都需要重新注册，实际使用还必须绑定有效的信用卡，容器配置可以参考其官网（需要爬墙）：</p>
<p><a href="https://arukas.io/en/#pricing" target="_blank">https://arukas.io/en/#pricing</a></p>
<p>每个账户可以最多创建一个免费容器，免费容器配置如下：</p>
<ul>
<li>每个月 730 小时运行时间；</li>
<li>0.1 vCPU；</li>
<li>128 MB 内存；</li>
<li>100 GB 流量；</li>
<li>仍然不支持外部存储；</li>
<li>支持绑定域名（针对 Endpoint）；</li>
<li>仍然只支持 Docker Hub 库，而且只支持修改 <code>CMD</code> 启动命令。</li>
</ul>
<p>可以看到新版 Arukas 免费容器的配置是有点捉襟见肘，还好我也只是拿来访问 Google 服务之类的，对流量需求不大，如果你经常要看 YouTube 视频之类的，那就不用考虑 Arukas 容器咯。</p>
<p>按照原来写的 <a href="https://zohead.com/archives/arukas-ge-tt/">Arukas容器使用ge.tt替代Endpoint域名</a> 文章重新部署 Shadowsocks 容器，我发现还算欣慰的是 Arukas 提供的 Endpoint 域名还没有被封锁，容器内 Web 服务器提供的内容可以通过 Endpoint 域名访问。</p>
<p>如果你只需要跑一个简单的静态网站，对资源和流量要求也不高的话，那 Arukas 容器也是挺不错的，毕竟还支持绑定自定义的域名。不过 Arukas 的 Endpoint 域名转发服务仍然只支持 HTTPS 访问，而且 Endpoint 地址应该只对容器开放的第一个内部端口有效，只支持 HTTP 协议，不支持 TCP 或者 UDP。如果用 Arukas 容器来跑动态网站，那有可能效果不太理想。</p>
<p>不出意料的是我准备搭梯子的时候，发现墙对 Arukas 封锁的比较彻底，测试了多个 IP 地址都无法正常连接，为此考虑修改原来的容器试试通过 kcptun 进行转发访问。</p>
<h2 id="arukas-shadowsocks-mod">Shadowsocks 容器修改</h2>
<p>我原来制作的 Arukas 专用 Shadowsocks 容器是基于 <a href="https://github.com/phusion/baseimage-docker" target="_blank">Baseimage-docker</a> 镜像修改的，增加 kcptun 支持也很简单。访问 kcptun 的官方 GitHub release 页面：</p>
<p><a href="https://github.com/xtaci/kcptun/releases" target="_blank">https://github.com/xtaci/kcptun/releases</a></p>
<p>下载 Linux amd64 版本的 kcptun 程序，我们也只需要将服务端程序加到原来的 Shadowsocks 容器镜像中，并简单修改下 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本（支持 kcptun 的修改已高亮显示）：</p>
<pre class="brush: bash; title: ; notranslate">
#!/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 [ &quot;x$SSH_AUTHORIZED_KEYS&quot; = &quot;x&quot; ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo &quot;$SSH_AUTHORIZED_KEYS&quot; | sed 's/\\n/\n/g' &gt; ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' &gt; /home/wwwroot/default/marathon.conf
if [ &quot;x$MARATHON_HOST&quot; != &quot;x&quot; ]; then
	getent hosts $MARATHON_HOST | awk '{print &quot;MARATHON_HOST_IP=&quot;$1; exit;}' &gt;&gt; /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=&quot;${T_NAME:17}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /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=&quot;${T_NAME:12}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /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 [ &quot;x$GETT_TOKEN&quot; != &quot;x&quot; ]; then
	if [ &quot;x$HOME&quot; = &quot;x&quot; ]; then
		export HOME=&quot;/root&quot;
	fi
	echo -n &quot;$GETT_TOKEN&quot; &gt; ~/.gett-token
	if [ &quot;x$GETT_SHARE_NAME&quot; != &quot;x&quot; ]; then
		python3 /usr/local/gett/uploader.py -l http://ge.tt/$GETT_SHARE_NAME | awk '{if (substr($5,1,13)==&quot;http://ge.tt/&quot;) {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
</pre>
<p>新版支持 kcptun 访问 Shadowsocks 的 Arukas 专用容器安装包下载地址，仍然支持 SSH 登录以及通过 Endpoint 地址或者 <a href="https://zohead.com/archives/ge-tt-cli-api/">ge.tt</a> 分享获取容器当前地址和端口：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz</a></p>
<p>原有的 <code>CMD</code> 启动命令以及以 <code>SHADOWSOCKS_CFGS_</code> 开头的 Shadowsocks 配置变量和 <code>SSH_AUTHORIZED_KEYS</code> SSH 证书变量配置都没有变化。</p>
<p>此次增加了以 <code>KCPTUN_CFGS_</code> 开头的 kcptun 配置变量，当然别忘了容器端口配置中也得指定一个新的 UDP 端口给 kcptun 服务使用。</p>
<p>例如我现有的 Shadowsocks 服务配置变量：</p>
<pre class="brush: jscript; title: ; notranslate">
SHADOWSOCKS_CFGS_xxx={ &quot;server&quot;:&quot;0.0.0.0&quot;, &quot;server_port&quot;:17374, &quot;local_port&quot;:1080, &quot;password&quot;:&quot;arukas-ss-svr&quot;, &quot;timeout&quot;:30, &quot;method&quot;:&quot;aes-256-cfb&quot; }
</pre>
<p>现在需要在 Arukas 容器中运行 kcptun 服务器进行 UDP 转发，可以添加一个 kcptun 配置变量（仍然是 JSON 格式，需要写成一行）：</p>
<pre class="brush: jscript; title: ; notranslate">
KCPTUN_CFGS_xxx = { &quot;listen&quot;: &quot;:29900&quot;, &quot;target&quot;: &quot;127.0.0.1:17374&quot;, &quot;key&quot;: &quot;arukas-kcp-svr&quot;, &quot;crypt&quot;: &quot;xor&quot;, &quot;mode&quot;: &quot;fast2&quot;, &quot;mtu&quot;: 1350, &quot;sndwnd&quot;: 128, &quot;rcvwnd&quot;: 128, &quot;datashard&quot;: 0, &quot;parityshard&quot;: 0, &quot;dscp&quot;: 46, &quot;nocomp&quot;: true, &quot;acknodelay&quot;: false, &quot;nodelay&quot;: 0, &quot;interval&quot;: 40, &quot;resend&quot;: 2, &quot;nc&quot;: 1, &quot;sockbuf&quot;: 4194304, &quot;keepalive&quot;: 10, &quot;log&quot;: &quot;/var/log/kcptun.log&quot; }
</pre>
<p>这里我指定 kcptun 服务器绑定默认的 29900 UDP 端口（Arukas 容器端口配置中即需要开放 29900 UDP 端口），转发地址即指向本地的 Shadowsocks 服务器端口。</p>
<blockquote>
<p><strong>提示</strong></p>
<p>上面贴出来的我使用的 kcptun 配置并不是最佳配置，只是由于我的 OpenWRT 路由器运算能力比较孱弱，避免出现路由器上的 kcptun 客户端导致 CPU 占用过高的问题。</p>
<p>kcptun 的配置稍微有点复杂，需要根据用户实际网络环境修改，这里我就不详细介绍了，请参考 <a href="https://github.com/xtaci/kcptun" target="_blank">GitHub</a> 项目主页的说明。</p>
</blockquote>
<h2 id="android-kcptun-test">Android kcptun 测试</h2>
<p>我们可以首先用 Android 手机测试通过 kcptun 连接 Arukas 容器的 Shadowsocks 服务，在手机上安装 <a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks" target="_blank">Shadowsocks</a> App 和专用的 <a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks.plugin.kcptun" target="_blank">kcptun</a> 插件。</p>
<p>安装完成之后 Shadowsocks 配置文件中就可以选择 kcptun 插件，需要注意你如果使用的是像我的 Nubia Z17 这种魔改版手机，可能需要在 <strong>手机管家</strong> 之类的系统设置中开启 kcptun 的自启动权限，防止出现 Shadowsocks App 无法启动 kcptun 的问题。</p>
<p>Shadowsocks App 连接的服务器地址也需要更换为 Arukas 容器实际地址和 kcptun 服务的外部访问端口，kcptun 插件的配置则保持与服务端一致即可，我的配置如下：</p>
<pre class="brush: plain; title: ; notranslate">
dscp=46;nocomp;mtu=1350;datashard=0;parityshard=0;mode=fast2;key=arukas-kcp-svr;crypt=xor
</pre>
<p>Android kcptun 插件的配置使用 <code>key=value</code> 的格式，中间以分号隔开，如果只有 <code>key</code> 没有 <code>value</code> 则表示启用该参数（true），具体配置参数可以点击 kcptun 插件的 <code>?</code> 按钮查看详细说明。</p>
<h2 id="openwrt-kcptun-script">OpenWRT 自动更新配置脚本</h2>
<p>使用 kcptun 之后，OpenWRT 路由器上的 Shadowsocks 配置也不太一样了，例如我的 <code>/etc/shadowsocks-arukas.json</code> 配置文件就可以保持不变了（固定连接本地 kcptun 地址和端口）：</p>
<pre class="brush: jscript; title: ; notranslate">
{
	&quot;server&quot; : &quot;127.0.0.1&quot;,
	&quot;server_port&quot; : &quot;17374&quot;,
	&quot;password&quot;: &quot;arukas-ss-svr&quot;,
	&quot;local_port&quot;: &quot;1080&quot;,
	&quot;timeout&quot; : &quot;30&quot;,
	&quot;method&quot;: &quot;aes-256-cfb&quot;
}
</pre>
<p>相应的增加 kcptun 客户端的配置文件 <code>/etc/kcptun-arukas.json</code>，<code>key</code> 密码与容器中 kcptun 服务器密码一致，<code>remoteaddr</code> 就是容器 kcptun 服务 UDP 监听的外部访问地址和端口：</p>
<pre class="brush: jscript; title: ; notranslate">
{
&quot;localaddr&quot;: &quot;:17374&quot;,
&quot;remoteaddr&quot;: &quot;&quot;,
&quot;key&quot;: &quot;arukas-kcp-svr&quot;,
&quot;crypt&quot;: &quot;xor&quot;,
&quot;mode&quot;: &quot;fast2&quot;,
&quot;mtu&quot;: 1350,
&quot;sndwnd&quot;: 128,
&quot;rcvwnd&quot;: 128,
&quot;datashard&quot;: 0,
&quot;parityshard&quot;: 0,
&quot;dscp&quot;: 46,
&quot;nocomp&quot;: true,
&quot;acknodelay&quot;: false,
&quot;nodelay&quot;: 0,
&quot;interval&quot;: 40,
&quot;resend&quot;: 2,
&quot;nc&quot;: 1,
&quot;sockbuf&quot;: 4194304,
&quot;keepalive&quot;: 10
}
</pre>
<p>为了支持 kcptun，我也稍微改了下 OpenWRT 路由器的 <code>arukas-ss.sh</code> 自动更新配置脚本，为了使用方便我把 kcptun 客户端的启动和停止操作也放到 <code>/etc/init.d/shadowsocks</code> 服务脚本中了，其它路由器请自行修改此脚本：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
ARUKAS_ENDPOINT=&quot;&quot;
GETT_SHRNAME=&quot;&quot;
RESTART_SHADOWSOCKS=&quot;no&quot;

[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] &amp;&amp; mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 5 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] &amp;&amp; rm -f /tmp/.marathon.conf
	if [ &quot;x$GETT_SHRNAME&quot; != &quot;x&quot; ]; then
		T_FILEID=`curl -s -k -f http://api.ge.tt/1/shares/$GETT_SHRNAME | sed -e 's/^.*&quot;fileid&quot;[^:]*:[^&quot;]*&quot;//' -e 's/&quot;.*$//'`
		if [ &quot;x$T_FILEID&quot; != &quot;x&quot; ]; then
			curl -s -k -f -o /tmp/.marathon.conf -L -e &quot;http://ge.tt/$GETT_SHRNAME&quot; &quot;http://api.ge.tt/1/files/$GETT_SHRNAME/$T_FILEID/blob?download&quot;
			[ $? -eq 0 ] &amp;&amp; break
		fi
	fi
	curl -s -k -f -o /tmp/.marathon.conf https://$ARUKAS_ENDPOINT.arukascloud.io/marathon.conf
	[ $? -eq 0 ] &amp;&amp; break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo &quot;Fetch server config after $IND tries.&quot;

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&gt;/dev/null
if [ &quot;x$MARATHON_HOST&quot; = &quot;x&quot; ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

if [ &quot;x$MARATHON_HOST_IP&quot; != &quot;x&quot; ]; then
	MARATHON_HOST=&quot;$MARATHON_HOST_IP&quot;
fi

while [ $# -gt 2 ]; do
	CMD=&quot;echo \${MARATHON_PORT_$2}&quot;
	TMP_PORT=`eval $CMD`

	if [ -f $1 -a &quot;x$TMP_PORT&quot; != &quot;x&quot; ]; then
		if [ &quot;x$3&quot; = &quot;xshadowsocks&quot; ]; then
			sed -i -e 's/&quot;server&quot;[^:]*:[^,]*,/&quot;server&quot; : &quot;'$MARATHON_HOST'&quot;,/' -e 's/&quot;server_port&quot;[^:]*:[^,]*,/&quot;server_port&quot; : &quot;'$TMP_PORT'&quot;,/' $1
			grep -q '^CONFIG.*='$1 /etc/init.d/shadowsocks
			[ $? -eq 0 ] &amp;&amp; RESTART_SHADOWSOCKS=&quot;yes&quot;
		elif [ &quot;x$3&quot; = &quot;xkcptun&quot; ]; then
			sed -i 's/&quot;remoteaddr&quot;[^:]*:[^,]*,/&quot;remoteaddr&quot; : &quot;'$MARATHON_HOST':'$TMP_PORT'&quot;,/' $1
			grep -q '^KCPTUN_CONFIG.*='$1 /etc/init.d/shadowsocks
			[ $? -eq 0 ] &amp;&amp; RESTART_SHADOWSOCKS=&quot;yes&quot;
		fi
	fi
	shift
	shift
	shift
done

if [ &quot;x$RESTART_SHADOWSOCKS&quot; = &quot;xyes&quot; ]; then
	/etc/init.d/shadowsocks restart
fi
</pre>
<p>使用之前请修改脚本最上面的 <code>ARUKAS_ENDPOINT</code> 和 <code>GETT_SHRNAME</code> 变量，分别为 Arukas 容器的 Endpoint 名（Arukas Endpoint 地址可访问的情况下建议优先使用）和 ge.tt 分享名。</p>
<p>为了区分 Shadowsocks 和 kcptun 配置文件，我对脚本调用方式也做了修改，增加了指定配置类型的参数（<code>shadowsocks</code> 或 <code>kcptun</code>），例如我的 crontab 配置：</p>
<pre class="brush: plain; title: ; notranslate">
30 * * * * /etc/arukas-ss.sh /etc/kcptun-arukas.json 29900 kcptun
</pre>
<p>这样路由器就可以自动更新 kcptun 客户端配置文件中的 <code>remoteaddr</code> 项了。</p>
<p>我的渣渣移动宽带环境下电脑通过路由器 kcptun 爬墙看 YouTube 视频效果如下：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442943/shadowsocks-kcptun-speed.png" alt="Arukas 容器 Shadowsocks kcptun 速度"></p>
<p>受限于路由器硬件的性能，Arukas 网络的 kcptun 速度并没有完全发挥出来，不过还是比原先的美国 VPS 要好多了，最后祝大家在开会的特殊阶段也能把梯子搭的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/arukas-kcptun/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arukas容器使用ge.tt替代Endpoint域名</title>
		<link>https://zohead.com/archives/arukas-ge-tt/</link>
		<comments>https://zohead.com/archives/arukas-ge-tt/#comments</comments>
		<pubDate>Sat, 06 May 2017 03:52:51 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Arukas]]></category>
		<category><![CDATA[Endpoint]]></category>
		<category><![CDATA[ge.tt]]></category>
		<category><![CDATA[gett-cli]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[ShadowsocksR]]></category>
		<category><![CDATA[容器]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1437</guid>
		<description><![CDATA[ge.tt 与 Endpoint 前面写了一篇介绍日本 Arukas 樱花容器及使用其 Endpoint 域名的文章，目前我在 Arukas 上面跑了一个 Shadowsocks 容器用于路由器自动爬墙。不过还是发现如果 Arukas 容器的开放端口里开启了 UDP 端口（给 OpenWRT 路由器上的 ss-tunnel 用于转发解析被封锁的域名），这种情况下 Arukas 的 Endpoint 地址就基本没办法正常访问了。文章中我写的 OpenWRT 下自动获取 Arukas 容器 Shadowsocks 配置的脚本也经常出错，用起来还是不太方便。 刚好之前为了给其他人分享文件，我还写了一 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="gett-and-endpoint">ge.tt 与 Endpoint</h2>
<p>前面写了一篇介绍日本 <a href="https://zohead.com/archives/arukas-container/">Arukas 樱花容器</a>及使用其 Endpoint 域名的文章，目前我在 Arukas 上面跑了一个 Shadowsocks 容器用于路由器自动爬墙。不过还是发现如果 Arukas 容器的开放端口里开启了 UDP 端口（给 OpenWRT 路由器上的 <code>ss-tunnel</code> 用于转发解析被封锁的域名），这种情况下 Arukas 的 Endpoint 地址就基本没办法正常访问了。文章中我写的 OpenWRT 下自动获取 Arukas 容器 Shadowsocks 配置的脚本也经常出错，用起来还是不太方便。</p>
<p>刚好之前为了给其他人分享文件，我还写了一篇介绍 <a href="https://zohead.com/archives/ge-tt-cli-api/">ge.tt 文件分享 API</a> 的文章，就想到既然 Endpoint 地址访问容易出错，那可以在 Arukas Shadowsocks 容器里使用 ge.tt 的 Python CLI 将容器的当前地址和外部端口配置文件上传到指定的 ge.tt 分享地址，这样 OpenWRT 系统里也能很方便地通过分享地址更新配置文件了。</p>
<h2 id="arukas-container-mod">Arukas 容器修改</h2>
<p>这里的 Arukas 容器系统我使用的还是最新 baseimage 系统，增加了 <code>shadowsocks-libev</code> 服务器程序，并将 <code>gett-cli</code> 工具集成到 baseimage 系统，然后将 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本修改为：</p>
<pre class="brush: bash; title: ; notranslate">
#!/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 [ &quot;x$SSH_AUTHORIZED_KEYS&quot; = &quot;x&quot; ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo &quot;$SSH_AUTHORIZED_KEYS&quot; | sed 's/\\n/\n/g' &gt; ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' &gt; /home/wwwroot/default/marathon.conf
if [ &quot;x$MARATHON_HOST&quot; != &quot;x&quot; ]; then
	getent hosts $MARATHON_HOST | awk '{print &quot;MARATHON_HOST_IP=&quot;$1; exit;}' &gt;&gt; /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=&quot;${T_NAME:17}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /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

if [ &quot;x$GETT_TOKEN&quot; != &quot;x&quot; ]; then
	if [ &quot;x$HOME&quot; = &quot;x&quot; ]; then
		export HOME=&quot;/root&quot;
	fi
	echo -n &quot;$GETT_TOKEN&quot; &gt; ~/.gett-token
	if [ &quot;x$GETT_SHARE_NAME&quot; != &quot;x&quot; ]; then
		python3 /usr/local/gett/uploader.py -l http://ge.tt/$GETT_SHARE_NAME | awk '{if (substr($5,1,13)==&quot;http://ge.tt/&quot;) {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
</pre>
<p>这里增加了两个 ge.tt 文件分享服务相关的环境变量，通过 Docker 容器的 ENV 环境变量指定：</p>
<ul>
<li><code>GETT_TOKEN</code> <br />
在某台设备上使用 <code>gett-cli</code> 工具登录成功之后就能看到 <code>~/.gett-token</code> 文件中的 Refresh Token 内容；</li>
<li><code>GETT_SHARE_NAME</code> <br />
预先创建好固定的 ge.tt 分享名（例如：<code>8D95lij2</code>），可以在 ge.tt 网页中上传文件创建，也可以用 <code>gett-cli</code> 工具创建。</li>
</ul>
<p>如果容器的 ENV 列表里有这两个环境变量，启动脚本会自动将 Arukas 容器的当前地址和外部端口配置文件 <code>marathon.conf</code> 上传到指定的 ge.tt 分享地址。</p>
<h2 id="use-shadowsocks-container">使用 Shadowsocks 容器</h2>
<p>容器的 <code>CMD</code> 指令值以及其它 SSH 公钥和 Shadowsocks 服务器 JSON 配置文件环境变量与 <a href="https://zohead.com/archives/arukas-container/">Arukas 容器</a>文章中介绍的相同，可以根据需要自行配置。</p>
<p>我修改后的 Arukas 上支持 ge.tt 并适用于 baseimage 系统的 Shadowsocks 服务器安装包可以从这里下载：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz</a></p>
<p>另外我还制作了一个 ShadowsocksR 服务器安装包，有需要的朋友可以下载测试看看，由于 baseimage 系统已经自带了 Python 3 环境，因此 ShadowsocksR 服务器安装包体积也要小一些：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ssr.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ssr.tar.gz</a></p>
<p>对于容器 ENV 列表中以 <code>SHADOWSOCKS_CFGS_</code> 开头的变量，启动脚本会自动在 <code>/etc/shadowsocks-libev</code> 目录（对于 ShadowsocksR 是 <code>/etc/shadowsocks</code> 目录）下生成 Shadowsocks 或 ShadowsocksR 服务器配置文件，配置文件内容就是该 JSON 格式变量的值。</p>
<p>例如我的 Arukas 容器配置中的 ShadowsocksR 环境变量：</p>
<pre class="brush: bash; title: ; notranslate">
SHADOWSOCKS_CFGS_xxx = { &quot;server&quot;:&quot;0.0.0.0&quot;, &quot;server_port&quot;:8113, &quot;local_port&quot;:1080, &quot;password&quot;:&quot;ssr-pass&quot;, &quot;timeout&quot;:30, &quot;method&quot;:&quot;aes-128-ctr&quot;, &quot;protocol&quot; : &quot;auth_aes128_md5&quot;, &quot;obfs&quot; : &quot;http_simple&quot; }
</pre>
<p>当然对于 ShadowsocksR 容器也需要相应地将 <code>CMD</code> 启动指令改为：</p>
<pre class="brush: bash; title: ; notranslate">
/sbin/my_init -- sh -c 'curl -o /arukas-baseimage-xenial-ssr.tar.gz https://zohead.com/downloads/arukas-baseimage-xenial-ssr.tar.gz &amp;&amp; tar -C / -xzf /arukas-baseimage-xenial-ssr.tar.gz &amp;&amp; /etc/my_init.d/01_start_ss_ssh.sh'
</pre>
<h2 id="openwrt-shadowsocks-script">OpenWRT 自动更新配置脚本</h2>
<p>为了能支持从 ge.tt 分享地址下载更新 Shadowsocks 配置，我对 OpenWRT 路由器上的 <code>arukas-ss.sh</code> 脚本也做了修改：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
ARUKAS_ENDPOINT=&quot;&quot;
GETT_SHRNAME=&quot;&quot;

[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] &amp;&amp; mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 5 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] &amp;&amp; rm -f /tmp/.marathon.conf
	if [ &quot;x$GETT_SHRNAME&quot; != &quot;x&quot; ]; then
		T_FILEID=`curl -s -k -f http://api.ge.tt/1/shares/$GETT_SHRNAME | sed -e 's/^.*&quot;fileid&quot;[^:]*:[^&quot;]*&quot;//' -e 's/&quot;.*$//'`
		if [ &quot;x$T_FILEID&quot; != &quot;x&quot; ]; then
			curl -s -k -f -o /tmp/.marathon.conf -L -e &quot;http://ge.tt/$GETT_SHRNAME&quot; &quot;http://api.ge.tt/1/files/$GETT_SHRNAME/$T_FILEID/blob?download&quot;
			[ $? -eq 0 ] &amp;&amp; break
		fi
	fi
	curl -s -k -f -o /tmp/.marathon.conf https://$ARUKAS_ENDPOINT.arukascloud.io/marathon.conf
	[ $? -eq 0 ] &amp;&amp; break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo &quot;Fetch server config after $IND tries.&quot;

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&gt;/dev/null
if [ &quot;x$MARATHON_HOST&quot; = &quot;x&quot; ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

while [ $# -gt 1 ]; do
	CMD=&quot;echo \${MARATHON_PORT_$2}&quot;
	SS_PORT=`eval $CMD`

	if [ -f $1 -a &quot;x$SS_PORT&quot; != &quot;x&quot; ]; then
		if [ &quot;x$MARATHON_HOST_IP&quot; != &quot;x&quot; ]; then
			MARATHON_HOST=&quot;$MARATHON_HOST_IP&quot;
		fi
		sed -i -e 's/&quot;server&quot;[^:]*:[^,]*,/&quot;server&quot; : &quot;'$MARATHON_HOST'&quot;,/' -e 's/&quot;server_port&quot;[^:]*:[^,]*,/&quot;server_port&quot; : &quot;'$SS_PORT'&quot;,/' $1
	fi
	shift
	shift
done

if [ &quot;x$RESTART_SHADOWSOCKS&quot; != &quot;xno&quot; ]; then
	/etc/init.d/shadowsocks restart
fi
</pre>
<p>使用之前请先根据需要修改脚本最上面的 <code>ARUKAS_ENDPOINT</code> 和 <code>GETT_SHRNAME</code> 变量（一般指定其中一个即可），分别为 Arukas 容器的 Endpoint 名和 ge.tt 分享名，脚本会分别尝试通过 ge.tt 分享地址和 Arukas Endpoint 地址下载容器的 <code>marathon.conf</code> 配置文件。</p>
<p>为了使用简单性考虑，修改后的 <code>arukas-ss.sh</code> 脚本是直接通过 <code>/etc/init.d/shadowsocks</code> 服务脚本重启 OpenWRT 上的 Shadowsocks 客户端程序。该脚本的使用方法也请参考我之前写的介绍 Arukas 容器及 Endpoint 的文章。</p>
<p>最后祝大家心中无墙，玩的开心 ^_^。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/arukas-ge-tt/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Arukas樱花Docker容器及Endpoint体验</title>
		<link>https://zohead.com/archives/arukas-container/</link>
		<comments>https://zohead.com/archives/arukas-container/#comments</comments>
		<pubDate>Fri, 31 Mar 2017 16:17:46 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Arukas]]></category>
		<category><![CDATA[Endpoint]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[樱花]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1408</guid>
		<description><![CDATA[Arukas 容器介绍 之前我在了解目前主流的容器服务商时除了 IBM Bluemix 还知道了日本 Arukas 容器，不过一直都没有测试的机会，最近 Arukas 难得给我发了注册通过的邮件，最新的政策显示免费测试期会延长到 2017 年 6 月 30 日（未来收费策略待定）。 下面的基本操作都在 Arukas 控制面板： https://app.arukas.io/ Arukas 容器限制 Arukas 容器还处于免费测试阶段，有一些限制需要先说明： 不支持特权容器，无法使用 TUN/TAP 设备（目前的容器服务商基本都不支持）； 没有固定公网 IP 地址，容器可能每隔几天甚至几个小时就 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="arukas-intro">Arukas 容器介绍</h2>
<p>之前我在了解目前主流的容器服务商时除了 IBM Bluemix 还知道了日本 Arukas 容器，不过一直都没有测试的机会，最近 Arukas 难得给我发了注册通过的邮件，最新的政策显示免费测试期会延长到 2017 年 6 月 30 日（未来收费策略待定）。</p>
<p>下面的基本操作都在 Arukas 控制面板：</p>
<p><a href="https://app.arukas.io/" target="_blank">https://app.arukas.io/</a></p>
<h3 id="arukas-limits">Arukas 容器限制</h3>
<p>Arukas 容器还处于免费测试阶段，有一些限制需要先说明：</p>
<ul>
<li>不支持特权容器，无法使用 TUN/TAP 设备（目前的容器服务商基本都不支持）；</li>
<li>没有固定公网 IP 地址，容器可能每隔几天甚至几个小时就会重启；</li>
<li>配置的容器内部端口会被映射到随机的外部端口；</li>
<li>自定义 Endpoint 域名只能以 HTTPS 方式访问，对应的容器内部端口只支持 HTTP 协议（下面会详细介绍）；</li>
<li>不支持使用自定义的 <code>Dockerfile</code> 文件构建容器，只能使用 Docker hub 上的镜像；</li>
<li>暂时不支持外部存储，因此容器里无法保存任何数据，每次重启容器数据会全部丢失；</li>
<li>创建容器时只能配置 <code>Dockerfile</code> 中的 <code>ENV</code>（环境变量）和 <code>CMD</code>（启动执行命令）指令，不支持 <code>RUN</code> 及 <code>ENTRYPOINT</code> 等其它指令。</li>
</ul>
<h3 id="about-endpoint">关于 Endpoint</h3>
<p>通过参考 Arukas 日文版帮助文档，我们可以得知虽然 Arukas 容器没有固定的公网 IP 地址，容器开放的内部端口每次启动也都被映射到随机的外部端口，但容器的 Endpoint 地址是始终固定不变的，类似于这样：</p>
<pre class="brush: plain; title: ; notranslate">

https://xxx.arukascloud.io/

</pre>
<p>经过测试我发现容器的 Endpoint 地址必须以 HTTPS 方式访问（HTTP 访问会直接返回 Connection refused），Endpoint 地址只对容器开放的第一个内部端口有效，而且该内部端口只支持 HTTP 协议，不支持 TCP 或者 UDP。</p>
<p>用户访问 Endpoint 子域名地址时并不是直接访问容器的当前公网地址，而是访问 Arukas 提供的 HAProxy 负载均衡服务器，HAProxy 负责转发并均衡容器下多个实例的 HTTP 请求，其网络拓扑图大概如下所示：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370568/arukas-endpoint.png" alt="Arukas Endpoint 网络拓扑图" title="Arukas Endpoint 网络拓扑图"></p>
<blockquote>
<p><strong>提示</strong></p>
<p>Arukas 官网上对 Endpoint 的说明遗漏了比较重要的一点：如果容器配置里开启了多个对外开放的内部端口，那么 Endpoint 请求转发只会在所有这些端口的服务都已经运行的情况下才有效。</p>
</blockquote>
<p>这样 Arukas 就能够在有限的服务器（内部端口映射到随机外部端口）和公网 IP 地址（固定 Endpoint 地址）情况下提供尽量多的容器访问支持。</p>
<h2 id="build-container">构建容器</h2>
<p>从上面的介绍来看虽然 Arukas 容器有很多体验不太好的限制，但其所在的樱花机房线路还是相当有吸引力的，立马准备建立容器看看运行效果。</p>
<p>为了测试 Arukas 容器的运行效果，我没有使用一些做好的通用 SSH 系统（例如：centos-ssh）或者 Shadowsocks 系统镜像，本文还是用的之前捣鼓过的 <a href="https://github.com/phusion/baseimage-docker" target="_blank">baseimage-docker</a> Docker 镜像。</p>
<h3 id="baseimage-docker-problem">baseimage-docker 的问题</h3>
<p>baseimage-docker 镜像虽然用起来很方便，支持轻量级的 <a href="http://smarden.org/runit/" target="_blank"><code>runit</code></a> 服务管理方案，但该镜像默认并没有开启 SSH 登录，如果需要开启 SSH 服务器或者执行自定义命令都需要修改 <code>Dockerfile</code> 文件中的 <code>RUN</code> 指令，具体可以参考该项目 GitHub 主页。</p>
<p>然而 Arukas 容器并不支持使用 <code>RUN</code> 命令配置执行自定义命令，也不能保存任何数据，因此 SSH 登录和执行自定义命令的问题需要通过其它方法解决。</p>
<p>幸好 baseimage-docker 还支持通过 <code>CMD</code> 指令开启运行 <a href="https://github.com/phusion/baseimage-docker#oneshot" target="_blank">one-shot command</a> 单次命令支持，对应的 <code>CMD</code> 指令类似这样：</p>
<pre class="brush: bash; title: ; notranslate">
/sbin/my_init -- COMMAND ARGUMENTS ...
</pre>
<p>容器系统的运行流程就相当于：</p>
<ul>
<li>运行所有启动脚本，例如 <code>/etc/my_init.d/*</code> 及 <code>/etc/rc.local</code>；</li>
<li>启动所有 <code>runit</code> 服务；</li>
<li>运行 <code>my_init</code> 参数中指定的自定义命令；</li>
<li>自定义命令退出之后即停止所有 <code>runit</code> 服务。</li>
</ul>
<p>因此我们可以在单次命令参数上做文章，实现开启 SSH 服务器、安装需要的软件并启动附加的服务。</p>
<h3 id="container-config">容器基本配置</h3>
<p>下面是我在 Arukas 控制面板建立的一个 Shadowsocks 服务器容器的配置：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370567/arukas-docker-config.png" alt="Arukas 容器配置" title="Arukas Endpoint 容器配置"></p>
<ul>
<li><strong>Image</strong> 我使用的是最新的 baseimage-docker 镜像：<code>phusion/baseimage:0.9.19</code>；</li>
<li><strong>Instances</strong> 一般就用默认的一个实例；</li>
<li><strong>Memory</strong> 可以根据需要选择 256 MB 或者 512 MB；</li>
<li><strong>Endpoint</strong> 指定 Endpoint 子域名地址；</li>
<li><strong>Port</strong> 设置里可以将容器中最多 20 个 TCP 或者 UDP 端口对外开放，我填了 80、22 外加一个 Shadowsocks 服务器端口，需要注意的就是上面的固定 Endpoint 地址只支持第一个端口；</li>
<li><strong>ENV</strong> 环境变量根据需要设置，我在这里指定了 SSH key 和 Shadowsocks 服务器配置；</li>
<li>
<p><strong>CMD</strong> 设置比较关键，我建立的 Shadowsocks 测试容器是这样的：</p>
<pre class="brush: bash; title: ; notranslate">
/sbin/my_init -- sh -c 'curl -o /arukas-baseimage-xenial-ss.tar.gz https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz &amp;&amp; tar -C / -xzf /arukas-baseimage-xenial-ss.tar.gz &amp;&amp; /etc/my_init.d/01_start_ss_ssh.sh'
</pre>
</li>
</ul>
<p>我制作了一个适用于最新 baseimage 系统的 Shadowsocks 服务器安装包：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz</a></p>
<p>容器系统启动时会自动将安装包下载到根目录下解压缩，然后执行其中的 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本：</p>
<pre class="brush: bash; title: ; notranslate">
#!/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 [ &quot;x$SSH_AUTHORIZED_KEYS&quot; = &quot;x&quot; ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo &quot;$SSH_AUTHORIZED_KEYS&quot; | sed 's/\\n/\n/g' &gt; ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' &gt; /home/wwwroot/default/marathon.conf
if [ &quot;x$MARATHON_HOST&quot; != &quot;x&quot; ]; then
	getent hosts $MARATHON_HOST | awk '{print &quot;MARATHON_HOST_IP=&quot;$1; exit;}' &gt;&gt; /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=&quot;${T_NAME:17}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /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

exec /usr/sbin/sshd -D -e -u 0
</pre>
<p>该启动脚本的执行流程如下：</p>
<ul>
<li>首先启用 SSH 服务器，并产生 SSH host key；</li>
<li>如果容器配置的 <strong>ENV</strong> 环境变量里存在 <code>SSH_AUTHORIZED_KEYS</code> 变量，那么就使用这个变量的内容作为 SSH 公钥（容器配置截图里我就使用此方法指定自定义公钥），如果不存在则使用 baseimage 提供的默认公钥；</li>
<li>接着获取 Arukas 容器的当前临时域名、公网 IP 地址以及每个内部端口映射等内容输出到 <code>/home/wwwroot/default</code> Web 服务器目录下的 <code>marathon.conf</code> 文件；</li>
<li>在默认的 80 端口启动 Web 服务器以支持 Endpoint 地址访问；</li>
<li>
<p>遍历容器配置的所有 <strong>ENV</strong> 环境变量，如果存在以 <code>SHADOWSOCKS_CFGS_</code> 开头的变量，就在 <code>/etc/shadowsocks-libev</code> 目录下生成 Shadowsocks 服务器配置文件，配置文件内容就是该变量的值。</p>
<p>例如我使用的一个 Shadowsocks 配置变量（将 Shadowsocks 服务器的 JSON 配置写成一行）：</p>
<pre class="brush: jscript; title: ; notranslate">
SHADOWSOCKS_CFGS_xxx={ &quot;server&quot;:&quot;0.0.0.0&quot;, &quot;server_port&quot;:17374, &quot;local_port&quot;:1080, &quot;password&quot;:&quot;arukas-ss-svr&quot;, &quot;timeout&quot;:30, &quot;method&quot;:&quot;aes-256-cfb&quot; }
</pre>
<p>这样就会自动产生 <code>/etc/shadowsocks-libev/xxx.json</code> 配置文件；</p>
</li>
<li>依次启动 <strong>ENV</strong> 环境变量里指定的所有 Shadowsocks 服务器（可以指定多个以 <code>SHADOWSOCKS_CFGS_</code> 开头的变量）；</li>
<li>最后以前台方式启动 SSH 服务器，这样就能实现 SSH 远程登录，而且 baseimage 容器也不会退出。</li>
</ul>
<h3 id="container-status">容器运行状态</h3>
<p>Arukas 容器启动运行成功之后，你可以在控制面板里查看运行状态：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370567/arukas-docker-status.png" alt="Arukas 容器运行状态" title="Arukas Endpoint 容器运行状态"></p>
<p>这里可以看到容器的 Endpoint 地址、用于直接访问容器的临时域名和映射的外部端口等信息。</p>
<p>容器启动之后会将当前的临时域名、内部端口映射等信息输出到系统环境变量中，这样上面的 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本才能直接获取到这些信息，有兴趣的朋友可以在容器中确认：</p>
<pre class="brush: bash; title: ; notranslate">
root@02a78258745b:~# env | grep -E '^MARATHON|MESOS'
MESOS_TASK_ID=db89b5a5-7df0-49f0-b5d4-47d6406abbd8.6cccf318-080c-11e7-aca2-0242a39fa0e7
MARATHON_PORT0=31198
MARATHON_PORT1=31689
MARATHON_PORT=31198
MARATHON_APP_RESOURCE_DISK=0.0
MARATHON_APP_RESOURCE_MEM=32.0
MARATHON_APP_LABEL_HAPROXY_0_VHOST=gloomy-golick-3736.arukascloud.io
MARATHON_APP_RESOURCE_GPUS=0
MESOS_CONTAINER_NAME=mesos-eb1747b8-0843-4061-bc0e-9cd1b5347ee2-S9.d07c30b6-51b1-44ca-a453-d4302ec08d2e
MARATHON_APP_LABEL_HAPROXY_GROUP=external
MARATHON_HOST=seaof-153-125-239-206.jp-tokyo-27.arukascloud.io
MARATHON_APP_LABELS=HAPROXY_GROUP HAPROXY_0_VHOST
MARATHON_APP_ID=/db89b5a5-7df0-49f0-b5d4-47d6406abbd8
MARATHON_APP_DOCKER_IMAGE=phusion/baseimage:0.9.19
MARATHON_APP_VERSION=2017-03-13T16:45:10.089Z
MARATHON_PORTS=31198,31689
MARATHON_APP_RESOURCE_CPUS=0.01
MARATHON_PORT_80=31198
MARATHON_PORT_22=31689
MESOS_SANDBOX=/mnt/mesos/sandbox
</pre>
<p>我们可以看看 Arukas 容器的服务器信息，其使用的是 CoreOS 系统（内核版本为 4.9.9）：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# uname -a
Linux 837bc28c1c36 4.9.9-coreos-r1 #1 SMP Tue Mar 28 22:27:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
</pre>
<p>内存是所有容器一起共享的（如果容器使用的内存超过配置中的限制太多会被重启）：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# free -m
              total        used        free      shared  buff/cache   available
Mem:          24115        4300        1520         715       18295       17563
Swap:          4095          24        4071
</pre>
<p>CPU 配置还算给力，使用的是 8 个 Xeon E5-2650：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# grep -E '^processor|physical id|model name' /proc/cpuinfo
processor	: 0
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 0
processor	: 1
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 1
processor	: 2
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 2
processor	: 3
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 3
processor	: 4
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 4
processor	: 5
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 5
processor	: 6
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 6
processor	: 7
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 7
</pre>
<p>只是容器内核对文件系统的支持比较坑爹：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# cat /proc/filesystems
nodev	sysfs
nodev	rootfs
nodev	tmpfs
nodev	bdev
nodev	proc
nodev	cpuset
nodev	cgroup
nodev	cgroup2
nodev	devtmpfs
nodev	debugfs
nodev	tracefs
nodev	securityfs
nodev	sockfs
nodev	bpf
nodev	pipefs
nodev	ramfs
nodev	hugetlbfs
nodev	devpts
nodev	pstore
nodev	mqueue
nodev	selinuxfs
nodev	autofs
	squashfs
	iso9660
	ext3
	ext2
	ext4
nodev	overlay
</pre>
<p>不支持 NFS 挂载远程目录，也不支持 FUSE 用户层文件系统来实现挂载 Amazon S3 存储之类的，这对于目前还不支持外部存储的 Arukas 容器来说实在不算友好。</p>
<h2 id="use-shadowsocks-container">使用 Shadowsocks 容器</h2>
<h3 id="shadowsocks-speed">Shadowsocks 效果</h3>
<p>客户端使用上面指定的 Shadowsocks 服务器配置就可以爬墙上网了，当然使用前需要将 Shadowsocks 服务器地址更换为 Arukas 容器的临时域名，并将服务器端口改为当前映射出来的外部端口（不能直接使用内部端口）。</p>
<p>这个是我在宿舍江苏移动宽带网络下观看 Youtube 1080p 视频的效果，8 Mbps 的速度看起来还是比较给力的：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370582/arukas-ss-speed.png" alt="Arukas Shadowsocks 速度" title="Arukas Shadowsocks 速度"></p>
<p>换到南京电信网络进行路由追踪，可以看到 ping 值还不到 50 ms：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370582/arukas-ip-route.png" alt="Arukas 容器路由追踪" title="Arukas 容器路由追踪" width="640" height="526"></p>
<h3 id="openwrt-shadowsocks-script">OpenWRT 自动更新 Shadowsocks 配置</h3>
<p>由于 Arukas 容器的外网地址和端口在每次启动时都不是固定的，容器重启后 Shadowsocks 客户端都需要获取当前临时域名和外部端口，这样用起来还是不太方便。特别对于我这种需要 OpenWRT 路由器直接翻墙的用户来说，每次修改 OpenWRT 设置就太麻烦了。</p>
<p>好消息就是 Arukas 容器的 Endpoint 地址还是固定的，我写的启动脚本也自动将容器当前的临时域名、公网 IP 地址、所有外部端口都输出到文件了，可以直接通过 Endpoint 地址访问。</p>
<p>因此我又专门写了一个适用于 OpenWRT 系统的更新 Arukas 容器配置的脚本：<code>arukas-ss.sh</code>，可添加到路由器的 Shadowsocks 服务脚本中，也可以设置成定时任务：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] &amp;&amp; mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 20 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] &amp;&amp; rm -f /tmp/.marathon.conf
	curl -s -k -f -o /tmp/.marathon.conf https://zohead-server.arukascloud.io/marathon.conf
	[ $? -eq 0 ] &amp;&amp; break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo &quot;Fetch server config after $IND tries.&quot;

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&gt;/dev/null
if [ &quot;x$MARATHON_HOST&quot; = &quot;x&quot; ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

while [ $# -gt 1 ]; do
	CMD=&quot;echo \${MARATHON_PORT_$2}&quot;
	SS_PORT=`eval $CMD`

	if [ -f $1 -a &quot;x$SS_PORT&quot; != &quot;x&quot; ]; then
		if [ &quot;x$MARATHON_HOST_IP&quot; != &quot;x&quot; ]; then
			MARATHON_HOST=&quot;$MARATHON_HOST_IP&quot;
		fi
		sed -i -e 's/&quot;server&quot;[^:]*:[^,]*,/&quot;server&quot; : &quot;'$MARATHON_HOST'&quot;,/' -e 's/&quot;server_port&quot;[^:]*:[^,]*,/&quot;server_port&quot; : &quot;'$SS_PORT'&quot;,/' $1
		SS_PID=`pgrep -f &quot;ss-redir -c $1&quot;`
		if [ $? -eq 0 ]; then
			kill $SS_PID &gt;/dev/null 2&gt;&amp;1
			kill -9 $SS_PID &gt;/dev/null 2&gt;&amp;1
			start-stop-daemon -x /usr/bin/ss-redir -b -S -- -c $1 -b 0.0.0.0
		fi
	fi
	shift
	shift
done
</pre>
<p><code>arukas-ss.sh</code> 脚本的使用方法为：</p>
<pre class="brush: bash; title: ; notranslate">
arukas-ss.sh shadowsocks-1.json 17374 shadowsocks-2.json 2233 ... ...
</pre>
<p>第一个参数为 Shadowsocks 客户端 JSON 配置文件的完整路径，第二个参数为该文件对应的 Arukas Shadowsocks 服务器配置的内部监听端口号，<code>arukas-ss.sh</code> 脚本支持多个本地 Shadowsocks 配置文件和服务器内部监听端口号，依次类推即可。</p>
<p>使用前需要替换 <code>arukas-ss.sh</code> 脚本中的 Endpoint 地址，考虑到 Arukas 容器目前的 Endpoint 访问还不太稳定的情况，脚本里也加了多次访问尝试，我的 Endpoint 地址是这样：</p>
<pre class="brush: plain; title: ; notranslate">

https://zohead-server.arukascloud.io/marathon.conf

</pre>
<p>另外可以修改 OpenWRT 的定时任务配置实现自动更新，例如在 <code>/etc/crontabs/root</code> 文件中增加一行：</p>
<pre class="brush: plain; title: ; notranslate">
30 * * * * /etc/arukas-ss.sh /etc/shadowsocks.json 17374
</pre>
<p>这就表示在每个小时的第 30 分钟执行 <code>arukas-ss.sh</code> 脚本更新 Arukas Shadowsocks 配置，一般这样就能对付 Arukas 容器每隔几个小时自动重启的问题了。</p>
<h2 id="postscript">后记</h2>
<p>经过我这段时间的试用，Arukas 容器做为爬墙服务器还是比较顺畅的，如果想捣鼓一个简单的 API 服务器也还凑合，不过由于 Arukas 目前还不支持外部存储，想拿来跑个博客程序之类的就要涉及到如何保存和恢复网站数据的问题了。</p>
<p>当然容器只能用 Endpoint 地址访问也是一个大问题，经过测试我也发现如果容器内开放的内部端口稍微一多（可能超过 3 个）时，Arukas 的 HAProxy 转发服务就不太稳定了，经常出现 502 或者 503 错误。如果容器内开放了 UDP 端口，Endpoint 地址甚至可能会处于一直都不能访问的状况。</p>
<p>如果 Arukas 容器在内测期间能解决这些问题，后续正式使用价格也不算离谱的话，感觉应该还是有些竞争力的，最后祝大家 4 月玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/arukas-container/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>小内存OpenVZ VPS使用UML开启BBR</title>
		<link>https://zohead.com/archives/openvz-uml-bbr/</link>
		<comments>https://zohead.com/archives/openvz-uml-bbr/#comments</comments>
		<pubDate>Mon, 06 Mar 2017 18:39:55 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[User-mode Linux]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[网络]]></category>
		<category><![CDATA[BBR]]></category>
		<category><![CDATA[busybox]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[OpenVZ]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[ShadowsocksR]]></category>
		<category><![CDATA[TAP]]></category>
		<category><![CDATA[UML]]></category>
		<category><![CDATA[VPS]]></category>
		<category><![CDATA[翻墙]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1365</guid>
		<description><![CDATA[前言 Bottleneck Bandwidth and RTT（BBR）是 Google 最近提交到 Linux 4.9 版本内核的新 TCP 拥塞控制算法，BBR 相对于 Linux 中已经用了好多年的默认 CUBIC 算法的主要改进是在有一定丢包率的网络链路上充分利用带宽，另外也能有效降低延迟。这对于很多使用美帝 VPS + Shadowsocks 爬墙方案的人来说应该还是比较有用的，目前从一些更新了内核开启 BBR 的 KVM VPS 用户的反馈来看效果也还是不错的。 我目前使用的爬墙服务器是 AlphaRacks 的低配 OpenVZ VPS，内存只有 96 MB，到国内的线路质量倒还 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="preface">前言</h2>
<p><a href="https://github.com/google/bbr">Bottleneck Bandwidth and RTT（BBR）</a>是 Google 最近提交到 Linux 4.9 版本内核的新 TCP 拥塞控制算法，BBR 相对于 Linux 中已经用了好多年的默认 CUBIC 算法的主要改进是在有一定丢包率的网络链路上充分利用带宽，另外也能有效降低延迟。这对于很多使用美帝 VPS + Shadowsocks 爬墙方案的人来说应该还是比较有用的，目前从一些更新了内核开启 BBR 的 KVM VPS 用户的反馈来看效果也还是不错的。</p>
<p>我目前使用的爬墙服务器是 AlphaRacks 的低配 OpenVZ VPS，内存只有 96 MB，到国内的线路质量倒还凑合，OpenVZ 虽然没办法直接升级 kernel ，但看到 AlphaRacks 控制面板里能开启 TUN/TAP，那可以考虑捣鼓使用 User-mode Linux（UML）来开启 BBR 了。</p>
<p>User-mode Linux 和 QEMU 这种虚拟机稍微有点类似，但 UML 是直接将 Linux 内核编译成可执行的 ELF 应用层程序，这样可以直接在普通 Linux 环境中运行及调试其它版本 Linux 内核的功能，有关 UML 的详细信息请参考其<a href="http://user-mode-linux.sourceforge.net/">官方网站</a>。</p>
<blockquote>
<p><strong>提示</strong></p>
<p>不想自己编译 UML 内核和构建 UML rootfs 的朋友可以直接拉到「<a href="#use-uml-ss-system">使用 UML Shadowsocks 系统</a>」这部分哦。</p>
</blockquote>
<h2 id="compile-uml-kernel">编译 User-mode Linux 内核</h2>
<h3 id="compile-prepare">准备编译环境</h3>
<p>我是直接在 Windows 10 RS2 64 位系统上编译 UML 内核的，使用 Win10 自带的 Bash on Ubuntu 14.04 环境编译还是非常方便的，而且编译速度相比使用虚拟机也是快了很多。</p>
<p>首先安装编译需要的软件包：</p>
<blockquote>
<p><strong>备注</strong></p>
<p>由于我使用的 OpenVZ VPS 系统是 32 位的，所以这里安装 <code>libc-dev</code> 和 <code>libvdeplug-dev</code> 开发包时都指定了使用 32 位版本；如果你需要编译 64 位版本的 UML 内核，那把下面的 <code>-i386</code> 去掉即可。</p>
</blockquote>
<pre class="brush: bash; title: ; notranslate">
zzm@ZZM-P238:~$ sudo apt-get install build-essential libncurses5-dev libc6-dev-i386 libvdeplug-dev-i386
</pre>
<p>这里安装 <code>libvdeplug-dev</code> 开发包是为了支持 UML 的 <a href="http://wiki.virtualsquare.org/wiki/index.php/VDE_Basic_Networking#Step_3:_run_a_User-Mode_Linux">Virtual Distributed Ethernet（VDE）</a>模式网卡设备，VDE 主要是为了让 UML 的网络功能在类似 Docker 这种连 TUN/TAP 都不支持的系统上也能工作起来。</p>
<p>接着可以下载最新 Linux 4.10.1 版本内核源代码，并解压缩准备配置内核选项，4.10.1 版本源代码解压之后不到 800 MB。</p>
<blockquote>
<p><strong>提示</strong></p>
<p>如果像我一样直接在 Win10 Bash 环境中编译，那么最好将内核源代码解压到 Win10 Bash 的 VolFs 文件系统中（也就是 Ubuntu rootfs 目录，一般直接 cd 到 <code>HOME</code> 主目录即可）。</p>
</blockquote>
<h3 id="uml-kernel-config">UML 内核配置</h3>
<p>如果使用默认的 UML 内核配置是比较简单的，直接下面两步即可，第二步内核配置界面里可以手工开启 BBR 功能：</p>
<pre class="brush: bash; title: ; notranslate">
zzm@ZZM-P238:~/linux-4.10.1$ cp arch/um/configs/i386_defconfig .config
zzm@ZZM-P238:~/linux-4.10.1$ make menuconfig ARCH=um
</pre>
<p>不过为了能编译出体积最小又能满足 BBR 爬墙需要的 kernel，我还是使用自己修改的最小配置，首先将下面的内容保存为 <code>mini.config</code> 文件（如果需要编译 64 位 kernel，那直接把开头的 <code>CONFIG_64BIT=n</code> 这一行去掉即可）：</p>
<pre class="brush: bash; title: ; notranslate">
zzm@ZZM-P238:~/linux-4.10.1$ cat mini.config
CONFIG_64BIT=n
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=n
CONFIG_HOSTFS=y
CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_KERNEL_STACK_ORDER=1
CONFIG_SWAP=n
CONFIG_SYSVIPC=y
CONFIG_EXPERT=n
CONFIG_EMBEDDED=n
CONFIG_SLUB_DEBUG=n
CONFIG_BLOCK=y
CONFIG_LBDAF=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_BLK_DEV_BSG=n
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_UBD=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=n
CONFIG_DEFAULT_IOSCHED=&quot;deadline&quot;
CONFIG_NETDEVICES=n
CONFIG_STDERR_CONSOLE=y
CONFIG_SSL=y
CONFIG_NULL_CHAN=y
CONFIG_PORT_CHAN=y
CONFIG_PTY_CHAN=y
CONFIG_TTY_CHAN=y
CONFIG_XTERM_CHAN=y
CONFIG_UNIX98_PTYS=y
CONFIG_EXT2_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_TMPFS=y
CONFIG_SYSFS=y
CONFIG_SCHED_DEBUG=n
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_BBR=y
CONFIG_DEFAULT_BBR=y
CONFIG_DEFAULT_TCP_CONG=&quot;bbr&quot;
CONFIG_IPV6=n
CONFIG_SYN_COOKIES=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_QFQ=y
CONFIG_NET_SCH_CODEL=y
CONFIG_NET_SCH_FQ_CODEL=y
CONFIG_NET_SCH_FQ=y
CONFIG_NET_SCH_FIFO=y
CONFIG_UML_NET=y
CONFIG_UML_NET_TUNTAP=y
CONFIG_UML_NET_VDE=y
CONFIG_DEBUG_KERNEL=n
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
</pre>
<p>简单说明一下上面的内核配置选项：</p>
<ul>
<li>启用了 UML 的 hostfs 及 mconsole 等很实用的功能；</li>
<li>支持 UML 的 ubd 块设备，也开启了 loop 设备支持，去掉了 ramdisk 等没什么用的其它设备支持；</li>
<li>支持 proc、sysfs、tmpfs 等虚拟文件系统，真实的文件系统只保留了 ext2 支持，需要 ext3 或者 ext4 支持的朋友请自行修改；</li>
<li>开启 BBR 并设置为默认拥塞控制算法，另外需要为 BBR 启用 Fair Queue 包调度器；</li>
<li>去掉了 IPv6 支持，去掉了所有的网卡设备驱动；</li>
<li>去掉了几乎所有的内核调试信息。</li>
</ul>
<p>然后使用 <code>mini.config</code> 生成新的内核配置文件：</p>
<pre class="brush: bash; title: ; notranslate">
zzm@ZZM-P238:~/linux-4.10.1$ make ARCH=um allnoconfig KCONFIG_ALLCONFIG=mini.config
</pre>
<h3 id="compile-kernel">编译内核</h3>
<p>内核选项配置完毕之后，编译就非常简单了：</p>
<pre class="brush: bash; title: ; notranslate">
zzm@ZZM-P238:~/linux-4.10.1$ make ARCH=um vmlinux -j4
</pre>
<p>这里我开启了 4 个并发编译（make 的 <code>-j4</code> 参数）支持，UML 的 vmlinux 可执行程序在我的笔记本上不到 4 分钟就编译完成了，最终编译出来的 vmlinux 文件大小大概为 3 - 4 MB。</p>
<p>你可以试着运行编译出来的 vmlinux 可执行程序查看编译时使用的内核配置：</p>
<pre class="brush: bash; title: ; notranslate">
[root@localhost ~]# ./vmlinux --showconfig
</pre>
<h2 id="prepare-uml-rootfs">准备 UML rootfs</h2>
<h3 id="prepare-rootfs-ss-libev">准备 rootfs 和 shadowsocks-libev</h3>
<p>既然 UML 内核我都是按最小化编译的，那运行的 rootfs 自然不能用像 Ubuntu、CentOS 那种「庞大」的系统了，这里我直接使用最小化的 busybox rootfs + Shadowsocks 服务端程序和运行库的方式，除了 busybox 基础环境和 Shadowsocks 服务端程序基本没有添加任何其它东西。</p>
<p>最终我将 UML vmlinux 内核文件和 rootfs 目录一起压缩打包起来大小也不过才 3 MB，这样能非常方便地上传到 VPS 上和分享给其他人。当然缺点就是如果需要安装其它的软件那只能手工拷贝到 rootfs 目录中了。</p>
<p>具体 busybox rootfs 的制作方法这里我就不做详细说明了，感兴趣的朋友可以参考相关的文档了解一下，我分别制作了 32 位和 64 位的 busybox rootfs 目录。</p>
<p>另外为了减少 UML 系统的程序依赖和内存占用，Shadowsocks 服务端我选择的是 <a href="https://github.com/shadowsocks/shadowsocks-libev">shadowsocks-libev</a>，这里我也分别编译了最新 3.0.3 版本 32 位和 64 位的服务端程序。</p>
<p>32 位 shadowsocks-libev 我是在 32 位 Ubuntu 14.04 系统下编译的，依赖的动态库也是使用的 Ubuntu 14.04 自带的库文件；64 位 shadowsocks-libev 则是在 64 位 CentOS 6 系统下编译的，所以 64 位运行库版本和 32 位的不同。你问我为什么不用同一个系统？因为我刚好有这两个系统的 VPS 能用来编译，实在是懒的换了 ^_^。</p>
<h3 id="test-uml-rootfs">测试 UML rootfs</h3>
<p>由于 OpenVZ 系统内核不支持 loop 设备，不能挂载文件系统映像进行修改，这里我直接使用 UML 的 hostfs 将 OpenVZ 主机系统的一个目录设为 UML 系统的 rootfs。</p>
<p>现在 UML hostfs 并没有某些网友说的存在只读的限制，而且相比使用 loop 设备或者 ubd 文件系统这种方式，hostfs 并不需要预先产生一个很大的文件，主机也能直接修改 UML rootfs 目录内容，UML 内核也根本不需要支持 ext3、ext4 这种真实的文件系统，综合比较下来实在是没有什么理由不用 hostfs。</p>
<p>首先安装 UML 工具 <code>uml-utilities</code> 软件包，后面的 <code>tunctl</code> 和 <code>uml_mconsole</code> 等命令会用到：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# apt-get install uml-utilities
</pre>
<p>接着可以配置 OpenVZ 系统上的 TUN/TAP 虚拟网卡和开启端口转发：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# tunctl -u root
Set 'tap0' persistent and owned by uid 0
root@zohead:~# ifconfig tap0 192.168.0.3 up
root@zohead:~# echo 1 &gt; /proc/sys/net/ipv4/ip_forward
root@zohead:~# iptables -t nat -I POSTROUTING -o venet0 -j MASQUERADE
root@zohead:~# iptables -t nat -A PREROUTING -i venet0 -p tcp --dport 9443 -j DNAT --to-destination 192.168.0.4
root@zohead:~# iptables -t nat -A PREROUTING -i venet0 -p udp --dport 9443 -j DNAT --to-destination 192.168.0.4
</pre>
<blockquote>
<p><strong>备注</strong></p>
<p>上面的命令中假设 TUN/TAP 虚拟网卡 IP 地址为 <code>192.168.0.3</code>（可以自行修改），UML 系统网卡 IP 地址为 <code>192.168.0.4</code>（需要和 TUN/TAP 虚拟网卡地址在同一网段），只将 OpenVZ 主机系统上 <code>9443</code> 端口的 TCP 和 UDP 数据转发到 UML 系统网卡上。</p>
</blockquote>
<p>最后是启动 UML 系统的例子：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# ./vmlinux-i686 umid=shadowsocks root=/dev/root rootfstype=hostfs rootflags=/root/umlfs-i686 rw mem=48M init=/sbin/init eth0=tuntap,tap0
</pre>
<p>简单说明一下 UML vmlinux 程序的参数：</p>
<ul>
<li><code>umid</code> 参数指定 UML 系统 ID，建议每个 UML 系统都使用的固定的 ID，不然每次运行都会在 <code>~/.uml</code> 目录下产生新的临时目录；</li>
<li><code>rootflags</code> 参数指定 UML rootfs 路径，这里 <strong>必须</strong> 使用绝对路径；</li>
<li><code>mem</code> 参数指定 UML 系统的内存大小，经过我的测试，只运行 shadowsocks-libev 服务端的话就算分配 32 MB 内存看起来也没什么压力；</li>
<li><code>init</code> 参数指定 UML 系统的 init 进程，不建议修改；</li>
<li><code>eth0=tuntap,tap0</code> 则是指定 UML 的 tuntap 模式网卡，使用 OpenVZ 主机系统的 <code>tap0</code> 虚拟网卡设备。</li>
</ul>
<h2 id="use-uml-ss-system">使用 UML Shadowsocks 系统</h2>
<h3 id="uml-linux-sh">uml-linux.sh 脚本</h3>
<p>为了使用起来方便，我把启动 UML 系统和设置端口转发的操作写成了一个 <code>uml-linux.sh</code> 脚本，这样 OpenVZ 系统启动之后可以根据配置自动运行并配置端口转发：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
UML_ID=&quot;shadowsocks&quot;
TAP_DEV=&quot;tap0&quot;
ROUTER_DEV=&quot;venet0&quot;
TAP_ADDR=&quot;192.168.0.3&quot;
UML_ADDR=&quot;192.168.0.4&quot;
REV_TCP_PORTS=&quot;&quot;
REV_UDP_PORTS=&quot;&quot;
FWD_TCP_PORTS=&quot;9443&quot;
FWD_UDP_PORTS=&quot;9443&quot;

DIR=&quot;$( cd &quot;$( dirname &quot;$0&quot; )&quot; &amp;&amp; pwd )&quot;

[ ! -d /sys/class/net/$TAP_DEV ] &amp;&amp; tunctl -t $TAP_DEV
ifconfig $TAP_DEV $TAP_ADDR up

echo 1 &gt; /proc/sys/net/ipv4/ip_forward

iptables -t nat -I POSTROUTING -o $ROUTER_DEV -j MASQUERADE

for i in $REV_TCP_PORTS; do
	if [ &quot;x$i&quot; = &quot;x*&quot; ]; then
		P_TMP=&quot;&quot;
	else
		P_TMP=&quot;--dport $i &quot;
	fi
	iptables -t nat -A PREROUTING -p tcp $P_TMP-j RETURN
done
for i in $REV_UDP_PORTS; do
	if [ &quot;x$i&quot; = &quot;x*&quot; ]; then
		P_TMP=&quot;&quot;
	else
		P_TMP=&quot;--dport $i &quot;
	fi
	iptables -t nat -A PREROUTING -p udp $P_TMP-j RETURN
done

for i in $FWD_TCP_PORTS; do
	if [ &quot;x$i&quot; = &quot;x*&quot; ]; then
		P_TMP=&quot;&quot;
	else
		P_TMP=&quot;--dport $i &quot;
	fi
	iptables -t nat -A PREROUTING -i $ROUTER_DEV -p tcp $P_TMP-j DNAT --to-destination $UML_ADDR
done
for i in $FWD_UDP_PORTS; do
	if [ &quot;x$i&quot; = &quot;x*&quot; ]; then
		P_TMP=&quot;&quot;
	else
		P_TMP=&quot;--dport $i &quot;
	fi
	iptables -t nat -A PREROUTING -i $ROUTER_DEV -p udp $P_TMP-j DNAT --to-destination $UML_ADDR
done

nohup $DIR/vmlinux-i686 umid=$UML_ID root=/dev/root rootfstype=hostfs rootflags=$DIR/umlfs-i686 rw mem=48M init=/sbin/init con=pts eth0=tuntap,$TAP_DEV,,$UML_ADDR &amp;
</pre>
<p>一般只要修改脚本最开始的几行配置即可（最后一行 vmlinux 程序和 UML rootfs 路径默认使用脚本所在路径，如果不同请自行修改）：</p>
<ul>
<li><code>TAP_ADDR</code> 为 TUN/TAP 虚拟网卡地址，<code>UML_ADDR</code> 为 UML 系统内网卡地址；</li>
<li><code>REV_TCP_PORTS</code> 和 <code>REV_UDP_PORTS</code> 分别指定 OpenVZ 主机系统需要保留哪些 TCP 和 UDP 端口不转发到 UML 系统（多个以空格隔开），一般如果 UML 系统使用固定的一些端口，那么默认留空即可；</li>
<li><code>FWD_TCP_PORTS</code> 和 <code>FWD_UDP_PORTS</code> 分别指定哪些 TCP 和 UDP 端口需要转发到 UML 系统（默认只写了一个 <code>9443</code>，实际如果需要多个则以空格隔开），如果需要指定端口范围也可以写成 <code>15000:20000</code>，如果需要所有端口都转发到 UML 系统那可以直接写成 <code>*</code>（此时 <code>REV_TCP_PORTS</code> 一般最少要留一个端口用于 SSH 远程登录）；</li>
<li>需要分配给 UML 系统的内存大小请自行修改 vmlinux 的 <code>mem</code> 参数。</li>
</ul>
<h3 id="uml-ss-config">UML Shadowsocks 系统配置</h3>
<p>另外 UML 系统内部的网卡地址配置及启动 shadowsocks-libev 服务端的操作都在 <code>/etc/rc.local</code> 脚本中：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
if [ -d /sys/class/net/eth0 ]; then
	ifconfig eth0 192.168.0.4 up
	route add default gw 192.168.0.3 dev eth0
	sleep 2
fi

SS_DNS=&quot;&quot;

[ -f /etc/default/pdnsd ] &amp;&amp; . /etc/default/pdnsd

# start local DNS server if needed
if [ &quot;x$START_DAEMON&quot; = &quot;xyes&quot; -o &quot;x$START_DAEMON&quot; = &quot;xYES&quot; ]; then
	pdnsd -d
	[ $? -eq 0 ] &amp;&amp; SS_DNS=&quot;-d 127.0.0.1 &quot;
fi

for i in `ls /etc/shadowsocks-libev/*.json 2&gt;/dev/null`; do
	SS_NAME=`basename $i .json 2&gt;/dev/null`
	start-stop-daemon -n shadowsocks-$SS_NAME -x ss-server -b -S -- -c $i -u $SS_DNS--fast-open
done

exit 0
</pre>
<p>简单说明一下：</p>
<ul>
<li>这里的 <code>192.168.0.4</code> 网卡 IP 地址就对应上面的 <code>UML_ADDR</code>，<code>192.168.0.3</code> 网关地址就是 <code>TAP_ADDR</code>，因此如果上面脚本中的地址修改了，那么 UML rootfs 的 <code>/etc/rc.local</code> 中的地址也需要修改；</li>
<li>你可以将 shadowsocks-libev 配置文件放到 <code>/etc/shadowsocks-libev</code> 目录中，此脚本会自动遍历并一一启动 <code>ss-server</code> 服务器，同时默认也开启了 TCP Fast Open 和 UDP 转发；</li>
<li>另外 rootfs 里集成了 <code>pdnsd</code> DNS 服务器，如果需要实现 DNS 缓存加速或者 UML 系统的 UDP DNS 解析存在问题，都可以启用 <code>pdnsd</code> 本地 DNS 服务器。</li>
</ul>
<p>配置修改完成之后，运行 <code>uml-linux.sh</code> 脚本就会在后台启动 UML 系统，并根据需要自动启动 shadowsocks-libev 服务器。</p>
<h3 id="control-uml-system">控制 UML 系统</h3>
<p>如果你需要登录到 UML 系统，可以先用 <code>uml_mconsole</code> 命令得到 UML 系统分配到的虚拟终端（第二个参数就是 UML 系统 ID）：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# uml_mconsole shadowsocks config con0
OK pts:/dev/pts/2
</pre>
<p>然后使用 <code>screen</code> 命令就可以连接到该虚拟终端上（默认什么都不显示，需要按回车键终端才会出来）：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# screen /dev/pts/2
</pre>
<p>如果想在 OpenVZ 主机系统里直接关闭整个 UML 系统，那也非常简单：</p>
<pre class="brush: bash; title: ; notranslate">
root@zohead:~# uml_mconsole shadowsocks halt
</pre>
<h3 id="uml-ss-download">UML Shadowsocks 系统下载</h3>
<p>为了方便大家使用，我把 32 位和 64 位的 UML 4.10.1 版本 vmlinux 内核程序及配置和 Shadowsocks 服务端 rootfs 目录、<code>uml-linux.sh</code> 脚本一起打包分享给大家。</p>
<p>32 位的 UML Shadowsocks 系统（百度网盘备用）：</p>
<p><a href="https://zohead.com/downloads/uml-shadowsocks-i686.tar.xz">https://zohead.com/downloads/uml-shadowsocks-i686.tar.xz</a> <br />
<a href="https://pan.baidu.com/s/1kVdoWcB" target="_blank">https://pan.baidu.com/s/1kVdoWcB</a></p>
<p>64 位的 UML Shadowsocks 系统：</p>
<p><a href="https://zohead.com/downloads/uml-shadowsocks-x64.tar.xz">https://zohead.com/downloads/uml-shadowsocks-x64.tar.xz</a> <br />
<a href="https://pan.baidu.com/s/1dFDta9N" target="_blank">https://pan.baidu.com/s/1dFDta9N</a></p>
<p>将上面的文件下载到 VPS 某个目录并解压缩，修改 <code>uml-linux.sh</code> 文件中的转发端口，将 <a href="https://wiki.archlinux.org/index.php/Shadowsocks" target="_blank">Shadowsocks 服务端配置文件</a>放到 rootfs 的 <code>/etc/shadowsocks-libev</code> 目录，之后以 root 身份运行 <code>uml-linux.sh</code> 脚本即可。</p>
<blockquote>
<p><strong>提示</strong></p>
<p>如果需要让 ShadowsocksR 服务器使用 TCP 等方式进行域名解析，可以修改 <code>/etc/default/pdnsd</code> 文件将其中的 <code>START_DAEMON</code> 改为 <code>yes</code> 来启用 <code>pdnsd</code> 本地 DNS 服务器。</p>
</blockquote>
<h3 id="uml-ssr-download">UML ShadowsocksR 系统</h3>
<p>考虑到某些网友的需要，我还生成了 32 和 64 位的 UML ShadowsocksR 系统，都是使用的最新支持混淆的 Python 版本 ShadowsocksR 服务器，有需要的朋友可以下载测试（百度网盘为备用下载地址）。</p>
<p>32 位的 UML ShadowsocksR 系统：</p>
<p><a href="https://zohead.com/downloads/uml-shadowsocksr-i686.tar.xz">https://zohead.com/downloads/uml-shadowsocksr-i686.tar.xz</a> <br />
<a href="https://pan.baidu.com/s/1eSDrWye">https://pan.baidu.com/s/1eSDrWye</a></p>
<p>64 位的 UML ShadowsocksR 系统：</p>
<p><a href="https://zohead.com/downloads/uml-shadowsocksr-x64.tar.xz">https://zohead.com/downloads/uml-shadowsocksr-x64.tar.xz</a> <br />
<a href="https://pan.baidu.com/s/1o7F3qpc">https://pan.baidu.com/s/1o7F3qpc</a></p>
<p>ShadowsocksR 系统的 rootfs 只包含了基础 Python 环境和 ShadowsocksR 服务器程序，同样下载并解压缩，由于包含了 Python 环境，该 rootfs 解压缩之后接近 30 MB。</p>
<p>使用前可根据需要修改 <code>uml-linux.sh</code> 文件中的转发端口，将 <a href="https://github.com/breakwa11/shadowsocks-rss/wiki/config.json" target="_blank">ShadowsocksR 服务器 JSON 格式配置文件</a>放到 rootfs 的 <code>/etc/shadowsocks</code> 目录，之后以 root 身份运行 <code>uml-linux.sh</code> 脚本即可（启用 <code>pdnsd</code> 本地 DNS 服务器的方法和上面的相同）。</p>
<h2 id="uml-bbr-compare">UML 系统 BBR 效果</h2>
<p>最后对比一下我的 AlphaRacks OpenVZ VPS 上启用 BBR 前后的对比速度，这里我就直接观看同一个 1080p 的 YouTube 视频来对比统计信息了。</p>
<p>在我的江苏移动宽带环境下，启用 BBR 之前 YouTube 视频连接速度一般只能跑到 1Mbps 左右：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442863/openvz-ss-speed.png" alt="OpenVZ 未启用 BBR 的 YouTube 速度" title="OpenVZ 未启用 BBR 的 YouTube 速度"></p>
<p>而在使用 UML Shadowsocks 系统开启 BBR 之后能跑到 2Mbps，不过有的时候速度还是不太稳定：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442867/openvz-ss-speed-bbr.png" alt="OpenVZ 启用 UML BBR 的 YouTube 速度" title="OpenVZ 启用 UML BBR 的 YouTube 速度"></p>
<p>UML 目前也是主要用于调试验证 Linux 内核功能的，总之 OpenVZ 使用 UML 开启 BBR 的实际使用效果还是需要长期观察测试的，本文也主要关注 UML 系统下使用 Shadowsocks 的问题，并没有考虑通用的情况，如果文章中有任何问题还请提出指正，祝大家玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/openvz-uml-bbr/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Android使用Shell命令配合Tasker控制手机</title>
		<link>https://zohead.com/archives/tasker-shell/</link>
		<comments>https://zohead.com/archives/tasker-shell/#comments</comments>
		<pubDate>Tue, 13 Dec 2016 16:38:02 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[NFC]]></category>
		<category><![CDATA[Secure Settings]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[Tasker]]></category>
		<category><![CDATA[飞行模式]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1325</guid>
		<description><![CDATA[Secure Settings 对比 Shell 命令 去年我写过一篇 Android 使用 Trigger + Tasker 设定 NFC 标签 的文章，主要介绍怎么使用 Tasker 和 Trigger App 设定 Android 手机刷 NFC 标签时执行指定的操作。该文章中对于手机的 飞行模式 / GPS / NFC 等功能的控制操作都是通过 Secure Settings App 实现的。 不过可惜的是我的华硕 Zenfone2 手机 ROM 升级到 6.0 版本之后，Secure Settings App 就有很多功能不能正常工作了，而且由于开发者也基本不再维护该 App 也有差 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="secure-settings-对比-shell-命令">Secure Settings 对比 Shell 命令</h2>
<p>去年我写过一篇 <a href="https://zohead.com/archives/tasker-nfc/">Android 使用 Trigger + Tasker 设定 NFC 标签</a> 的文章，主要介绍怎么使用 <a href="https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm" target="_blank">Tasker</a> 和 <a href="https://play.google.com/store/apps/details?id=com.jwsoft.nfcactionlauncher" target="_blank">Trigger</a> App 设定 Android 手机刷 NFC 标签时执行指定的操作。该文章中对于手机的 飞行模式 / GPS / NFC 等功能的控制操作都是通过 <a href="https://play.google.com/store/apps/details?id=com.intangibleobject.securesettings.plugin" target="_blank">Secure Settings</a> App 实现的。</p>
<p>不过可惜的是我的华硕 Zenfone2 手机 ROM 升级到 6.0 版本之后，Secure Settings App 就有很多功能不能正常工作了，而且由于开发者也基本不再维护该 App 也有差不多两年没有任何更新。</p>
<p>最近看到 <a href="http://www.notenoughtech.com/tasker/tasker-run-shell-commands/" target="_blank">Best run shell commands in Tasker</a> 文章介绍  Tasker 的几个常用 Shell 命令控制移动数据、飞行模式等选项，使用 Tasker 自带的运行 Shell 命令功能相比 Secure Settings 插件也有一些好处：</p>
<ul>
<li>Tasker 直接支持运行 Shell 命令（新增 <strong>操作类别</strong> -&gt; <strong>代码</strong> -&gt; <strong>运行外壳</strong> 即可），不需要专门安装 Secure Settings 等第三方 App；</li>
<li>多数命令在手机 root 后就能正常工作，不像 Secure Settings 那样需要特别安装成系统 App；</li>
<li>Shell 命令失效需要替换时也比较灵活，直接改 Shell 命令行就可以。</li>
</ul>
<p>因此我还是卸载了 Secure Settings App，将原来文章里的所有 Tasker 任务的 Secure Settings 操作都以 Shell 命令进行替代。</p>
<h2 id="tasker-任务使用-shell-命令">Tasker 任务使用 Shell 命令</h2>
<h3 id="数据开关-运行-shadowsocks">数据开关 + 运行 Shadowsocks</h3>
<p>为实现以下目标：</p>
<ol>
<li>具有路由器翻墙的住处网络环境下自动关闭手机 Shadowsocks 和移动数据；</li>
<li>其它网络环境下都开启 Shadowsocks 手机翻墙；</li>
<li>任何 Wi-Fi 环境下关闭移动数据以省电；</li>
<li>离开任何 Wi-Fi 自动开启移动数据。</li>
</ol>
<p>为此我建了 4 个 Tasker 配置和任务（当然也可以更简单）：</p>
<ol>
<li>连接住处的 OpenWRT Wi-Fi（根据 Tasker 的 SSID 条件区分） <br />
关闭 Shadowsocks 和移动数据；</li>
<li>连接其它 Wi-Fi <br />
关闭移动数据；</li>
<li>离开任何 Wi-Fi <br />
开启移动数据；</li>
<li>离开住处 Wi-Fi <br />
开启 Shadowsocks。</li>
</ol>
<p>现在 Android 版本 Shadowsocks App 是自带 Tasker 插件支持的（操作类别里选 <strong>插件</strong> -&gt; <strong>影梭</strong> 即可），开启和关闭 Shadowsocks 配置非常简单。</p>
<p>移动数据开关可以分别用下面的命令（Tasker 运行外壳中需要启用 <strong>使用Root</strong> 选项）：</p>
<pre class="brush: bash; title: ; notranslate">
svc data enable
svc data disable
</pre>
<h3 id="控制飞行模式及-nfc">控制飞行模式及 NFC</h3>
<p>为了实现和之前文章里类似的目标：</p>
<ol>
<li>睡觉前刷 NFC 标签开启飞行模式；</li>
<li>打开 NFC（这样起来之后可以刷 NFC 标签）；</li>
<li>起来刷 NFC 标签关闭飞行模式。</li>
</ol>
<p>另外考虑最好只使用一个 NFC 标签就达到效果，这里我只建了一个 Tasker 任务包含 4 个操作：</p>
<ol>
<li>Tasker 操作类别中选 <strong>变量</strong> -&gt; <strong>变量设置</strong>，<code>%TMPAIR</code> 发往 <code>%AIR</code> <br />
先保存 <code>%AIR</code> 这个 Tasker 自带的飞行模式变量；</li>
<li>如果 <code>%AIR = off</code> 则运行外壳开启飞行模式；</li>
<li>如果 <code>%AIR = on</code> 则运行外壳开启 NFC；</li>
<li>如果 <code>%TMPAIR = on</code> 则运行外壳关闭飞行模式。</li>
</ol>
<h4 id="开启关闭飞行模式">开启关闭飞行模式</h4>
<p>开启和关闭飞行模式可以直接使用下面的两条命令：</p>
<pre class="brush: bash; title: ; notranslate">
settings put global airplane_mode_on 1; am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true
settings put global airplane_mode_on 0; am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false
</pre>
<h4 id="开启关闭-nfc">开启关闭 NFC</h4>
<p>开启和关闭 NFC 功能则相对复杂一些，需要区分 Android 系统版本：</p>
<ul>
<li>Android 4.4 以上：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 5
# Enable NFC
service call nfc 6
</pre>
<ul>
<li>Android 4.0.1 - Android 4.3.1：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 4
# Enable NFC
service call nfc 5
</pre>
<ul>
<li>Android 2.3.4 - Android 2.3.7：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 18
# Enable NFC
service call nfc 19
</pre>
<ul>
<li>Android 2.3.3：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 20
# Enable NFC
service call nfc 21
</pre>
<ul>
<li>Android 2.3.2：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 13
# Enable NFC
service call nfc 14
</pre>
<p>我在运行 Android 6.0 系统的 Zenfone2 手机上可以正常使用第一段的两条命令控制系统 NFC 功能。</p>
<h3 id="gps-开关-开启关闭百度地图">GPS 开关 + 开启关闭百度地图</h3>
<p>需求还是和之前的文章相同：</p>
<ol>
<li>刷 NFC 标签自动开启 GPS 和百度地图进行导航：</li>
<li>导航完成后再刷一次 NFC 标签自动关闭百度地图并关闭 GPS。</li>
</ol>
<p>为此我还是只建立一个 Tasker 任务，包含多个操作：</p>
<ol>
<li>Tasker 操作类别中选 <strong>变量</strong> -&gt; <strong>变量设置</strong>，<code>%TMPGPS</code> 发往 <code>%GPS</code> <br />
先保存 <code>%GPS</code> 这个 Tasker 自带的 GPS 设置变量；</li>
<li>如果 <code>%GPS = off</code> 则启动应用 -&gt; 百度地图；</li>
<li>如果 <code>%GPS = off</code> 则运行外壳开启 GPS；</li>
<li>如果 <code>%TMPGPS != on</code> 则停止运行任务（操作类别中选 <strong>任务</strong> -&gt; <strong>停止</strong>）忽略后续操作；</li>
<li>按钮 -&gt; 后退（操作类别中选 <strong>输入</strong> -&gt; <strong>按钮</strong>），此操作需要添加多个以模拟持续按返回键退出百度地图；</li>
<li>杀死应用 -&gt; 百度地图；</li>
<li>运行外壳关闭 GPS。</li>
</ol>
<p>通过 Shell 命令开启关闭 GPS 也稍微有点特殊，需要使用下面两条命令：</p>
<pre class="brush: bash; title: ; notranslate">
settings put secure location_providers_allowed +gps
settings put secure location_providers_allowed -gps
</pre>
<h2 id="后记">后记</h2>
<p>为了方便查询，我把一些可能经常用到的 Android Shell 控制命令也整理保存到我的 Wiki 知识库中了，读者可以点击 Wiki 链接 <a href="https://wiki.zohead.com/%E6%8A%80%E6%9C%AF/Android/Android%20Shell%E6%8E%A7%E5%88%B6%E6%89%8B%E6%9C%BA.md" target="_blank">Android Shell 控制手机</a> 查看。后续有其它 Shell 命令需要加进来或者修改时，我也会尽量及时更新该文档的，最后祝大家玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/tasker-shell/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>newifi mini路由器OpenWRT初步体验</title>
		<link>https://zohead.com/archives/newifi-mini-openwrt/</link>
		<comments>https://zohead.com/archives/newifi-mini-openwrt/#comments</comments>
		<pubDate>Sat, 09 Jan 2016 16:54:13 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[生活]]></category>
		<category><![CDATA[网络]]></category>
		<category><![CDATA[crontab]]></category>
		<category><![CDATA[dnsmasq]]></category>
		<category><![CDATA[gfwlist]]></category>
		<category><![CDATA[ipset]]></category>
		<category><![CDATA[newifi mini]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[PandoraBox]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[翻墙]]></category>
		<category><![CDATA[路由器]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=1115</guid>
		<description><![CDATA[关于 newifi mini 之前在我住的地方一直都是凑合用着房东默认提供的渣渣 FAST 牌子路由器给几个人 PC 和手机上网，最近在尝试手机视频和照片通过 Wi-Fi DLNA 推送到 Android TV 棒上时发现这款路由器的 Wi-Fi 速度虽然看起来是 56 Mbps 的，但实际无线局域网的传输速度却异常感人，通过 iperf 测试工具得到的局域网机器之间的纯粹网络传输速度只有 600 KB/s 左右，这就造成 DLNA 媒体推送的效果非常差：稍微大点的照片需要等个几秒才能出来，视频推送更是经常缓冲无法忍。 这几天在网上搜索一番之后果断有了换路由器的念头，刚好最近小米、360、百度 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>关于 newifi mini</h2>
<p>之前在我住的地方一直都是凑合用着房东默认提供的渣渣 FAST 牌子路由器给几个人 PC 和手机上网，最近在尝试手机视频和照片通过 Wi-Fi DLNA 推送到 Android TV 棒上时发现这款路由器的 Wi-Fi 速度虽然看起来是 56 Mbps 的，但实际无线局域网的传输速度却异常感人，通过 iperf 测试工具得到的局域网机器之间的纯粹网络传输速度只有 600 KB/s 左右，这就造成 DLNA 媒体推送的效果非常差：稍微大点的照片需要等个几秒才能出来，视频推送更是经常缓冲无法忍。</p>
<p>这几天在网上搜索一番之后果断有了换路由器的念头，刚好最近小米、360、百度等厂商都推出了自家物（Zì）美（Dài）价（Hòu）廉（Mén）的智能路由器，比较之后发现联想和百度联合推出的 newifi mini 路由器相对符合我的要求：</p>
<ul>
<li>官方系统默认没有上锁可以很方便的刷 OpenWRT 等系统；</li>
<li>支持 2.4G 和 5G Wi-Fi，而且支持 802.11ac 千兆无线；</li>
<li>网上有一些黑点，但综合评价装 OpenWRT 之后还行；</li>
<li>99 RMB 的价格也还算合理（有段时间特价到 69 哦）。</li>
</ul>
<p>这样就在京东上入了一个，上午下单下午就送到的路由器带盒子照片：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442857/newifi-mini.jpg" alt="newifi mini路由器" title="newifi mini路由器"></p>
<h2>折腾 OpenWRT 系统</h2>
<p>外观看起来还凑合，不多说插上网线先试试官方系统，用了不到 10 分钟难以忍受必须弃用，从这里下载适合 newifi mini 的 PandoraBox OpenWRT 系统和 uboot 文件：</p>
<p><a href="http://downloads.openwrt.org.cn/PandoraBox/Lenovo-Y1_RY-1S/">http://downloads.openwrt.org.cn/PandoraBox/Lenovo-Y1_RY-1S/</a></p>
<p>重启路由器时长按 Reset 键进入恢复模式通过连网线之后就可以刷上（我用的 Dell Chromebook 和 Acer Win10 平板都没有 RJ45 接口，还好我还有个 USB 的有线网卡），刷的速度还是很快的，重启之后发现 PandoraBox 系统只是启动时间就已经比官方系统要好很多了 ^_^。</p>
<p>废话不多说，下面就是先在 OpenWRT 里配置 PPPoE 拨号连上网再说，刷完系统之后实际测试目前除了 5GHz 的 Wi-Fi 信号穿墙效果比较差（看起来在国内几个智能路由器里都有）之外还没发现什么问题。</p>
<p>接着是最主要的步骤：安装和配置 ShadowSocks 软件包实现 PC 和手机的无缝翻墙，由于之前从来没有搞过 OpenWRT 系统，在看了一些文章之后采用了飞羽博客里提到的使用 ipset + gfwlist 实现按需翻墙的方案，这样既可以避免影响访问国内网站和一些国外网站的速度，而且这种方案相对也比较灵活，默认使用 gfwlist 可以覆盖绝大多数需要翻墙的网站，也可以自己手工增加域名或者 IP 地址，详细介绍请参考 <a href="https://cokebar.info/archives/962">飞羽博客</a>。</p>
<p>我在实际测试中发现如果使用很多网友选择的 ChinaDNS 方案还是有一些网站域名会碰到 DNS 污染的情况，这样导致有一些网站还是不能访问，因此我选择了直接使用 ShadowSocks 解析（需要 ShadowSocks 服务端支持 UDP 转发）所有在 ipset 列表中的域名的方式，这样只需要在 PandoraBox 里运行 ss-redir 和 ss-tunnel 服务。</p>
<p>关于 gfwlist 的自动更新问题，为了方便我也是用的飞羽提供的 <code>gfwlist2dnsmasq.py</code> Python 脚本自动生成 <code>dnsmasq_list.conf</code> 配置文件，如果你的路由器里装有 Python 的运行环境可以直接使用这个脚本生成配置文件保存到路由器中。</p>
<p>我看到 newifi mini 的 rootfs 空间实在是有点小不适合再装个相对庞大的 Python 环境，因此就把 <code>gfwlist2dnsmasq.py</code> 放到我的 VPS 上了，并添加了 crontab 任务设置每天凌晨 5 点自动根据 gfwlist 生成 <code>dnsmasq_list.conf</code> 配置文件并输出到我的网站（也就是这个博客）目录里，并同时在 PandoraBox 上也添加了每天凌晨 5 点 10 分从我的博客下载 dnsmasq 配置文件覆盖到 <code>/etc/dnsmasq.d</code> 目录中。</p>
<p>这个是我基于 gfwlist 自动生成的 dnsmasq 配置文件地址：</p>
<p><a href="https://zohead.com/downloads/dnsmasq.tar.gz">https://zohead.com/downloads/dnsmasq.tar.gz</a></p>
<p>大家如果图省事的话也可以直接用我的这个配置文件哦，另外 PandoraBox 上的 crontab 定时任务配置如下所示：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]#cat /etc/crontabs/root
10 5 * * * curl -k -o /tmp/dnsmasq.tar.gz https://zohead.com/downloads/dnsmasq.tar.gz &amp;&amp; tar -C /tmp -xzf /tmp/dnsmasq.tar.gz &amp;&amp; cat /tmp/dnsmasq_list.conf &gt; /etc/dnsmasq.d/dnsmasq_list.conf &amp;&amp; rm -f /tmp/dnsmasq.tar.gz /tmp/dnsmasq_list.conf
</pre>
<p>实际使用时改掉行开始的地方执行的时间和后面的下载地址即可。</p>
<h2>手机 Tasker 设置</h2>
<p>经过一番小折腾我和小伙伴们在住的地方就可以不用装任何其它软件直接无缝翻墙上网了，对于我的 Android 手机在带出去和在公司里使用也需要翻墙的情况，就可以用到最新 ShadowSocks App 的 Tasker 集成功能：</p>
<ul>
<li>创建 Tasker 配置文件和任务，设置回到住处连接到 newifi mini 路由器对应 SSID 的 Wi-Fi 时自动关闭手机的 ShadowSocks App；</li>
<li>再创建另外一个 Tasker 配置文件和任务，设置离开此 SSID 的 Wi-Fi 时就自动开启 ShadowSocks 并连接到指定的服务器。</li>
</ul>
<p>来一张我的手机 Tasker App 的配置截图：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442946/shadowsocks-tasker.jpg" alt="ShadowSocks Tasker配置" title="ShadowSocks Tasker配置"></p>
<p>这样我就可以在任何地方都能 Happy 的上各种不存在的网站咯，本文中有任何问题欢迎提出指正哦，最后还是祝大家玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/newifi-mini-openwrt/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>博客搬家到HighSpeedWeb VPS了</title>
		<link>https://zohead.com/archives/blog-hswvps/</link>
		<comments>https://zohead.com/archives/blog-hswvps/#comments</comments>
		<pubDate>Mon, 02 Mar 2015 18:04:41 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[主机空间]]></category>
		<category><![CDATA[网络]]></category>
		<category><![CDATA[HighSpeedWeb]]></category>
		<category><![CDATA[Linost]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[VPS]]></category>
		<category><![CDATA[主机]]></category>
		<category><![CDATA[博客]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=860</guid>
		<description><![CDATA[2013年的4月份因为不堪忍受 000webhost 三蛋空间的蛋疼速度和恶心无故封账户机制，切换到 Linost 空间用了差不多两年了。平心而论 Linost 的主机还算比较稳定，虽然不定时的抽风一下，但做简单的博客主机还是可以，期间还在 Linost 上买了一年的 SSH 代理服务并使用至今，现在看到 SSH 代理服务器被 GFW 封的越来越厉害，于是想自己搞个 VPS 跑 WordPress 博客程序，顺带跑下 Shadowsocks 用来爬墙比较方便（只要不是流量很高被 GFW 盯上了一般不易被封）。 左挑右选之后还是决定先拿一个性价比比较高的 VPS 来练练手，因此在 Linost  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>2013年的4月份因为不堪忍受 000webhost 三蛋空间的蛋疼速度和恶心无故封账户机制，切换到 <a href="https://my.linost.com/aff.php?aff=1674" target="_blank">Linost</a> 空间用了差不多两年了。平心而论 <a href="https://my.linost.com/aff.php?aff=1674" target="_blank">Linost</a> 的主机还算比较稳定，虽然不定时的抽风一下，但做简单的博客主机还是可以，期间还在 <a href="https://my.linost.com/aff.php?aff=1674" target="_blank">Linost</a> 上买了一年的 SSH 代理服务并使用至今，现在看到 SSH 代理服务器被 GFW 封的越来越厉害，于是想自己搞个 VPS 跑 WordPress 博客程序，顺带跑下 Shadowsocks 用来爬墙比较方便（只要不是流量很高被 GFW 盯上了一般不易被封）。</p>
<p>左挑右选之后还是决定先拿一个性价比比较高的 VPS 来练练手，因此在 <a href="https://my.linost.com/aff.php?aff=1674" target="_blank">Linost</a> 主机快到期的时候在 HighSpeedWeb 上买了一个 OpenVZ 256MB 内存的 VPS。官网在此：</p>
<p><a href="http://www.highspeedweb.net/" target="_blank">http://www.highspeedweb.net/</a></p>
<p>OpenVZ 256MB VPS 正常价格是 15 美元一年，使用 <strong>25OFF</strong> 这个优惠码之后可以打 75 折还是相当划算的。购买之前还比较顺利，但在提交完订单准备 PayPal 付款时遇到麻烦，主机系统报未通过 MaxMind 检查，提示是高危欺诈订单，而且我填的名字、地址、电话之类的都是真实信息，无奈只能提交一个工单，说明我的 IP 地址和实际地址是对应的，几番沟通之后终于客服把订单给恢复正常了。</p>
<p>为节省内存，VPS 用了 Debian 7.0 32 位的系统，系统里的无关服务基本都被停掉，只保留了 SSH、cron 等基础服务，移除掉自带的 Apache 支持（256MB 内存真心有点带不动），然后从 <a href="http://www.lnmp.org/" target="_blank">http://www.lnmp.org/</a> 上下载了最新稳定版的 LNMP 服务器套件并编译安装。</p>
<p>把原来备份的 Web 目录文件和 MySQL 数据导入 VPS 系统，稍加修修改，更改域名 A 记录之后，博客网站就迁移过来。接下来就装了一个 Shadowsocks 服务器用来爬墙，可惜由于 OpenVZ 系统诸多限制无法优化提升代理性能，但日常使用也还算没什么问题。</p>
<p>最后把年前弄的七牛云存储的 CDN 加速功能开启了，用 WordPress 另外安装的 WP Super Cache 插件设置 CDN 服务器地址之后让七牛云存储缓存静态内存，结果博客网页整体打开速度也提升了，最主要这样也减少了对我这种低配置 VPS 的 CPU 和 内存压力。</p>
<p>虽然 OpenVZ 的 VPS 相对与 KVM 和 Xen 的来说可玩性低些，但下面等有空时还是可以再搞搞 VPS 上的 rsync 备份之类的，最后还是 HighSpeedWeb 尽量稳定咯~~~</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/blog-hswvps/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
