Nginx https load-balance on Raspberry Pi

我的Raspberry Pi工作了大约半年之后,文件系统开始出现莫名其妙的问题,各种文件都出现乱码,以至于某系统命令一执行就segment fault。到重新“安装”系统的时候了。

之前主要跑的服务是我的博客,nginx + wordpress搭的,在RPi上因为CPU的问题(php-fpm执行时几乎占满cpu),响应比较慢。既然重新弄了,考虑把某些请求交给家里的其它机器来处理。
家里还有一台跑Ubuntu的笔记本,希望满足如下要求:
1) 如果笔记本开机着,http请求(几乎)都交给笔记本处理;
2) 如果笔记本关机,http请求都由RPi来处理;
这些应该是完全自动实现的。

在Stackoverflow上问了这个问题,有人提示说可以通过nginx的load-balance功能来实现我的需求。于是开始google一番,找到了解决方案。
基本的思想是,把nginx配置成反向代理,笔记本和RPi都作为upstream来处理http请求;通过nfs共享同一个wordpress目录;配置mysql让wordpress访问同一个数据库。
一步一步来配置这些。
其中Raspberry Pi的地址固定为192.168.1.100,笔记本的地址固定为192.168.1.101,数据库名为minewpdb,数据库用户名为minedb

1. 配置Mysql
mysql仍然放在RPi上,让mysql接受网络的请求,这样不同的机器可以用同一个mysql数据库。

sudo vim /etc/mysql/my.cnf
==> 把 bind-address 改成RPi的ip地址
bind-address            = 192.168.1.100

mysql -u root -p #登录mysql控制台
mysql> grant all on minewpdb.* to 'mineblog'@'192.168.1.100' identified by 'xxx'; # 本地RPi的wordpress访问
mysql> grant all on minewpdb.* to 'mineblog'@'192.168.1.101' identified by 'xxx'; # 笔记本的wordpress访问
mysql> quit;
sudo service mysql restart # 重启mysql服务

# 在RPi和笔记本上分别测试一下
mysql -u mineblog -h 192.168.1.100 -p # 如果能登录成功,就ok了

2. 配置wordpress
Wordpress仍然在RPi上,只要修改wordpress的config文件,把数据库的host,用户名和密码都设对就行了。

sudo vim /path/to/wordpress/wp-config.php
==> 修改DB_HOST等参数
define('DB_NAME', 'minewpdb');
define('DB_USER', 'mineblog');
define('DB_PASSWORD', 'xxx');
define('DB_HOST', '192.168.1.100');

3. 配置nfs
在RPi上设置nfs export,让笔记本mount它,这样可以保证跑的wordpress是同一份。

sudo vim /etc/exports
==> 添加wordpress目录到exports
/path/to/wordpress 192.168.1.101(rw,no_root_squash,insecure,sync,no_subtree_check)
sudo service rpcbind start  # RPi的nfs依赖于rpcbind
sudo update-rc.d rpcbind enable  # 设置rpcbind自动启动
sudo service nfs-kernel-server start  # 重启nfs

在笔记本上,mount这个目录:

sudo mount -t nfs 192.168.1.100:/path/to/wordpress /path/to/wordpress

4. 配置nginx
在RPi上要把nginx配置成反向代理,upstream是RPi和笔记本,端口号都是8000,真正的wordpress运行在8000端口上。
添加新的配置文件 /etc/nginx/sites-available/wordpress-load-balance,注意我把http的访问全部重定向到https,以防GFW

# Upstream to abstract backend connection(s) for php
upstream php {
server unix:/var/run/php5-fpm.sock;
}

upstream mineservers {
# 设置两个upstream, 其中笔记本优先,同时设置5s的fail_timout
# 因为局域网很稳定,所以max_fails设成1就行了,
# 如果fail就说明笔记本关机中,让RPi自己来处理
server 192.168.1.101:8000   weight=999 fail_timeout=5s max_fails=1;
server 192.168.1.100:8000;
}

server {
listen 80;
server_name mine260309.me;
rewrite     ^ https://$server_name$request_uri? permanent;
}

server {
listen          443 ssl;
server_name     mine260309.me;

ssl_certificate     /path/to/cert/mine260309.me.2014.chain.crt;
ssl_certificate_key /path/to/cert/mine260309.me.2014.key;
ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;
access_log         /path/to/wordpress/logs/proxy.log;
error_log            /path/to/wordpress/logs/proxy_error.log;

location / {
# 代理到upstream
proxy_pass  http://mineservers;

### force timeouts if one of backend is died ##
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

### Set headers ####
proxy_set_header        Accept-Encoding   "";
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

### Most PHP, Python, Rails, Java App can use this header ###
#proxy_set_header X-Forwarded-Proto https;##
#This is better##
proxy_set_header        X-Forwarded-Proto $scheme;
add_header              Front-End-Https   on;

### By default we don't want to redirect it ####
proxy_redirect     off;
}
}

server {
root /path/to/wordpress;
# 在8000端口监听
listen          8000;
server_name     mine260309.me;
... # normal wordpress configurations
}

在笔记本上用同样的配置就可以了。

这样,任何一个请求到RPi,它会让nginx优先反向代理到笔记本的nginx的8000端口,由笔记本来处理;
如果笔记本关机,在5秒钟之后它会fail,于是再由RPi自己的8000端口处理。

Q.E.D.

Share