几个 Nginx 子目录 rewrite 的例子

我们已经有很多客户在 VPS 上使用 Nginx,对于刚从 Apache 转过来的客户最常遇到的一个问题就是怎么弄 Nginx 下的 rewrite 以及怎么把 Apache 里的 .htaccess 转化成 Nginx,网上关于这方面的资料一大堆,关于 wordpress, discuz, phpcms, ecshop, shopex 等的 rewrite 应有尽有,直接 copy 就可以。还有一个 Nginx 新手常见的问题是拿到这些 rewrite 规则后不知道怎么改,比如 Nginx 下子目录的 rewrite 应该改成什么样子?/ 下是 wordpress,/bbs 下装个 discuz,/ 是 discuz,/blog 下装个 wordpress 或者 / 下是 wordpress,/blog 下再装个 wordpress 等,这样的 rewrite 怎么改呢?弄几个例子放到我们的 FAQ 里供参考:

WordPress 安装在子目录 /blog 下:

location /blog/ {
    root   /home/www/vpsee.com;
    index  index.php index.html index.htm;
    if (!-e $request_filename) {
       rewrite ^.+/?(/blog/wp-.*) $1 last;
       rewrite ^.+/?(/blog/.*\.php)$ $1 last;
       rewrite ^(.+)$ /blog/index.php?q=$1 last;
    }
}

Discuz! 7.2 安装在子目录 /bbs 下:

location /bbs/ {
    root   /home/www/vpsee.com;
    index  index.php index.html index.htm;
    rewrite ^/bbs/archiver/((fid|tid)-[\w\-]+\.html)$ /bbs/archiver/index.php?$1 last;
    rewrite ^/bbs/forum-([0-9]+)-([0-9]+)\.html$ /bbs/forumdisplay.php?fid=$1&page=$2 last;
    rewrite ^/bbs/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /bbs/viewthread.php?tid=$1&extra=page%3D$3&page=$2 last;
    rewrite ^/bbs/space-(username|uid)-(.+)\.html$ /bbs/space.php?$1=$2 last;
    rewrite ^/bbs/tag-(.+)\.html$ /bbs/tag.php?name=$1 last;
}

Discuz! X1.5 安装在子目录 /bbs 下:

