nginx+django+wordpress+mediawiki+mercurial配置笔记

昨天终于按捺不住,把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搜索出来的各个页面之间,祝好运。

参考文献:

  1. https://fedoraproject.org/wiki/EPEL
  2. http://blog.timc3.com/2010/03/26/django-on-redhat-or-centos/
  3. http://wiki.nginx.org/NginxHttpRewriteModule
  4. http://code.djangoproject.com/wiki/InitdScriptForLinux
  5. http://djangoadvent.com/1.2/deploying-django-site-using-fastcgi/
  6. http://tomasz.sterna.tv/2009/04/php-fastcgi-with-nginx-on-ubuntu/
  7. http://mercurial.selenic.com/wiki/PublishingRepositories
  8. http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/
  9. http://www.mediawiki.org/wiki/MediaWiki
  10. http://wiki.nginx.org/NginxMediaWiki
This entry was posted in 有点儿专业 and tagged , , , , , . Bookmark the permalink.

2 Responses to nginx+django+wordpress+mediawiki+mercurial配置笔记

  1. 你贴代码的样式很漂亮啊

    • 谢谢,用的是syntexhighligher这个插件。不过,存在的问题是这个插件对不同语言的javascript不是动态加载的。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>