<?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; OpenWRT</title>
	<atom:link href="https://zohead.com/archives/tag/openwrt/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>香橙派R1 Plus LTS软路由体验</title>
		<link>https://zohead.com/archives/r1-plus-lts/</link>
		<comments>https://zohead.com/archives/r1-plus-lts/#comments</comments>
		<pubDate>Sun, 21 Aug 2022 12:32:40 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[数码]]></category>
		<category><![CDATA[网络]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[R1 Plus LTS]]></category>
		<category><![CDATA[红米]]></category>
		<category><![CDATA[路由器]]></category>
		<category><![CDATA[香橙派]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1768</guid>
		<description><![CDATA[去年家里装修好之后为了一步到位就打算把无线网络也升级到 WiFi 6 了，不过可惜买的时候没注意，选了有点坑的 红米 AX3000 路由器（不是老的红米 AX6，这款的实际产品型号为：RA81）。这款路由器用的是高通 IPQ5000 处理器，集成 256MB 内存，WiFi 6 功能用起来虽然也没有太大的问题，只是开机运行时间久了总会有卡卡的感觉，最主要小米的魔改系统没有给 SSH 权限，而网上其它小米路由器的破解 SSH 方法对这款路由器并不起作用。 最近我想了想还是准备上个采用标准 OpenWRT 系统的软路由，红米 AX3000 路由器就准备只用来发射 WiFi 信号了。软路由原本考虑很 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>去年家里装修好之后为了一步到位就打算把无线网络也升级到 WiFi 6 了，不过可惜买的时候没注意，选了有点坑的 <a href="https://www.mi.com/shop/buy/detail?product_id=14538" target="_blank">红米 AX3000 路由器</a>（不是老的红米 AX6，这款的实际产品型号为：RA81）。这款路由器用的是高通 IPQ5000 处理器，集成 256MB 内存，WiFi 6 功能用起来虽然也没有太大的问题，只是开机运行时间久了总会有卡卡的感觉，最主要小米的魔改系统没有给 SSH 权限，而网上其它小米路由器的破解 SSH 方法对这款路由器并不起作用。</p>
<p>最近我想了想还是准备上个采用标准 OpenWRT 系统的软路由，红米 AX3000 路由器就准备只用来发射 WiFi 信号了。软路由原本考虑很多网友用过的友善 <a href="https://www.friendlyelec.com/index.php?route=product/product&amp;path=69&amp;product_id=282" target="_blank">NanoPi R2S</a>，只是最近这款软路由的溢价实在有点多，一番了解之后还是定下了迅龙推出的与 R2S 配置基本相同的 <a href="http://www.orangepi.cn/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-R1-Plus-LTS-Router.html" target="_blank">Orange Pi R1 Plus LTS</a> 软路由。</p>
<h2 id="intro">介绍</h2>
<p>R1 Plus LTS 软路由的基本硬件参数如下：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>Rockchip RK3328</td>
</tr>
<tr>
<td>GPU</td>
<td>Mali-450MP2</td>
</tr>
<tr>
<td>内存</td>
<td>1GB LPDDR3</td>
</tr>
<tr>
<td>WAN</td>
<td>裕太微 YT8531C 10M/100M/1000M 以太网</td>
</tr>
<tr>
<td>LAN</td>
<td>Realtek RTL8153B 10M/100M/1000M USB 以太网</td>
</tr>
<tr>
<td>尺寸</td>
<td>63mm X 60.6mm X 27.25mm</td>
</tr>
<tr>
<td>重量</td>
<td>175g</td>
</tr>
</tbody>
</table>
<p>其实香橙派之前还出了一款 R1 Plus 软路由，与我买的 R1 Plus LTS 区别也很小：</p>
<ul>
<li>R1 Plus 用的是 1GB DDR4 内存；</li>
<li>R1 Plus 的 WAN 口使用的是 Realtek RTL8211E PHY。</li>
</ul>
<p>所以 R1 Plus LTS 相当于是 R1 Plus 的低配版，只是可能由于芯片短缺等原因 R1 Plus 现在也基本上买不到了。</p>
<p>我购买的 R1 Plus LTS 软路由是自带官方金属外壳的，而且开发板本身都已经装好固定了的，因此主板本身我也就没拆了，看看软路由的外观：</p>
<p><img src="https://images.weserv.nl/?url=http://res.cloudinary.com/digwht2y0/image/upload/v1737442932/r1pluslts-appearance.jpg" alt="R1 Plus LTS 软路由"></p>
<p>前面是 TF 卡槽以及 SYS、LAN、WAN 指示灯，后面就是供电接口以及两个网口了。</p>
<p>本来打算用闲置的华为手机充电器，又考虑到放在家里需要长期稳定运行，我也顺便买了官方的 5V 3A USB Type-C 电源适配器：</p>
<p><img src="https://images.weserv.nl/?url=http://res.cloudinary.com/digwht2y0/image/upload/v1737442932/r1pluslts-charger.jpg" alt="R1 Plus LTS 电源适配器"></p>
<h2 id="system">系统</h2>
<p>我找了一张老的 8GB TF 卡做系统盘，为了稳定也用的是官方提供的最新 OpenWrt 21.02.1 r16325-88151b8303 版本系统，也不考虑第三方固件提供的各种花里胡哨的功能了。</p>
<p>为了方便我也没有使用官方用户手册里推荐的 <code>Win32Diskimager</code> 或者 <code>balenaEtcher</code> 之类的工具来烧写镜像，直接用 Linux 自带的 <code>dd</code> 命令进行烧写：</p>
<blockquote>
<p><strong>备注</strong></p>
<p>我的笔记本自带了 PCIe 的读卡器，所以这里的 <code>dd</code> 命令写的是 <code>/dev/mmcblk0</code> 设备，如果用的是 USB 读卡器，应该就要换成 <code>/dev/sdb</code> 之类的设备。</p>
</blockquote>
<pre class="brush: bash; title: ; notranslate">
~# dd if=openwrt-rockchip-armv8-xunlong_orangepi-r1-plus-lts-ext4-sysupgrade.img of=/dev/mmcblk0 bs=1024k
</pre>
<p>由于 <code>dd</code> 命令没有校验的功能，烧写完成之后可以强制检查一下系统是否正确：</p>
<pre class="brush: bash; title: ; notranslate">
~# e2fsck -f /dev/mmcblk0p2
</pre>
<p>系统烧写完成之后就可以插到软路由上启动了，OpenWRT 系统第一次启动的时候会自动扩容 rootfs 分区，启动完成之后可以登录系统确认 rootfs 分区大小是否正确。</p>
<p>首先通过 SSH 登录或者 LuCI Web 管理界面修改 OpenWRT 的镜像源，这里我用的是清华的镜像源：</p>
<pre class="brush: bash; title: ; notranslate">
~# cat /etc/opkg/distfeeds.conf
src/gz openwrt_core https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/targets/rockchip/armv8/packages
src/gz openwrt_base https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/packages/aarch64_generic/base
~# cat /etc/opkg/customfeeds.conf
src/gz openwrt_luci https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/packages/aarch64_generic/luci
src/gz openwrt_packages https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/packages/aarch64_generic/packages
src/gz openwrt_routing https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/packages/aarch64_generic/routing
src/gz openwrt_telephony https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/21.02.1/packages/aarch64_generic/telephony
</pre>
<p>香橙派官方提供的 OpenWRT 系统自带了 Adblock、Squid、Transmission 甚至 Docker 等软件的支持，用户也可以自行卸载，例如卸载 MiniDLNA：</p>
<pre class="brush: bash; title: ; notranslate">
~# opkg remove luci-i18n-minidlna-zh-cn luci-app-minidlna minidlna
</pre>
<p>通过 SSH 登录可以看到 OpenWRT 系统的 Linux 内核是 5.4 版本的，应该也够用了：</p>
<pre class="brush: bash; title: ; notranslate">
~# uname -a
Linux R1PlusLTS 5.4.154 #0 SMP PREEMPT Sun Oct 24 09:01:35 2021 aarch64 GNU/Linux
</pre>
<p>然后是 CPU 信息：</p>
<pre class="brush: bash; title: ; notranslate">
~# cat /proc/cpuinfo
processor    : 0
BogoMIPS    : 48.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant   : 0x0
CPU part    : 0xd03
CPU revision  : 4
</pre>
<h2 id="luci-issue">LuCI 问题</h2>
<p>值得一提的是我使用 Chrome 浏览器访问 OpenWRT 的 LuCI Web 管理界面经常出现类似 <code>_(...).format is not a function</code> 这样的报错，控制台还有其它错误：</p>
<pre class="brush: plain; title: ; notranslate">
A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
</pre>
<p>后来发现使用 Chrome 无痕式窗口访问 LuCI Web 界面就没有问题，因此怀疑是某些 Chrome 扩展导致的，经常一番禁用扩展并测试，确认是由 <a href="https://chrome.google.com/webstore/detail/tronlink/ibnejdfjmmkpcnlpebklmnkoeoihofec" target="_blank">TronLink</a> 这个波场官方的钱包导致的，禁用 TronLink 扩展就可以正常访问 LuCI 界面。</p>
<p>不过为了能正常使用 TronLink 钱包，我还是在 TronLink 扩展的详情页将 <strong>允许此扩展程序读取和更改您在所访问的网站上留存的所有数据</strong> 选项由 <strong>在所有网站上</strong> 改为了 <strong>点击时</strong>，这样 LuCI 界面和 TronLink 就都可以用了。</p>
<h2 id="performance">性能</h2>
<p>这里我就不做常见的 CPU 性能、加解密性能测试了，因为 RK3328 的性能已经有好多网友测试过了，我主要关注 LAN 口 RTL8153B USB 网卡的性能。</p>
<p>我的笔记本直接带了千兆有线网卡，这样我就将笔记本通过千兆网线接到软路由的 LAN 口，用 <code>iperf</code> 命令做一下简单的测试了，先看看 LAN 口接收数据的性能：</p>
<pre class="brush: bash; title: ; notranslate">
~# iperf -s -w 512K
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 1.00 MByte (WARNING: requested 512 KByte)
------------------------------------------------------------
[ 4] local 192.168.2.1 port 5001 connected with 192.168.2.57 port 65244
[ ID] Interval    Transfer   Bandwidth
[ 4] 0.0-30.0 sec 3.31 GBytes  949 Mbits/sec
</pre>
<p>接着我又测试了 LAN 口发送数据的性能：</p>
<pre class="brush: bash; title: ; notranslate">
root@R1PlusLTS:~# iperf -c 192.168.2.57 -w 512K -t 30
------------------------------------------------------------
Client connecting to 192.168.2.57, TCP port 5001
TCP window size: 1.00 MByte (WARNING: requested 512 KByte)
------------------------------------------------------------
[ 3] local 192.168.2.1 port 44562 connected with 192.168.2.57 port 5001
[ ID] Interval    Transfer   Bandwidth
[ 3] 0.0-30.0 sec 3.30 GBytes  946 Mbits/sec
</pre>
<h2 id="summary">总结</h2>
<p>最后我把 R1 Plus LTS 软路由的联网配置好之后，将原来的红米 AX3000 路由器的 WAN 口接到 R1 Plus LTS 的 LAN 口，并把 AX3000 从 <strong>普通路由</strong> 模式切换为 <strong>有线中继</strong> 模式，这样原有的手机之类的无线终端设备就能继续上网了：</p>
<p><img src="https://images.weserv.nl/?url=http://res.cloudinary.com/digwht2y0/image/upload/v1737370582/ax3000-ap.png" alt="红米 AX3000 有线中继"></p>
<p>由于 R1 Plus LTS 软路由只有一个 LAN 口，家里的 NAS 服务器只能接在红米 AX3000 路由器上了。还好 AX3000 使用有线中继模式之后，终端设备与软路由也还在同一网段，而且上面的测试结果可以看出软路由的 LAN 口性能也不是瓶颈，我用支持 WiFi 6 的电脑和手机访问 NAS 服务器的速度也没什么问题，可以满足日常使用需求了。</p>
<p>最后说一下 R1 Plus LTS 软路由的散热，我购买的是自带官方金属外壳的版本，这两个月连续运行下来我发现也挺稳定的，通过命令可以查看 CPU 温度：</p>
<pre class="brush: bash; title: ; notranslate">
root@R1PlusLTS:~# cat /sys/class/thermal/thermal_zone0/temp
56818
</pre>
<p>上面结果中的 57 摄氏度是在南京接近 40 度的高温下室内不开空调看到的，实际使用下来我还没有遇到温度超过 60 摄氏度的情况，看起来挺过这个最热夏天之后，R1 Plus LTS 软路由就可以留下来暂定长期使用了。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/r1-plus-lts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>OpenWRT实现OpenVPN按ipset自动分流</title>
		<link>https://zohead.com/archives/openwrt-openvpn-ipset/</link>
		<comments>https://zohead.com/archives/openwrt-openvpn-ipset/#comments</comments>
		<pubDate>Sun, 16 Jul 2017 04:35:35 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[网络]]></category>
		<category><![CDATA[dnsmasq]]></category>
		<category><![CDATA[gfwlist]]></category>
		<category><![CDATA[ipset]]></category>
		<category><![CDATA[iptables]]></category>
		<category><![CDATA[newifi mini]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[PandoraBox]]></category>
		<category><![CDATA[TUN]]></category>
		<category><![CDATA[Windscribe]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1476</guid>
		<description><![CDATA[接着上面一篇介绍 Windscribe 免费 VPN 的文章，住处的网络通过 OpenVPN 连接 Windscribe 之后虽然速度不快，但好歹广电宽带下没有之前用的几个 VPS 经常超时的问题了。因此想着最好能部署到现在用的 newifi mini 路由器上（毕竟已经刷了 PandoraBox 固件），目标就是能在路由器上用 OpenVPN 连接 Windscribe 并自动分流翻墙访问某些特殊的网站。 OpenWRT 安装使用 OpenVPN 首先在路由器上安装 OpenVPN 客户端： 把上篇文章中生成的 Windscribe OpenVPN 配置文件上传到 /etc/openvpn  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>接着上面一篇介绍 <a href="https://zohead.com/archives/windscribe-openvpn/">Windscribe 免费 VPN</a> 的文章，住处的网络通过 OpenVPN 连接 Windscribe 之后虽然速度不快，但好歹广电宽带下没有之前用的几个 VPS 经常超时的问题了。因此想着最好能部署到现在用的 newifi mini 路由器上（毕竟已经刷了 PandoraBox 固件），目标就是能在路由器上用 OpenVPN 连接 Windscribe 并自动分流翻墙访问某些特殊的网站。</p>
<h2 id="openwrt-安装使用-openvpn">OpenWRT 安装使用 OpenVPN</h2>
<p>首先在路由器上安装 OpenVPN 客户端：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]# opkg update
[root@PandoraBox:/root]# opkg install openvpn-openssl
</pre>
<p>把上篇文章中生成的 Windscribe OpenVPN 配置文件上传到 <code>/etc/openvpn</code> 目录，假设配置文件路径为 <code>/etc/openvpn/windscribe.ovpn</code>。</p>
<p>这里需要注意 OpenWRT 的 OpenVPN 客户端并不能像 Windows 等客户端那样提示用户输入 Windscribe VPN 连接用户名和密码，只能通过用户密码文件指定。我们需要手工生成用户密码文件 <code>/etc/openvpn/windscribe.txt</code>，文件格式为第一行用户名，第二行密码。</p>
<p>接着修改 OpenVPN 配置文件，增加一行指定用户密码文件：</p>
<pre class="brush: plain; title: ; notranslate">
auth-user-pass windscribe.txt
</pre>
<blockquote>
<p><strong>提示</strong></p>
<p>如果你使用的 OpenVPN 客户端版本比较老（比如我的 PandoraBox 系统里安装的是 2.3.6-2 版本），可能不支持 Windscribe OpenVPN 配置文件里的 <code>block-outside-dns</code> 选项，如果 OpenVPN 运行报错的话可以注释掉这个选项。</p>
</blockquote>
<p>然后修改 <code>/etc/config/openvpn</code> 配置文件增加一个新的 OpenVPN instance，新的配置名称不要与现有的重复即可：</p>
<pre class="brush: plain; title: ; notranslate">
config openvpn 'windscribe'
	option config '/etc/openvpn/windscribe.ovpn'
	option enabled '1'
</pre>
<p>剩下就是激活并启动 OpenVPN 客户端服务了：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]# /etc/init.d/openvpn enable
[root@PandoraBox:/root]# /etc/init.d/openvpn start
</pre>
<p>稍等一会，如果一切正常的话，用 <code>logread</code> 命令应该能看到 OpenVPN 的连接日志：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]# logread -f
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: TUN/TAP device tun0 opened
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: do_ifconfig, tt-&gt;ipv6=0, tt-&gt;did_ifconfig_ipv6_setup=0
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: /sbin/ifconfig tun0 10.110.34.41 netmask 255.255.254.0 mtu 1500 broadcast 10.110.35.255
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: Initialization Sequence Completed
</pre>
<p>连接上服务器之后可以看看 OpenVPN tun 设备路由信息：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.110.34.1     128.0.0.0       UG    0      0        0 tun0
0.0.0.0         10.58.71.1      0.0.0.0         UG    0      0        0 eth0.2
10.58.71.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0.2
10.110.34.0     0.0.0.0         255.255.254.0   U     0      0        0 tun0
103.10.197.3    10.58.71.1      255.255.255.255 UGH   0      0        0 eth0.2
128.0.0.0       10.110.34.1     128.0.0.0       UG    0      0        0 tun0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br-lan
</pre>
<h2 id="dnsmasq-配置修改">dnsmasq 配置修改</h2>
<p>与之前使用的 Shadowsocks 通过 ipset 自动分流类似，我们首先需要在 OpenWRT 上安装 <code>dnsmasq-full</code> 和 <code>ipset</code> 包。</p>
<p>基本原理也很简单，OpenWRT 上的 dnsmasq 服务器将 gfwlist 中的域名通过 OpenVPN 解析防止域名污染并将解析结果添加到 ipset，然后设置 ipset 中的所有 IP 地址都走 OpenVPN 翻墙，其它地址仍然走默认的宽带线路。</p>
<p>dnsmasq 使用 gfwlist 和 gfwlist 自动更新的方法可以参考我之前写的 <a href="https://zohead.com/archives/newifi-mini-openwrt/">newifi mini路由器OpenWRT初步体验</a> 文章。</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>只是自动更新 gfwlist 的 crontab 配置文件要修改一下了，因为上面的 dnsmasq 配置文件是为 Shadowsocks 本地转发解析域名准备的，这里换成 Google 提供的 <code>8.8.8.8</code> DNS 解析服务器：</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; sed -i 's/127\.0\.0\.1#5353$/8.8.8.8/g' /tmp/dnsmasq_list.conf &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>
<h2 id="配置-ipset-自动分流">配置 ipset 自动分流</h2>
<p>首先修改 <code>/etc/iproute2/rt_tables</code> 配置文件，为 OpenVPN 专门增加一个名字为 <code>gfwtable</code> 的路由表（数字不和现有的表重复即可）：</p>
<pre class="brush: plain; title: ; notranslate">
99	gfwtable
</pre>
<p>需要注意的是我们可以从上面的 OpenVPN tun 设备路由信息中看到 OpenVPN 客户端连接上服务器之后自动添加了默认路由，而为了使默认流量都走宽带线路，需要修改 OpenVPN 配置文件禁用默认路由：</p>
<pre class="brush: plain; title: ; notranslate">
route-nopull
</pre>
<p>编辑 <code>/etc/firewall.user</code> 文件增加自定义的防火墙规则：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]# cat /etc/firewall.user
ipset -N gfwlist iphash
iptables -t mangle -N fwmark
iptables -t mangle -C OUTPUT -j fwmark || iptables -t mangle -A OUTPUT -j fwmark
iptables -t mangle -C PREROUTING -j fwmark || iptables -t mangle -A PREROUTING -j fwmark
</pre>
<p>分别简单解释一下：</p>
<ul>
<li>第一行增加新的 iphash 类型的名为 <code>gfwlist</code> 的 ipset；</li>
<li>第二行在 iptables 的 <code>mangle</code> 表中新增 <code>fwmark</code> 链；</li>
<li>第三和第四行分别在 iptables 的 <code>mangle</code> 表的 <code>OUTPUT</code> 和 <code>PREROUTING</code> 链中增加 <code>fwmark</code> target，为了避免重复，增加之前都用了 iptables 命令判断原有规则是否已经存在；</li>
<li>后面三条规则有些 OpenWRT 系统里已经自带了，这里为了保险还是加上了。</li>
</ul>
<p>接着还要再修改 Windscribe OpenVPN 配置文件，增加 VPN 的启动和停止脚本设置，因为我们要在脚本中 添加 / 删除 路由和 iptables 规则：</p>
<pre class="brush: plain; title: ; notranslate">
script-security 2
up /etc/openvpn/openvpn-up.sh
down /etc/openvpn/openvpn-down.sh
</pre>
<p>当然别忘了给 OpenVPN 启动和停止脚本增加执行权限：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]#chmod +x /etc/openvpn/openvpn-up.sh /etc/openvpn/openvpn-down.sh
</pre>
<p>OpenVPN 调用启动和停止脚本的参数格式会区分 tun 和 tap 设备，对于 tun 设备脚本调用参数是这样的：</p>
<pre class="brush: bash; title: ; notranslate">
cmd tun_dev tun_mtu link_mtu ifconfig_local_ip ifconfig_remote_ip [ init | restart ]
</pre>
<p>tap 设备则是：</p>
<pre class="brush: bash; title: ; notranslate">
cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ]
</pre>
<p>这里我们只需要关心第一个 tun /tap 设备名参数，我的 OpenVPN 启动脚本如下：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]#cat /etc/openvpn/openvpn-up.sh
#!/bin/sh
ip route add 8.8.8.8 dev $1
iptables -t mangle -A fwmark -m set --match-set gfwlist dst -j MARK --set-mark 0xffff
ip rule add fwmark 0xffff table gfwtable
ip route add default dev $1 table gfwtable
iptables -I FORWARD -o $1 -j ACCEPT
iptables -t nat -I POSTROUTING -o $1 -j MASQUERADE
</pre>
<p>同样简单说明一下：</p>
<ul>
<li>首先将 <code>8.8.8.8</code> DNS 解析服务器设置为从 OpenVPN 走防止域名污染；</li>
<li>使用 iptables <code>mangle</code> 表中的 <code>fwmark</code> 链为所有目标为 gfwlist ipset 中 IP 地址的数据包打标记，这里标记号用的是 0xffff；</li>
<li>所有标记号为 0xffff 的数据包都使用上面新增的 <code>gfwtable</code> 路由表；</li>
<li><code>gfwtable</code> 路由表固定使用 OpenVPN 线路；</li>
<li>最后两条 iptables 规则也非常重要，允许路由器下的其它设备访问被封锁域名时走 OpenVPN 线路。</li>
</ul>
<p>类似的 OpenVPN 停止脚本就比较简单了：</p>
<pre class="brush: bash; title: ; notranslate">
[root@PandoraBox:/root]#cat /etc/openvpn/openvpn-down.sh
#!/bin/sh
ip rule del table gfwtable
iptables -t mangle -D fwmark -m set --match-set gfwlist dst -j MARK --set-mark 0xffff
iptables -D FORWARD -o $1 -j ACCEPT
iptables -t nat -D POSTROUTING -o $1 -j MASQUERADE
</pre>
<p>都是清理启动脚本中增加的规则，ip route 项会在 tun 设备停止时自动删除，不需要手工进行清理了。</p>
<h2 id="总结">总结</h2>
<p>经过这番对 OpenWRT 的配置折腾，现在住处的手机和电脑就都能通过 Windscribe OpenVPN 自动翻墙了。</p>
<p>最后贴上我的 newifi mini 路由器上的 Windscribe 完整 OpenVPN 配置文件给大家参考，由于文件比较长我放到 Pastebin 上了，最后祝大家炎炎夏日也能玩的开心：</p>
<p><a href="http://pastebin.com/raw.php?i=TWbaMXdg" target="_blank">http://pastebin.com/raw.php?i=TWbaMXdg</a></p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/openwrt-openvpn-ipset/feed/</wfw:commentRss>
		<slash:comments>36</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>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>
	</channel>
</rss>