location /bbs/ {
    root   /home/www/vpsee.com;
    index  index.php index.html index.htm;
    rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last;
    rewrite ^([^\.]*)/article-([0-9]+)-([0-9]+)\.html$ $1/portal.php?mod=view&aid=$2&page=$3 last;
    rewrite ^([^\.]*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last;
    rewrite ^([^\.]*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last;
    rewrite ^([^\.]*)/group-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last;
    rewrite ^([^\.]*)/space-(username|uid)-(.+)\.html$ $1/home.php?mod=space&$2=$3 last;
    rewrite ^([^\.]*)/([a-z]+)-(.+)\.html$ $1/$2.php?rewrite=$3 last;
    if (!-e $request_filename) {
        return 404;
    }
}

如果对理解 ^([^\.]*)/([a-z]+)-(.+)\.html$ 这样的正则表达式有困难并对这方面有兴趣的话可以看看一些书,最好的一本应该是 O’Reilly 出的 Mastering Regular Expressions(也有中文版:《精通正则表达式》)。

使用 Nginx 和 GeoIP 模块来处理不同国家的访问

如果想屏蔽某个地区的 IP 访问的话,用 iptables 把来自某个国家的 IP 重定向到预定页面不是特别灵活的办法,如果只有一个 IP 可用而有多个网站在同一 VPS 上怎么办?用 iptable 屏蔽某个网站的话也会屏蔽同一 VPS 上的其他网站的访问。所以正统的办法还是用 GeoIP 配合对应的 web 服务器模块,比如:apache + mod_geoip 或者 nginx + http_geoip_module 等。

安装 Nginx

因为要用到 http_geoip_module 模块,系统自带的 nginx 一般不带这个模块,所以要下载 nginx 源代码后自行编译:

# wget http://nginx.org/download/nginx-0.9.6.tar.gz
# tar zxvf nginx-0.9.6.tar.gz
# cd nginx-0.9.6
# ./configure --without-http_empty_gif_module --with-poll_module \
--with-http_stub_status_module --with-http_ssl_module \
--with-http_geoip_module
# make; make install

安装 MaxMind 的 GeoIP 库

MaxMind 提供了免费的 IP 地域数据库(GeoIP.dat),不过这个数据库文件是二进制的,需要用 GeoIP 库来读取,所以除了要下载 GeoIP.dat 文件外(见下一步),还需要安装能读取这个文件的库。

# wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
# tar -zxvf GeoIP.tar.gz
# cd GeoIP-1.4.6
# ./configure
# make; make install

刚才安装的库自动安装到 /usr/local/lib 下,所以这个目录需要加到动态链接配置里面以便运行相关程序的时候能自动绑定到这个 GeoIP 库:

# echo '/usr/local/lib' > /etc/ld.so.conf.d/geoip.conf
# ldconfig

下载 IP 数据库

MaxMind 提供了免费的 IP 地域数据库,这个数据库是二进制的,不能用文本编辑器打开,需要上面的 GeoIP 库来读取:

# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
# gunzip GeoIP.dat.gz

配置 Nginx

最后是配置 nginx,在相关地方加上如下的配置就可以了:

# vi /etc/nginx/nginx.conf

http {
...
geoip_country /home/vpsee/GeoIP.dat;
fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
fastcgi_param GEOIP_COUNTRY_CODE3 $geoip_country_code3;
fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;
...
}

server {
...
        location / {
            root   /home/vpsee/www;
            if ($geoip_country_code = CN) {
                root /home/vpsee/cn;
            }
            ...
        }
...
}

这样,当来自中国的 IP 访问网站后就自动访问到预定的 /home/vpsee/cn 页面。关于 Nginx + GeoIP 还有很多有用的用法,比如做个简单的 CDN,来自中国的访问自动解析到国内服务器、来自美国的访问自动转向到美国服务器等。MaxMind 还提供了全球各个城市的 IP 信息,还可以下载城市 IP 数据库来针对不同城市做处理。

Nginx 使用 Linux-native aio 需要 Linux 内核支持

Nginx 性能优异在于善于利用操作系统内核的各种特性,比如 aio/epoll/sendfile (Linux), kqueue (FreeBSD) 等。对于使用 VPS 做图片站的站长来说,使用 nginx 的 aio 特性会大大提高性能,图片站的特点是大量的读 io 操作,nginx aio 不用等待每次 io 的结果有助于并发处理大量 io 和提高 nginx 处理效率。

前段时间有位客户要用 nginx aio,他用 rpm 升级安装 nginx 到 0.8.5 版本时候发现 rpm 包里的 nginx 没有包含 Linux-native aio (asynchronous I/O) 的支持,所以需要下载 nginx 源代码并带上参数 –with-file-aio 编译。除了要带参数外,Linux 内核还必须有支持这一特性的 api,eventfd(),否则在 nginx 错误日志(/var/log/nginx/error.log)里会看到类似的报错:

eventfd() failed (38: Function not implemented)
worker process 1858 exited with fatal code 2 and can not be respawn

要让 nginx 使用 aio 特性还需要修改 nginx 配置文件:

# vi /etc/nginx/nginx.conf
...
location / {
aio on;
directio 1;
output_buffers 1 128k;
}
...

昨天另一客户遇到 nginx 启动配置都正确却无法看到网页的情况,VPSee 刚开始怀疑是他自己的 nginx 配置有误或者防火墙屏蔽了80端口,后来登录到他的 VPS 上发现 nginx 配置的确没问题,能正常启动,可以 telnet 80 端口,但是不能 get 到网页。打开 nginx 日志也发现 eventfd() failed 的错误提示。后来检查他的 Linux VPS 内核版本是 2.6.18,查了一下 man 帮助发现只有 2.6.22 以后版本才支持 eventfd,解决方法很简单,升级内核就可以了。

Linux-native aio 比传统的 POSIX aio 功能更丰富一些,重要的一点是能通过内核加速提供高性能。直接用 Linux-native aio API 比较晦涩,为了方便使用和开发 Linux-native aio 应用程序我们可以用 libaio/libaio-devel 库。不过 nginx 的作者没有用这些库,因为 nginx 需要 eventfd(),而 libaio 库里只有 0.3.107 版本起才支持 eventfd;nginx 也没有用 glibc,因为 glibc 要到 2.8 版本才支持 eventfd(),为了减少对库的依赖性,nginx 干脆直接用 Linux-native aio API (system calls).

$ vi nginx-0.9.1/src/event/modules/ngx_epoll_module.c
...
#if (NGX_HAVE_FILE_AIO)

/*
 * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
 * as syscalls instead of libaio usage, because the library header file
 * supports eventfd() since 0.3.107 version only.
 *
 * Also we do not use eventfd() in glibc, because glibc supports it
 * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
 * into single eventfd() function with different number of parameters.
 */
...

这里说到了 eventfd(),eventfd 是 Linux-native aio 其中的一个 API,用来生成 file descriptors,这些 file descriptors 可为应用程序提供更高效 “等待/通知” 的事件机制。和 pipe 作用相似,但比 pipe 更好,一方面它只用到一个 file descriptor(pipe 要用两个),节省了内核资源;另一方面,eventfd 的缓冲区管理要简单得多,pipe 需要不定长的缓冲区,而 eventfd 全部缓冲只有定长 8 bytes.

在 Debian 上源码编译和安装 Nginx+PHP+FastCGI+MySQL

前天有一位新客户购买我们的 VPS 后多次在上面源码编译和安装 Nginx+PHP+FastCGI+MySQL 不成功,遇到一些问题,总的来说分为两类,一个是包依赖问题,一个是 MySQL 目录的权限设置问题。昨天这位客户给我们发来一个论坛链接很细致的描述了他的安装过程和遇到的问题,可惜后面回帖的人都没说到重点,还有一位回帖人居然是我们的客户,呵呵,世界好小。VPSee 决定花点时间写个教程,可能对其他的 Linux/VPS 用户也有帮助。我们的 VPS 和那些使用 SolusVM 控制面板和模版的 VPS 服务商不同,我们自己制作 VPS 模版,采用最小化安装,不添加任何乱七八糟的东西,保持最简和干净,所以 VPS 上只装有必备的软件包和库,在编译 Nginx+PHP+FastCGI+MySQL 之前必须先安装一些编译时需要的软件包和库。

记得以前有位客户问过为什么我们的 VPS 上连基本的 gcc 工具都没有?为什么我们采用最小化安装?为什么我们没有提供那些都安装好的模版?有3个原因,1、不需要 gcc Linux 也可以运行,所以 gcc 不是必须的,这满足我们最小化的要求;2、安全,如果有人得到 Linux 普通用户帐号可以下载、通过 gcc 编译和运行一些后门代码以得到 root 权限或者干坏事,所以不是必要的话不推荐安装 gcc 等编译工具,同样的道理也适用我们对其他工具的要求;3、定制,每个人的要求是不同的,有的人喜欢 nginx,有的人喜欢 apache,所以我们采用最小化安装,把选择留给客户。我们认为最小化可以带来简单、安全和灵活。

下面的操作步骤在我们的 256MB Debian 5.0 VPS 上测试通过,Nginx/PHP/MySQL 都采用当前最新稳定源代码版本。

安装必备软件包

# aptitude install libtidy-dev curl libcurl4-openssl-dev libcurl3 \
libcurl3-gnutls zlib1g zlib1g-dev libxslt1-dev libzip-dev libzip1 \
libxml2 libsnmp-base libsnmp15 libxml2-dev libsnmp-dev libjpeg62 \
libjpeg62-dev libpng12-0 libpng12-dev zlib1g zlib1g-dev libfreetype6 \
libfreetype6-dev libbz2-dev libxpm-dev libmcrypt-dev libmcrypt4 \
sqlite3 bzip2 build-essential libreadline5-dev libedit-dev autoconf

编译和安装 MySQL

下载和编译 MySQL,但是先不要安装:

# wget http://mysql.mirror.rafal.ca/Downloads/MySQL-5.1/mysql-5.1.50.tar.gz
# tar zxvf mysql-5.1.50.tar.gz
# cd mysql-5.1.50

# ./configure \
 --prefix="/usr/local/mysql-5.1.50" \
 --enable-thread-safe-client \
 --with-extra-charsets=all
# make

需要改几个权限问题才能安装 MySQL,否则会出现 Access denied for user ‘root’@'localhost’ (using password: NO) 经典问题:

# groupadd mysql
# useradd -g mysql mysql

# cp support-files/my-small.cnf /etc/my.cnf
# vi /etc/my.conf
...
[mysqld]
user = mysql
...

# chown -R mysql:mysql /usr/local/mysql-5.1.50/
# chmod 777 /tmp

安装和启动 MySQl,修改 root 密码,登录 MySQL:

# cd mysql-5.1.50
# make install

# /usr/local/mysql-5.1.50/bin/mysql_install_db --user=mysql
# /usr/local/mysql-5.1.50/bin/mysqld_safe &
# /usr/local/mysql-5.1.50/bin/mysqladmin -u root password 'new-password'
# /usr/local/mysql-5.1.50/bin/mysql -u root -p

编译和安装 PHP

先下载 PHP 软件包,然后配置、编译,这里采用 php 5.2 分支的最新稳定代码:

# wget http://www.php.net/get/php-5.2.13.tar.bz2/from/us.php.net/mirror
# tar jxvf php-5.2.13.tar.bz2
# cd php-5.2.13

# ./configure \
 --prefix="/usr/local/php-5.2.13" \
 --with-mysql="/usr/local/mysql-5.1.50" \
 --with-gd \
 --with-ttf \
 --with-openssl \
 --enable-mbstring \
 --enable-fastcgi
# make && make install

编译和安装 Nginx

下载、配置和编译安装 nginx,注意编译 nginx 需要额外安装几个软件包:

# wget http://nginx.org/download/nginx-0.7.67.tar.gz
# tar zxvf nginx-0.7.67.tar.gz

# aptitude install libgcrypt11-dev libpcre3 libpcre3-dev libssl-dev

# cd nginx-0.7.67
# ./configure  --prefix="/usr/local/nginx-0.7.67"  --with-http_ssl_module
# make && make install

编译和安装 FastCGI

Nginx 需要 FastCGI 的支持才能运行 PHP 脚本,从 lighttpd 下载、编译和安装 spawn-fcgi:

# wget http://www.lighttpd.net/download/spawn-fcgi-1.6.2.tar.bz2
# tar jxvf spawn-fcgi-1.6.2.tar.bz2

# cd spawn-fcgi-1.6.2
# ./configure --prefix="/usr/local/php-5.2.13"
# make && make install

启动 FastCGI:

# /usr/local/php-5.2.13/bin/spawn-fcgi -a 127.0.0.1 -p 9000 \
-u www-data -g www-data -f /usr/local/php-5.2.13/bin/php-cgi \
-P /var/run/fastcgi-php.pid

编辑 Nginx 的配置文件,让 php 脚本被发送到 FastCGI 服务器由 FastCGI 处理,然后启动 nginx:

# vi /usr/local/nginx-0.7.67/conf/nginx.conf
...
        # fix nginx/php/fastcgi important security issue
        # http://cnedelcu.blogspot.com/2010/05/nginx-php-via-fastcgi-important.html
        location ~ \..*/.*\.php$ {
            return 403;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
            #root           html;
            root           /usr/local/nginx-0.7.67/html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/local/nginx-0.7.67/html$fastcgi_script_name;
            include        fastcgi_params;
        }
...

# /usr/local/nginx-0.7.67/sbin/nginx -c /usr/local/nginx-0.7.67/conf/nginx.conf

安装 Nginx+FastCGI+PHP 完后测试一下是否 PHP 页面能否被正确解析,在 html 下创建一个含有 phpinfo(); 函数的文件,最后打开浏览器检查下面的 index.php 能否被正确执行。:

# vi /usr/local/nginx-0.7.67/html/index.php
phpinfo();

编译源代码需要消耗大量内存,我们只建议 256MB 或以上 VPS 用户使用源码方式安装。

NetBSD 上安装和配置 Nginx+PHP+FastCGI+MySQL

NetBSD 支持 n 种硬件架构,是地球上支持最多体系的系统;OpenBSD 来自 NetBSD,自称是地球上最安全的系统;FreeBSD 和 NetBSD 一样来自原始的 4.4 BSD-lite,但是 FreeBSD 现在主要支持 i386,在 PC 体系上 FreeBSD 比 NetBSD/OpenBSD 好很多,性能也最好。这三种 BSD 各有特点,和不同的 Linux 发行版一样每个系统都有很多粉丝,当然使用 FreeBSD 的人最多。VPSee 的一台老掉牙的 IBM ThinkPad 就在跑 FreeBSD,嗯,现在这台机器还在工作呢。虽然 NetBSD 的性能在 i386 上没有 FreeBSD 那么好,但是它的稳定性是非常的赞,Benchmarking BSD and Linux 这篇测试的作者说:

Please note that NetBSD was the only BSD that never crashed or panicked on me, so it gets favourable treatment for that.

我们上周五发布了 NetBSD VPS,我们鼓励用户自己动手安装 Nginx+PHP+FastCGI+MySQL 和熟悉 NetBSD 环境,这篇文章在我们的 NetBSD VPS 上搭建:

下载 pkgsrc

The NetBSD Packages Collection (pkgsrc) 是 NetBSD 下的基于源码的软件包管理系统,不同于 Debian/Ubuntu 上的 apt-get,pkgsrc 是基于源代码的方式管理软件包的,有点像 Gentoo 里面的 emerge 系统。pkgsrc 有三个分支,HEAD、pkgsrc-yyyyQqq 和 pkgsrc-wip,前两个是 pkgsrc 项目组的正式分支。我们在这里使用 pkgsrc-yyyyQqq(季度分支),下载和解压 pkgsrc 并放到合适的目录:

# ftp ftp://ftp.NetBSD.org/pub/pkgsrc/pkgsrc-2010Q2/pkgsrc-2010Q2.tar.bz2
# tar jxvf pkgsrc-2010Q2.tar.bz2
# mv pkgsrc /usr/

安装 Nginx+PHP+FastCGI+MySQL

编译和安装 PHP,注意编译 PHP 的时候需要加上 fastcgi 说明,这样 PHP 编译才会把 FastCGI 部分编译进去:

# vi /etc/mk.conf
PKG_OPTIONS.php = fastcgi

# cd /usr/pkgsrc/lang/php5
# make install clean clean-depends

配置 PHP:

# /usr/pkg/etc/php.ini
cgi.fix_pathinfo=1

编译和安装 FastCGI:

# cd /usr/pkgsrc/www/spawn-fcgi/
# make install clean clean-depends

编译和安装 Nginx:

# cd /usr/pkgsrc/www/nginx
# make install clean clean-depends

配置 Nginx:

# cp /usr/pkg/share/examples/rc.d/nginx /etc/rc.d/
# vi /usr/pkg/etc/nginx/nginx.conf
location / {
            root   share/examples/nginx/html;
            index  index.html index.htm index.php;
        }

...

location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/pkg/share/examples/nginx/html$f
astcgi_script_name;
            include        /usr/pkg/etc/nginx/fastcgi_params;
        }

把 Nginx 加到启动文件以便启动系统时自动启动:

# vi /etc/rc.conf
nginx=YES

编译和安装 MySQL:

# cd /usr/pkgsrc/databases/php-mysql
# make install clean clean-depends

# cd /usr/pkgsrc/databases/mysql5-server
# make install clean clean-depends

配置 PHP 以便加载 MySQL 动态连接库:

# vi /usr/pkg/etc/php.ini
extension=mysql.so

把 MySQL 加到启动文件以便启动系统时自动启动:

# cp /usr/pkg/share/examples/rc.d/mysqld /etc/rc.d/

# vi /etc/rc.conf
mysqld=YES

启动 FastCGI:

# /usr/pkg/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/pkg/libexec/cgi-bin/php
spawn-fcgi: child spawned successfully: PID: 18554

启动 Nginx:

# /etc/rc.d/nginx start
Starting nginx.

启动 MySQL 和设置 root 密码:

# /etc/rc.d/mysqld start

# /usr/pkg/bin/mysqladmin -u root -p password 'new-password'

测试

写一个 phpinfo() 文件放在 nginx 目录下,然后打开浏览器测试是否能正确访问 php 文件:

# vi /usr/pkg/share/examples/nginx/html/index.php


http://www.vpsee.com/index.php

CentOS 5 上部署 Nginx、Mongrel 和 Rails

接着昨天的来,昨天 VPSee 简单的安装和试用了一下 Redmine,发现 Redmine 的界面很简单清新、使用也很方便,需要的功能都有。今天打算部署到稍微专业一点的环境,Ruby on Rails 的部署方案主要有以下几种:

  • Lighttpd + FastCGI
  • Nginx + Mongrel
  • Nginx + Thin
  • Nginx + Phusion Passenger
  • Apache2 + Thin
  • Apache2 + Phusion Passenger (Mod_Rails)

目前用的比较多、比较成熟的要算 Nginx + Mongrel 和 Apache2 + Passenger 了,Apache2 + Passenger 配置很简单,非常适合多 ruby app 的部署。考虑到成熟、稳定、而且 VPSee 对 Nginx 比较熟悉,所以选定 Nginx + Mongrel 组合作为 Redmine 环境的部署方案。以下的内容虽然以 Redmine 为例来描述如何部署 Nginx + Mongrel,其配置方法也适用与一般 Rails 程序部署的情况。

安装和配置 Ruby on Rails

详细参考 “CentOS 5 上配置 Redmine 和 Git” 中的 “安装必要的软件包” 和 “安装和配置 Ruby on Rails”.

安装和配置 Mongrel

拷贝 mongrel_cluster 启动文件到 /etc/init.d/,在 /etc 下创建一个目录 mongrel_cluster 用来存放 mongrel 程序的配置文件,配置文件必须以 yml 扩展名结尾,不能是 yaml,最后修改 yml 配置文件,注意 user/group 要和前面一文的对上,否则 mongrel_cluster 启动不了:

# gem install mongrel
# gem install mongrel_cluster

# cp /usr/local/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources \
/mongrel_cluster /etc/init.d/
# chmod +x /etc/init.d/mongrel_cluster
# /sbin/chkconfig --level 345 mongrel_cluster on

# mkdir /etc/mongrel_cluster
cp /usr/local/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources/defaults.yaml /etc/mongrel_cluster/redmine.yml

# vi /etc/mongrel_cluster/redmine.yml
---
cwd: /home/redmine/
port: "9000"
environment: production
address: 127.0.0.1
pid_file: log/mongrel.pid
servers: 4
group: redmine
user: redmine

启动 mongrel:

# /etc/init.d/mongrel_cluster start

安装配置 Nginx

安装完 nginx 后需要修改配置文件,nginx 支持模块化配置,为了更清晰最好把全局配置文件和 virtal host 配置文件分开,先是修改 nginx 的全局配置文件:

# yum install nginx

# vi /etc/nginx/nginx.conf
user              nginx;
worker_processes  1;
error_log         /var/log/nginx/error.log;
pid               /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/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;
    tcp_nopush      on;
    tcp_nodelay     off;
    keepalive_timeout  65;

    gzip  on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types text/plain text/html text/css application/x-javascript
text/xml application/xml application/xml+rss text/javascript;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/vhosts/*;
}

接着在 /etc/nginx/ 下面创建一个文件夹 vhosts 用来存放多个 virtual host 局部配置文件:

# mkdir /etc/nginx/vhosts
# vi /etc/nginx/vhosts/vpsee.com.conf

upstream mongrel_server {
        server 127.0.0.1:9000;
        server 127.0.0.1:9001;
        server 127.0.0.1:9002;
        server 127.0.0.1:9003;
}

server {
        listen  80;
        server_name  vpsee.com www.vpsee.com;

        client_max_body_size 10M;
        root   /home/redmine;

        access_log  /var/www/access_vpsee.com.log  main;

        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect false;
            proxy_max_temp_file_size 0;

            if (-f $request_filename) {
                break;
            }
            if (-f $request_filename/index.html) {
                rewrite (.*) $1/index.html break;
            }
            if (-f $request_filename.html) {
                rewrite (.*) $1.html break;
            }
            if (!-f $request_filename) {
                proxy_pass http://mongrel_server;
                break;
            }
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
}

启动 nginx:

# /etc/init.d/nginx start

打开浏览器应该就可以访问了。

Linux kernel 的 sendfile 是如何提高性能的

现在流行的 web 服务器里面都提供 sendfile 选项用来提高服务器性能,那到底 sendfile 是什么,怎么影响性能的呢?sendfile 实际上是 Linux 2.0+ 以后的推出的一个系统调用,web 服务器可以通过调整自身的配置来决定是否利用 sendfile 这个系统调用。先来看一下不用 sendfile 的传统网络传输过程:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

硬盘 >> kernel buffer >> user buffer >> kernel socket buffer >> 协议栈

一般来说一个网络应用是通过读硬盘数据,然后写数据到 socket 来完成网络传输的。上面2行用代码解释了这一点,不过上面2行简单的代码掩盖了底层的很多操作。来看看底层是怎么执行上面2行代码的:

1、系统调用 read() 产生一个上下文切换:从 user mode 切换到 kernel mode,然后 DMA 执行拷贝,把文件数据从硬盘读到一个 kernel buffer 里。
2、数据从 kernel buffer 拷贝到 user buffer,然后系统调用 read() 返回,这时又产生一个上下文切换:从kernel mode 切换到 user mode。
3、系统调用 write() 产生一个上下文切换:从 user mode 切换到 kernel mode,然后把步骤2读到 user buffer 的数据拷贝到 kernel buffer(数据第2次拷贝到 kernel buffer),不过这次是个不同的 kernel buffer,这个 buffer 和 socket 相关联。
4、系统调用 write() 返回,产生一个上下文切换:从 kernel mode 切换到 user mode(第4次切换了),然后 DMA 从 kernel buffer 拷贝数据到协议栈(第4次拷贝了)。

上面4个步骤有4次上下文切换,有4次拷贝,我们发现如果能减少切换次数和拷贝次数将会有效提升性能。在kernel 2.0+ 版本中,系统调用 sendfile() 就是用来简化上面步骤提升性能的。sendfile() 不但能减少切换次数而且还能减少拷贝次数。

再来看一下用 sendfile() 来进行网络传输的过程:

继续阅读 »

Nginx 上配置 WordPress Mu 的重写规则

wordpressmu

WordPress Mu 可以看作是一款多用户版的 WordPress,可以方便架设自己的 BSP,像 blogbus.com,yo2.cn 做的那样。 后台和 WP 差不多,多了一个 Site Admin 用来管理整个 blog, 其他部分和独立的 WP 大同小异。最方便的是 WPMU 和 WP 的部分插件和主题可以通用,基于 WP 丰富的主题和插件,可以很好的应用到 WPMU 上。这样,节约了重新定制主题和寻找插件的时间和资源。

首先需要安装和配置好 Nginx+PHP5+Mysql+FastCGI,然后从官方网站下载 WPMU,安装完毕后打开 nginx.conf,配置 Nginx 以支持 WordPress MU 的 rewrite rules。注意:需要把下面的 vpsee.com 和路径换成你自己的域名和路径;如果不用 WP SuperCache 插件可以把相关部分注释掉。

继续阅读 »

FreeBSD 上安装配置 Nginx+PHP+FastCGI+Mysql

freebsd

在 VPS 里很少看见 FreeBSD 的踪影,主要原因是因为两大开源虚拟系统 Xen 和 OpenVZ 对 FreeBSD 都不是那么友好:(,OpenVZ 不能支持非 Linux 内核的操作系统,Xen 对 FreeBSD 的支持不太好(也可以说FreeBSD 对 Xen 的支持不好)。最近 VPSee 从 Advantagecom 订了一个 256MB 的 Xen VPS,想在上面试试 FreeBSD 先,Advantagecom 不提供换操作系统的面板,每次都要提交 ticket 换系统好麻烦,而且一个月只能换一次系统。VPSee 打算先用一个月的 FreeBSD,然后再换成 Linux。就目前 VPS 的状况来说,VPSee.com 还是推荐使用 Linux,对于 VDS 或者自己的服务器来说,Linux 和 FreeBSD 都是很棒的操作系统。

安装所需软件

FreeBSD上 有2种安装软件的方法:一种是二进制安装;另一种是源代码安装(Ports collection)。

二进制安装所需软件:

# /usr/sbin/pkg_add -r -v mysql51-server
# /usr/sbin/pkg_add -r -v nginx
# /usr/sbin/pkg_add -r -v php5
# /usr/sbin/pkg_add -r -v php5-mysql
# /usr/sbin/pkg_add -r -v lighttpd


继续阅读 »

64MB VPS 上优化 Nginx

nginx

Nginx 小巧,高效,稳定等优点非常适合配置不高,内存小的 VPS。这里的优化策略不是让nginx每秒能处理更多的请求,那是一个繁忙网站要做的。记住,这是一个只有 64MB 的 VPS,对于架设一个访问量不大的网站/博客来说,尽可能减少 Nginx 的内存占用率是最重要的,用尽量小的 Nginx 占用内存去满足不大的访问量。

优化 nginx.conf

Nginx 运行的进程数,一般设置成和 CPU 的核数相同。

worker_processes  1;

使用 epoll,Linux 内核2.6版本以上支持 epoll(eventport支持 Soaris,kqueue 支持 BSD系列),worker_connections 每个 Nginx 进程所允许的最大的连接数,max_clients = worker_processes * worker_connections。

 events {
    use epoll;
    worker_connections  128;
 }

设置连接的超时时间。

keepalive_timeout  5;


继续阅读 »