树莓派网关代理

参考文章树莓派二代 dnsmasq ipset iptables shadowsocks 网关代理将gfwlist转换成带ipset的dnsmasq规则,适用于OpenWrt智能上网使用ipset让openwrt上的shadowsocks更智能的重定向流量的补充终于折腾好了。

先简单说下原理。一般来说,正常的上网是通过路由器拨号上网并充当网关进行 NAT 转发,实现本地局域网内多台设备同时上网。而问题在于,路由器一般功能有限无法提供更加智能的网关业务处理。除非路由器支持第三方固件升级,如 OpenWrt 或 DDWrt 等。实际上,除开路由器网关,可以使用其他电脑(比如树莓派)充当二级网关,来解决此问题。

原有的网络拓扑是路由器 IP 为 192.168.1.1,通过路由器上的 DHCP 指定网关为 192.168.1.1,主 DNS 服务器为 119.29.29.29 备选 DNS 服务器为 114.114.114.114。

修改后的网络拓扑是路由器 IP 为 192.168.1.1,树莓派 IP 为 192.168.1.2,通过路由器上的 DHCP 指定网关为 192.168.1.2,主 DNS 服务器为 192.168.1.2 备选 DNS 服务器为 119.29.29.29。树莓派的网关为 192.168.1.1,手工指定主 DNS 服务器为 119.29.29.29 备选 DNS 服务器为 114.114.114.114。

所以第一步需要将树莓派设置为 iface eth0 inet static,执行 sudo nano /etc/network/interfaces,修改内容如下:

auto lo

iface lo inet loopback

auto eth0
#iface eth0 inet dhcp
iface eth0 inet static
        address 192.168.1.2
        netmask 255.255.255.0
        network 192.168.1.0
        gateway 192.168.1.1

然后,执行 sudo nano /etc/resolv.conf,修改内容如下:

nameserver 119.29.29.29
nameserver 114.114.114.114

下一步是打开 NAT 网关,执行 sudo nano /etc/sysctl.conf,修改指定行为:

net.ipv4.ip_forward=1

检查 sudo nano /etc/iptables.up.rules,如果有 8080 转发,请禁止

:POSTROUTING ACCEPT [0:0]
#-A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8081
#-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
COMMIT

NAT 需要重启才能生效。这样,树莓派可以充当一个普通的网关代理,但没有 DNS 服务。此时可以将客户端网关修改为 192.168.1.2,DNS 服务器指定为 119.29.29.29 检查是否可以上网。

我们知道,通过域名访问任何一项网络服务,都先必须解析域名。现在要做的就是,树莓派使用 dnsmasq 提供局域网的 DNS 服务,使用特殊的规则解析指定的域名,并将解析到的 IP 加入 ipset 规则组,然后 iptables nat 使用 ipset 指定的规则组自动走 shadowsocks 的代理线路进行访问。从而达到我们的目的。

需要安装的包有:sudo apt-get install ipset dnsmasq shadowsocks-libev

我们并不需要 shadowsocks-libev 自带的 server 服务,执行 sudo update-rc.d shadowsocks-libev remove 禁止自动启动服务。

替代的是使用 ss-redir 连接 shadowsocks 代理服务器(通常会使用的是 ss-local 来开启 socks 代理,但 redir 会减少 socks 代理开销)。

手工建立 shadowsocks-redir 服务,执行:

sudo cp /etc/init.d/shadowsocks-libev /etc/init.d/shadowsocks-redir
sudo cp /etc/default/shadowsocks-libev /etc/default/shadowsocks-redir
sudo cp /etc/shadowsocks-libev/config.json.dpkg-old /etc/shadowsocks-libev/redir.json

需要 sudo nano /etc/init.d/shadowsocks-redir 将相关 shadowsocks-libev 改为 shadowsocks-redir,以及 ss-server 改为 ss-redir

# Provides:          shadowsocks-redir
DESC=shadowsocks-redir       # Introduce a short description here
NAME=shadowsocks-redir       # Introduce the short server's name here
DAEMON=/usr/bin/ss-redir     # Introduce the server's location here

sudo nano /etc/default/shadowsocks-redir 修改 CONFFILE

CONFFILE="/etc/shadowsocks-libev/redir.json"

sudo nano /etc/shadowsocks-libev/redir.json 配置 local_address 和端口,需要绑定 0.0.0.0 和 1080 端口(建议)

{
    "server":"example.com",
    "server_port":10307,
    "local_address":"0.0.0.0",
    "local_port":1080,
    "password":"password"
}

开启服务,并设置自动启动服务

sudo service shadowsocks-redir start 
sudo update-rc.d shadowsocks-redir defaults

可以使用 sudo netstat -nlp | grep redir 查看服务端口是否正常。

使用 sudo ipset -N ss iphash 创建新的 ipset 规则组,因为系统重启后 ipset 数据会丢失,建议将 ipset -N ss iphash 加入到 /etc/init.d/networkingstart> 中,如

case "$1" in
start)
        if init_is_upstart; then
                exit 1
        fi
        ipset -N ss iphash
        process_options
        check_ifstate

否则,修改 iptables 默认规则后,会导致 ss 规则找不到,从而无法启动网络。

修改 iptables nat 规则,sudo iptables -t nat -A PREROUTING -p tcp -m set --match-set ss dst -j REDIRECT --to-port 1080

