昨天终于按捺不住,把httpd换成了nginx。一天跑下来,效果优良。趁着记忆尚存,写下来备用。
任务篇
为了节约内存以及轻量级优化,将现有VPS用Apache httpd跑着的一个Django站点、一个Wordpress博客、一个Wiki、一个Mercurial版本控制和一些静态存档转移到nginx上面来。
系统篇
使用CentOS 5.5作为系统,因为之前用apache httpd跑的,所以这里假设python、php以及mysql等等所需用到的已经没问题了。接下来,可以轻松的用yum install nginx来安装nginx,版本为0.6.39。貌似默认的yum源里面是没有nginx的,需配置EPEL,请见参考[1]。
后面要做init.d脚本,所以,安装个start-stop-daemon是必要的[2]。
wget http://developer.axis.com/download/distribution/apps-sys-utils-start-stop-daemon-IR1_9_18-2.tar.gz tar zxvf apps-sys-utils-start-stop-daemon-IR1_9_18-2.tar.gz cd apps/sys-utils/start-stop-daemon-IR1_9_18-2 gcc start-stop-daemon.c -o start-stop-daemon cp start-stop-daemon /usr/local/sbin/
为了编译,这里还需要gcc,并将编译好的可执行性文件拷贝到系统PATH目录下。
另外,因为后面Django的fastcgi需要用到flup,所以,也可以在这里把flup用yum装好。
mercurial的进程需要用到lighttpd里的spawn-fcgi,可以从lighttpd官网下载编译,如果nginx是通过EPEL安装的,那么也可以通过yum来直接安装spawn-fcgi。
静态页面篇
我个人在httpd下养成的习惯是在conf.d文件夹下面用单独的文件分别配置每个应用。所以,将这个习惯迁移到nginx之后,配置文件的清单列表如下
[lqi@longyiqi conf.d]$ ls ssl.conf v-hg-lqi.conf v-theplayer-qly.conf upstream-fair.conf virtual.conf v-wiki-lqi.conf v-archives-lqi.conf v-media-lqi.conf v-www-lqi.conf v-archives-qly.conf v-media-qly.conf v-blog-qly.conf v-rewrite-lqi.conf
作为静态页面,一部分是作为网站的媒体文件,以这个博客的媒体服务器为例,配置如下
server {
listen 80;
server_name media.qilongyi.com;
location / {
root /home/lqi/qly.com/media;
index index.html index.htm;
}
}
另一部分是作为文档索引,以主网站的archives为例,配置如下
server {
listen 80;
server_name archives.longyiqi.com;
location / {
autoindex on;
root /path/to/archives;
index index.html index.htm;
}
}
本质的区别是autoindex on。
重定向篇
因为我有longyiqi.com和qilongyi.com两个域名,前者用作个人介绍网站,后者作为分享交流网站,同时,为了美化域名和便于流向管理,我希望像longyiqi.com、qilongyi.com以及www.qilongyi.com都转到www.longyiqi.com,作为统一的网站入口。所以,下面是有关重定向的配置文件
server {
listen 80;
server_name longyiqi.com www.qilongyi.com qilongyi.com;
location / {
rewrite ^(.*)$ http://www.longyiqi.com$1 permanent;
}
}
rewrite的同时将后面的参数也一并传了过去,同时,通过permanent生成301的header,有助于SEO[3]。
动态脚本篇
为了方便维护,我将Django、Mercurial和php-cgi(用来渲染Wordpress和Mediawiki)的fastcgi进程做成init.d脚本,分别为fastcgi-dj、fastcgi-hg和fastcgi-wp,并通过chkconfig –add fastcgi-dj、chkconfig –add fastcgi-hg和chkconfig –add fastcgi-wp做成服务。同时,在nginx文件下面配置两个fastcgi_params文件,分别为fastcgi_params_dj(用于Python)和fastcgi_params_wp(用于Php),方便对基于Python和基于Php的应用分别做特殊处理,同时,在conf.d文件夹下面储存不同应用的配置文件。
我觉得这样的部署具有较高的内聚性和相对低的耦合性,提高后期维护效率和降低成本。
Python+Django篇
Django官方有一篇wiki提供了一个init.d的脚本[4],我根据个人情况作了一些修改。
#! /bin/sh
### BEGIN INIT INFO
# Provides: FastCGI servers for Django
# Required-Start: networking
# Required-Stop: networking
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: Start FastCGI servers with Django.
# Description: Django, in order to operate with FastCGI, must be started
# in a very specific way with manage.py. This must be done
# for each DJango web server that has to run.
### END INIT INFO
#
# Author: Guillermo Fernandez Castellanos
# .
#
# Version: @(#)fastcgi 0.1 11-Jan-2007 guillermo.fernandez.castellanos AT gmail.com
#
#### SERVER SPECIFIC CONFIGURATION
DJANGO_SITES="site_name"
SITES_PATH=/path/to/site
RUNFILES_PATH=/path/to/run
HOST=127.0.0.1
PORT_START=9000
RUN_AS=lqi
FCGI_METHOD=threaded
#### DO NOT CHANGE ANYTHING AFTER THIS LINE!
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="FastCGI servers for Django"
NAME=$0
SCRIPTNAME=/etc/init.d/$NAME
#
# Function that starts the daemon/service.
#
d_start()
{
# Starting all Django FastCGI processes
PORT=$PORT_START
for SITE in $DJANGO_SITES
do
echo -n ", $SITE"
if [ -f $RUNFILES_PATH/$SITE.pid ]; then
echo -n " already running"
else
start-stop-daemon --start --quiet \
--pidfile $RUNFILES_PATH/$SITE.pid \
--chuid $RUN_AS --exec /usr/bin/env -- python \
$SITES_PATH/$SITE/manage.py runfcgi \
method=$FCGI_METHOD \
host=$HOST port=$PORT pidfile=$RUNFILES_PATH/$SITE.pid
chmod 400 $RUNFILES_PATH/$SITE.pid
fi
let "PORT = $PORT + 1"
done
}
#
# Function that stops the daemon/service.
#
d_stop() {
# Killing all Django FastCGI processes running
for SITE in $DJANGO_SITES
do
echo -n ", $SITE"
start-stop-daemon --stop --quiet --pidfile $RUNFILES_PATH/$SITE.pid \
|| echo -n " not running"
if [ -f $RUNFILES_PATH/$SITE.pid ]; then
rm $RUNFILES_PATH/$SITE.pid
fi
done
}
ACTION="$1"
case "$ACTION" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
restart|force-reload)
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
echo "Usage: $NAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
exit 0
在nginx下面,需要将fastcgi_params_dj下面的
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
换成
fastcgi_param PATH_INFO $fastcgi_script_name;
最后配置nginx的虚拟主机
server {
listen 80;
server_name www.longyiqi.com;
location / {
include fastcgi_params_dj;
fastcgi_pass 127.0.01:9000;
break;
}
}
Python+Mercurial篇
因为Mercurial通过其Web Interface进行版本控制操作,这为我们的服务器端配置降低了难度,而且,上面Django中的一些配置也是可以进行复用的。
首先我们要做一个cgi脚本hgwebdir.cgi
#!/usr/bin/env python
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from flup.server.fcgi import WSGIServer
WSGIServer(hgwebdir('/path/to/hgweb.config')).run()
接下来为Mercurial的web接口进行配置,即上面的hgweb.config文件。
[web] baseurl = / allow_push = * push_ssl = false [collections] /path/to/hg = /path/to/hg
关于hgweb.config的具体配置方式可以参考Mercurial的官方手册[7]。
对Mercurial的init.d脚本,我基于参考[8]进行的修改。
#! /bin/sh
#
# fcgi-hg Startup script for the nginx HTTP Server
#
# chkconfig: - 84 15
# description: Loading php-cgi using spawn-cgi
# HTML files and CGI.
#
# Author: Ryan Norbauer
# Modified: Geoffrey Grosenbach http://topfunky.com
# Modified: David Krmpotic http://davidhq.com
# Modified: Kun Xi http://kunxi.org
DAEMON=/usr/bin/spawn-fcgi
FCGIHOST=127.0.0.1
FCGIPORT=9090
FCGIUSER=lqi
FCGIGROUP=lqi
FCGIAPP=/path/to/hgwebdir.cgi
PIDFILE=/path/to/run/hg.pid
DESC="HG in FastCGI mode"
start() {
$DAEMON -a $FCGIHOST -p $FCGIPORT -u $FCGIUSER -g $FCGIGROUP -f $FCGIAPP -P $PIDFILE 2> /dev/null || echo -en "\n already running"
}
stop() {
kill -QUIT `cat $PIDFILE` || echo -en "\n not running"
}
restart() {
kill -HUP `cat $PIDFILE` || echo -en "\n can't reload"
}
case "$1" in
start)
echo -n "Starting $DESC: "
start
;;
stop)
echo -n "Stopping $DESC: "
stop
;;
restart|reload)
echo -n "Restarting $DESC: "
stop
# One second might not be time enough for a daemon to stop,
# if this happens, d_start will fail (and dpkg will break if
# the package is being upgraded). Change the timeout if needed
# be, or change d_stop to have start-stop-daemon use --retry.
# Notice that using --retry slows down the shutdown process somewhat.
sleep 1
start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
exit 3
;;
esac
exit $?
关于nginx的配置就容易了很多,只要将对django的配置进行简单的修改即可,同时,作为我的私人版本控制,在我的配置上,增添了用户验证。
server {
listen 80;
server_name hg.longyiqi.com;
location / {
auth_basic "Private Mercurial Repositories of Longyi Qi";
auth_basic_user_file /path/to/auth;
include fastcgi_params_dj;
fastcgi_pass 127.0.01:9090;
break;
}
}
PHP+Wordpress篇
参考[6]中提供了一个php的fastcgi的init.d脚本,但是,该脚本不能做成服务,所以,基于该脚本我做了较多的修改。
#!/bin/bash
### BEGIN INIT INFO
# Provides: FastCGI servers for WordPress
# Required-Start: networking
# Required-Stop: networking
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: Start FastCGI servers with WordPress.
# Description: Start FastCGI servers with WordPress.
### END INIT INFO
BIND=127.0.0.1:8000
USER=lqi
PHP_FCGI_CHILDREN=6
PHP_FCGI_MAX_REQUESTS=1000
PHP_CGI=/usr/bin/php-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
RETVAL=0
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="FastCGI servers for WordPress"
NAME=$0
SCRIPTNAME=/etc/init.d/$NAME
start() {
echo -n "Starting PHP FastCGI: "
start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
RETVAL=$?
echo "$PHP_CGI_NAME."
}
stop() {
echo -n "Stopping PHP FastCGI: "
killall -q -w -u $USER $PHP_CGI
RETVAL=$?
echo "$PHP_CGI_NAME."
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: php-fastcgi {start|stop|restart}"
exit 1
;;
esac
exit $RETVAL
nginx配置目录下的fastcgi_params_wp保持和fastcgi_params.default一样就可以。
关于nginx虚拟主机的配置如下
server {
listen 80;
server_name blog.qilongyi.com;
root /path/to/blog;
index index.php index.html;
fastcgi_index index.php;
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?q=$1 last;
}
}
location ~ \.php$ {
include fastcgi_params_wp;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:8000;
}
}
里面为了美化url而做了重定向。
PHP+MediaWiki篇
对MediaWiki本身的配置请参考[9]。
而由于在前面在配置Wordpress的时候已经配置好了php-cgi,所以现在只需要配置nginx,让其对MediaWiki进行支持即可。
server {
listen 80;
server_name wiki.longyiqi.com;
root /path/to/mediawiki;
index index.php index.html;
fastcgi_index index.php;
location / {
error_page 404 = @mediawiki;
}
location @mediawiki {
rewrite ^/([^?]*)(?:\?(.*))? /index.php?title=$1&$2 last;
}
location ~ \.php$ {
include fastcgi_params_wp;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:8000;
}
}
里面的rewrite来自参考[10]。
希望我的这一系列的配置文件笔记可以减少你奔波于Google搜索出来的各个页面之间,祝好运。
参考文献:
- https://fedoraproject.org/wiki/EPEL
- http://blog.timc3.com/2010/03/26/django-on-redhat-or-centos/
- http://wiki.nginx.org/NginxHttpRewriteModule
- http://code.djangoproject.com/wiki/InitdScriptForLinux
- http://djangoadvent.com/1.2/deploying-django-site-using-fastcgi/
- http://tomasz.sterna.tv/2009/04/php-fastcgi-with-nginx-on-ubuntu/
- http://mercurial.selenic.com/wiki/PublishingRepositories
- http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/
- http://www.mediawiki.org/wiki/MediaWiki
- http://wiki.nginx.org/NginxMediaWiki
黑白dè独舞
你贴代码的样式很漂亮啊
谢谢,用的是syntexhighligher这个插件。不过,存在的问题是这个插件对不同语言的javascript不是动态加载的。