在 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

自动监测和重启 FastCGI 服务

昨天有个服务器出了点小问题,PHP FastCGI 进程无缘无故就死在那里了,造成 Nginx 不能和 FastCGI 通信,不能解析 PHP 页面,只能看到 Nginx 的 默认 HTML 页面。登录到服务器检查日志也没有找到原因,重启 FastCGI 后恢复正常。服务器上装了 monit,如果服务关闭的话会自动重启,但是这里 FastCGI 服务并没有关闭,只不过由于某种原因不能和 Nginx 通信,所以 monit 误认为 FastCGI 运行正常没有执行重启 FastCGI 的命令。

今天写了一个 Python 脚本用来后台监测 nginx 的日志,如果在日志里发现 111: Connection refused 或者 104: Connection reset by peer 等错误就 kill 掉所有 php-cgi 进程后重启服务。程序有几个地方需要说明:

1、如果不先 kill 直接运行 /etc/init.d/php-cgi restart 重启服务有时候不管用,因为这时候 php-cgi 只是驻留在内存里的死进程而而已不能执行任何命令,所以需要 kill 全部 php-cgi 进程后再启动;
2、读 nginx 的 log 文件的时候要小心,log 文件通常很大,如果用 python 的普通读文件函数会把整个文件读出来后再处理,速度很慢,也会占用大量内存,所以最好用 tail 截取文件,我们只需要分析最后部分(也是最近)的记录即可;
3、程序通过 /var/run/php_cgi.pid 来判断 PHP FastCGI 是否正在运行,通过 /var/log/nginx/error.log 来判断 Nginx/FastCGI 是否工作正常,每600秒检查一次,如果工作不正常 sleep 2秒后重启 php-cgi;
4、本程序可扩展到重启其他服务,比如通过 /var/run/lighttpd.pid 来判断 lighttpd 是否需要重启;
5、程序中 daemonize 函数来自 Python Cookbook(O’Reilly ) 一书。

程序使用

拷贝下面代码做一定修改以后保存为 checkphpcgi,增加文件可执行权限后用 root 运行程序:

# chmod +x checkphpcgi

# ./checkphpcgi
usage: ./checkphpcgi start|stop|restart

# ./checkphpcgi start

如果想要停止程序:

继续阅读 »