因为 iptables 重启后规则失效,需要修改 sudo nano /etc/iptables.up.rules

:POSTROUTING ACCEPT [0:0]
-A PREROUTING -p tcp -m set --match-set ss dst -j REDIRECT --to-port 1080
COMMIT

下一步就是配置 dnsmasq,首先打开 sudo nano /etc/dnsmasq.conf,修改

# Include another lot of configuration options.
#conf-file=/etc/dnsmasq.more.conf
conf-dir=/etc/dnsmasq.d

然后创建一个 google 的规则 sudo nano /etc/dnsmasq.d/google.conf 内容为

server=/.googleapis.com/208.67.222.222#5353
ipset=/.googleapis.com/ss
server=/.google.com/208.67.222.222#5353
ipset=/.google.com/ss

使用 sudo service dnsmasq restart 重启服务,并将客户端的网关和 DNS 服务器都改为 192.168.1.2 即可以直接访问 google。

最后一步就是每天自动更新 gfwlist 规则为 dnsmasq 配置了。执行 sudo nano /etc/cron.daily/dnsmasq-gfwlist.py,内容为 https://gist.github.com/larryli/bf0671b41ede5d77c52862f57fff6159

所有测试没问题后,请将路由器 DHCP 服务器,将网关设置为 192.168.1.2,DNS 服务器为 192.168.1.2 即完成所有配置。

树莓派+USB 摄像头家用监控

raspbian 下很简单,直接安装 motion 即可:

sudo apt-get install motion

不过需要手工打开服务配置:

sudo nano /etc/default/motion

start_motion_daemon=no 修改为:

start_motion_daemon=yes

处理一个小的权限问题:

sudo chmod 777 /var/lib/motion

sudo service motion start 启动服务。

默认会使用 /dev/video0 这个设备,请确定 USB 摄像头插上去,能否 lsusb 列出,并且设备映射成功。

在路由器开放外网端口之前可以修改 /etc/motion/motion.conf 文件中以下配置:

width 640
height 480 # 视频大小
text_right Larry Li(Shenzhen)n%Y-%m-%d %T-%q # 右下角文字
text_left CAMERA rpi1 # 左下角文字
target_dir /var/lib/motion # 文件存放位置,需要 chmod 777
picture_filename %Y%m%d/%H%M%S-%v-%q # 也可以按 %Y/%m/%d/%H%M%S-%v-%q 年月日一层一层建目录存放
movie_filename %Y%m%d/%H%M%S-%v # 其他几个 filename 配置也相同处理
stream_port 8081 # 指定实时 http 监控端口
stream_localhost off # 需要将 on 修改为 off 取消仅 localhost 访问限制
stream_limit 2 # 最好设置一个访问数限制
stream_auth_method 1 # 1 是标准的 basic auth
stream_authentication username:password # 用户名和密码
webcontrol_port 0 # 关闭控制端口,或者也设置 basic auth 的用户名和密码 

然后使用 btsync 把 /var/lib/motion 共享给手机和远程电脑,我直接使用了 rw 读写模式,手工在远程删除旧文件。

PHP 切换到 7.0

用的是 ppa:ondrej/php-7.0

sudo add-apt-repository ppa:ondrej/php-7.0
sudo apt-get update
udo apt-get install php7.0-cli php7.0-fpm php7.0-gd php7.0-json php7.0-mcrypt php7.0-mysql php7.0-readline php7.0-sqlite php-apcu

有一个坑需要注意的是,sock 文件是从 /var/run/php5-fpm.sock 变成了 /var/run/php/php7.0-fpm.sock

因为 VPS 性能所限,整体提升并不是很给力,只是一两倍而已。

Git 提交 GnuPG 自动签名

一般来说使用 git commit -S 就调用 gpg 工具自动搜索 user.name<user.email> 对应的私钥来签名提交。

git 2.0 以上版本提供了 commit.gpgsign 设置可以自动打开 gpg 签名选项。

然后配合 user.signingkey 就可以设置默认的 key 来自动签名了。

git config --global user.name "Larry Li"
git config --global user.email larryli@qq.com
git config --global user.signingkey 2D8B022C
git config --global commit.gpgsign true

密钥 2D8B022C 可以通过 gpg -K 查看可用的私钥。

WebSocket、API 与 Push 推送

WebSocket 从 2010 年出现到现在已经五六年了,目前来说主流浏览器已经对其普遍支持,但实际运行却非常之少。

一般来说,WebSocket 都是双向全双工通信的。所以很容易设计一个异步协议 WAMP,提供异步的 RPC 远程调用Publish & Subscribe 模式实现。

但是,这种设计完全无视了 WebSocket 是基于 HTTP 协议的。也就是说,HTTP 使用 url 来路由,WebSocket 也同样可以用 url 来路由。

就拿 Pub/Sub 模式来说,WebSocket 天生就可以使用不用的路由来表示不同的 Pub。

而浏览器作为 Client 去 Call 服务器不正是 RESTful API 该做的事情么?

那么,除非是服务器要去 Call 浏览器端,WAMP 的大部分设计都是不需要的。

WebSocket 真的只需要简单的使用,就如它一开始被赋予的使命一样,作为一个 Push 及时的把服务端最新的消息推送到客户端。甚至消息都不需要包含实体,而只是一个通知即可。