nginx1.4.1をchefでソースからインストールしてみる(websocket proxy)
以前、Vagrant上にNode.jsの環境構築を行いましたが、nginx1.3からwebsocketのproxyが可能になったとのことなので、最新の安定版であるnginx1.4.1をchefでインストールして、websocketのproxyができるまでを確認してみました。
前提条件
nginx1.4のレシピ作成
- レシピのスケルトン作成
cd /etc/chef
bin/knife cookbook create nginx1.4 -o site-cookbooks/
- recipes/default.rb を追加
vi site-cookbooks/nginx1.4/recipes/default.rb
bash "install_nginx" do
user "root"
group "root"
cwd "/tmp"
flags "-e"
code <<-EOH
rm -rf nginx-1.4.1.tar.gz
rm -rf nginx-1.4.1
rm -rf pcre-8.32.tar.gz
rm -rf pcre-8.32
wget http://nginx.org/download/nginx-1.4.1.tar.gz
tar zxf nginx-1.4.1.tar.gz
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.32.tar.gz
tar -xvf pcre-8.32.tar.gz
cd nginx-1.4.1
./configure --prefix=/usr/local --conf-path=/etc/nginx/nginx.conf --user=nginx --group=nginx --with-pcre=/tmp/pcre-8.32
make
make install
chkconfig nginx on
EOH
creates "/usr/local/sbin/nginx"
end
directory '/etc/nginx' do
mode 0755
owner 'root'
group 'root'
recursive true
end
template '/etc/nginx/nginx.conf' do
source 'nginx.conf.erb'
end
directory '/var/log/nginx' do
mode 0755
owner 'root'
group 'root'
recursive true
end
- nginx.conf.erb を追加
vi site-cookbooks/nginx1.4/templates/default/nginx.conf.erb
user nobody;
worker_processes 4;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 2048;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location = /50x.html {
root html;
}
}
include /etc/nginx/vhost.d/*.conf;
}
- initスクリプト作成レシピ
site-cookbooks/nginx1.4/recipes/initfile.rb
template "/etc/rc.d/init.d/nginx" do
source 'initfile.erb'
owner "root"
group "root"
mode "0755"
end
service "nginx" do
supports :status => true, :restart => true, :reload => true
action [:enable, :start]
end
- initスクリプトテンプレート追加
vi site-cookbooks/nginx1.4/templates/default/initfile.erb
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: Nginx is an HTTP(S) server, HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /etc/nginx/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /var/run/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/local/sbin/nginx"
prog=$(basename $nginx)
sysconfig="/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/nginx"
pidfile="/var/run/${prog}.pid"
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
[ -f $sysconfig ] && . $sysconfig
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc -p $pidfile $prog
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest_q || return 6
stop
start
}
reload() {
configtest_q || return 6
echo -n $"Reloading $prog: "
killproc -p $pidfile $prog -HUP
echo
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
configtest_q() {
$nginx -t -q -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
# Upgrade the binary with no downtime.
upgrade() {
local oldbin_pidfile="${pidfile}.oldbin"
configtest_q || return 6
echo -n $"Upgrading $prog: "
killproc -p $pidfile $prog -USR2
retval=$?
sleep 1
if [[ -f ${oldbin_pidfile} && -f ${pidfile} ]]; then
killproc -p $oldbin_pidfile $prog -QUIT
success $"$prog online upgrade"
echo
return 0
else
failure $"$prog online upgrade"
echo
return 1
fi
}
# Tell nginx to reopen logs
reopen_logs() {
configtest_q || return 6
echo -n $"Reopening $prog logs: "
killproc -p $pidfile $prog -USR1
retval=$?
echo
return $retval
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest|reopen_logs)
$1
;;
force-reload|upgrade)
rh_status_q || exit 7
upgrade
;;
reload)
rh_status_q || exit 7
$1
;;
status|status_q)
rh_$1
;;
condrestart|try-restart)
rh_status_q || exit 7
restart
;;
*)
echo $"Usage: $0 {start|stop|reload|configtest|status|force-reload|upgrade|restart|reopen_logs}"
exit 2
esac
- websocket proxy 確認用のバーチャルホスト設定
vi site-cookbooks/nginx1.4/recipes/vhost.rb
# nginx.conf
directory '/etc/nginx/vhost.d/' do
mode 0755
owner "root"
group "root"
recursive true
end
template '/etc/nginx/vhost.d/example.com.conf' do
source 'example.com.conf.erb'
variables(
:nginx_port => node[:nginx][:port],
)
end
- バーチャルホストテンプレート追加
vi site-cookbooks/nginx1.4/templates/default/example.com.conf.erb
server {
listen <%= @nginx_port %>;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Host $host;
}
}
- jsonに追記
{
"nginx": {
"port": 80
},
"run_list":[
"nodejs",
"iptables",
"nginx1.4::default",
"nginx1.4::initfile",
"nginx1.4::vhost"
]
}
- cook
/bin/knife solo cook nodejs
- vagrantにログインしてインストール確認
ssh nodejs
nginx -v
nginx version: nginx/1.4.1
これでnginx1.4.1がインストールできました。
websocketのproxy検証
- macの/etc/hostsにバーチャルホストのドメインを追加
sudo vi /etc/hosts
192.168.33.10 example.com
- socket.ioのサンプル作成
# モジュールインストール
npm install express
npm install ejs
npm install socket.io
# スケルトン作成
./node_modules/.bin/express -e
# app.js にsocket通信イベント追加
vi app.js
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
var server = http.createServer(app);
server.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
console.log('connection');
socket.on('disconnect', function() {
console.log('disconnected');
});
});
# index.ejsテンプレート編集
vi views/index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript">
var socket = io.connect();
socket.on('connect', function() {
alert('socket connected');
});
</script>
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
</body>
</html>
# アプリケーション起動
node app.js
- ブラウザからアクセス
「socket connected」のアラートが表示されてwebsocketのproxyができていることを確認できます。