Nginx 虚拟主机 配置 支持独立urlwrite 文件, php-fpm独立用户和php....

Nginx 虚拟主机 环境配置。

最近租了台服务器,准备做一些网站。纠结apache/nginx很久,最后选定了Nginx+php-fpm。

因为可能会有几个站,为了安全,我希望每个站点直接都能尽量独立,避免互相影响。

主要实现功能:

  • -能够相对快捷的添加虚拟主机。
  • -每个虚拟主机直接相对独立,避免一个网站有漏洞,全服务器手影响
  • -能够方便的配置urlrewrite,还是需要reload或restart ( 谁让nginx 不支持像 .htaccess 这样吗方便的东西呢?)
  • -每个虚拟主机能独立配置php.ini


上面是废话,下面就是大概实现方法。

一、主要环境


CentOS 5.7, Nginx 1.06 PHP 5.2.17(php-fpm)
安装过程省略,我基本都是编译安装在 /usr/local/ 下面。

二、Web目录结构&权限


/home/$USER$/            用户
|-- $DOMAIN$            域名
    |-- logs
    |   |-- access.log        访问日志
    |   `-- .nginx        用户Nginx,可以定义urlrewrite 即使不需要也要创建,空内容,因为 nginx 配置文件中要include~。
    `-- wwwroot            用户存放web文件
         `-- index.html

权限:

Home目录下的全部目录(除了用户后来创建的)都是711, 用户组和其他用户都只能进入目录,不能查看目录有什么文件。

home下的所有文件文件(除了用户后来创建的)都是644,目录所有者能读写,用户组内的和其他用户只能读。

将 umask 都设置成 0022,这样的话用户创建的目录就是 755,能访问,能读取(显示目录下的文件)。创建的文件则是644,所有者能读写,用户组的和其他用户只能读取。


三、基本实现


1.在/(也可以是其他)目录下创建vhost目录。
2.在 /vhost 目录下创建logs目录用于记录日志(php-fpm)。
3.在 /vhost 目录下对应每个虚拟主机的用户创建一个用户目录。
4.在用户目录内创建该用户的虚拟主机的目录,目录名称为主域名(比如:qq.com)。
5.再在域名目录下创建 nginx.conf 和 php-fpm.conf 。nginx.conf 会被 主的nginx.conf 包含,里面指定了web目录等配置。php-fpm.conf 是php-fpm启动时读取的配置文件,指定了执行php的用户和组,socket端口等配置。
6.在 /vhost 目录下创建 chHosts.sh,该文件用户遍历/vhost目录下存在那些虚拟主机,记录下来,写入到 /vhost/hosts 文件,以便使用。 hosts 内容大概如下:

user1/qq.com
user2/yahoo.com
user3/google.com
user3/yahoo.com

7.在 /vhost 目录下创建 php-fpm 文件,该文件用于启动每个虚拟主机的php-fpm 修改自默认的php-fpm,借助hosts的内容,读取每个主机的php-fpm配置文件启动各自的php-fpm。

8.在主 nginx 的配置文件中的 http{ } 中添加下面内容,我是删了所有的server{}的~

    # VHOST
    include   /vhost/*/*/nginx.conf; 

vhost 目录结构大致如下:
.
|-- user1
|   `-- qq.com
|       |-- nginx.conf
|       |-- php-fpm.conf
|       |-- php-fpm.pid
|       `-- php-fpm.socket
|-- chHosts.sh
|-- hosts
|-- logs
|   `-- user1_qq.com.log
`-- php-fpm

php-fpm.conf 文件内容大致如下:

<?xml version="1.0" ?>
<configuration>
    <section name="global_options">
        <value name="pid_file">/vhost/user1/qq.com/php-fpm.pid</value>  <!-- 记录主进程pid -->
        <value name="error_log">/vhost/logs/user1_qq.com.log</value>    <!-- 记录php-fpm错误日志 -->
        <value name="log_level">warn</value>                            <!-- 日志记录级别 -->
        <value name="emergency_restart_threshold">10</value>
        <value name="emergency_restart_interval">1m</value>
        <value name="process_control_timeout">5s</value>
        <value name="daemonize">yes</value>
    </section>
    <workers>
        <section name="pool">
            <value name="name">user1_qq.com</value>            <!-- 该pool名称,日志中使用 -->
            <value name="listen_address">/vhost/user1/qq.com/php-fpm.socket</value>   <!-- 使用socket 文件,要和和nginx中一致 -->
            <value name="listen_options">
                <value name="backlog">-1</value>
                <value name="owner"></value>
                <value name="group"></value>
                <value name="mode">0666</value>
            </value>
            <value name="php_defines">
                <!-- 这里可以设置php.ini中的参数,指定的php.ini无法覆盖。 -->
                <!--<value name="disable_functions">phpinfo,exec,passthru,shell_exec,system,proc_open,popen,show_source</value>
                <value name="open_basedir">/tmp/:./:/home/user1/qq.com/</value>-->
            </value>
            <value name="user">user1</value>        <!-- 执行php时的用户该用户有什么权限php就有什么权限~ -->
            <value name="group">user1</value>        <!-- 执行php是的用户组 -->
            <value name="pm">
                <value name="style">static</value>
                <value name="max_children">128</value>
                <value name="apache_like">
                    <value name="StartServers">10</value>
                    <value name="MinSpareServers">5</value>
                    <value name="MaxSpareServers">35</value>
                </value>
            </value>
            <value name="request_terminate_timeout">0s</value>
            <value name="request_slowlog_timeout">0s</value>
            <value name="slowlog">/vhost/logs/user1_qq.com_slow.log</value>   
            <value name="rlimit_files">65535</value>
            <value name="rlimit_core">0</value>
            <value name="chroot"></value>
            <value name="chdir"></value>
            <value name="catch_workers_output">yes</value>
            <value name="max_requests">1024</value>
            <value name="allowed_clients">127.0.0.1</value>
            <value name="environment">
                <value name="HOSTNAME">$HOSTNAME</value>
                <value name="PATH">/usr/local/bin:/usr/bin:/bin</value>
                <value name="TMP">/tmp</value>
                <value name="TMPDIR">/tmp</value>
                <value name="TEMP">/tmp</value>
                <value name="OSTYPE">$OSTYPE</value>
                <value name="MACHTYPE">$MACHTYPE</value>
                <value name="MALLOC_CHECK_">2</value>
            </value>

        </section>

    </workers>

</configuration>
有简单的注释,其他看 官方文档。
主要的是执行php时的用户和用户组,必须是 nginx 中 web目录的所有者 和 所有者的组,这样可以隔离开每个用户的虚拟主机,保证了基本的安全。
php_defines 中可以配置disable_functions 和 open_basedir 这样更加安全点。

nginx.conf的内容大致如下:
server {
  server_name www.qq.com qq.com;
  root   /home/user1/qq.com/wwwroot/;
  access_log  /home/user1/qq.com/logs/access.log;
 
  include /home/user1/qq.com/.nginx;
  location ~ \.php$ {
    fastcgi_pass   unix:/vhost/user1/qq.com/php-fpm.socket;
    fastcgi_index  index.php;
    include       fcgi.conf;
  }

  include   cache.conf;
  error_page   404 403 500 503 505 504 502
  error_page   500 503 505 504 502
}

php-fpm.socket 文件用于和 php-fpm 通信,当然也可以指向到/tmp目录下。
.nginx 上面说了,可以用作urlrewrite等配置。

cache.conf 内容:
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
      expires       30d;
    }

    location ~ .*\.(js|css)?$
    {
      expires       1h;
    }

fcgi.conf 内容大致如下:
 fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    'Apache/2.2.17 (Unix) DAV/2 PHP/5.2.17';

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect

fastcgi_param  REDIRECT_STATUS    200;

php-fpm 内容如下:
#!/bin/sh
#
# php-fpm - this script starts and stops the php-fpm daemin
#
# chkconfig: - 85 15
# description: php-fpm
# processname: php-fpm
# config:      /usr/local/php/etc/php-fpm.conf

vhost=$2

php_fpm_BIN=/usr/local/php/bin/php-cgi
php_fpm_CONF=/vhost/$vhost/php-fpm.conf
php_fpm_PID=/vhost/$vhost/php-fpm.pid
php_INI=/home/$vhost/php.ini


php_opts="--fpm-config $php_fpm_CONF"

if [ ! $vhost ]; then
    cat /vhost/hosts|while read line;do
         $0 $1 $line
    done
    exit
fi

if [ ! -r $php_fpm_CONF ]; then
    echo -n "不存在配置文件; $php_fpm_CONF"
    exit
fi

if [ -r $php_INI ]; then
    php_opts="$php_opts -c $php_INI"
fi


wait_for_pid () {
    try=0

    while test $try -lt 35 ; do

        case "$1" in
            'created')
            if [  -f "$2" ] ; then
                try=''
                break
            fi
            ;;

            'removed')
            if [ ! -f "$2" ] ; then
                try=''
                break
            fi
            ;;
        esac

        echo -n .
        try=`expr $try + 1`
        sleep 1

    done

}

case "$1" in
    start)
        if [ -f $php_fpm_PID ]; then
                echo 'Has started!'
                exit
        fi
        echo -n "Starting php_fpm ($vhost) "

        $php_fpm_BIN --fpm $php_opts

        if [ "$?" != 0 ] ; then
            echo " failed"
            exit 1
        fi

        wait_for_pid created $php_fpm_PID

        if [ -n "$try" ] ; then
            echo " failed"
            exit 1
        else
            echo " done"
        fi
    ;;

    stop)
        echo -n "Shutting down php_fpm ($vhost)"

        if [ ! -r $php_fpm_PID ] ; then
            echo "warning, no pid file found - php-fpm is not running ?"
            exit 1
        fi

        kill -TERM `cat $php_fpm_PID`

        wait_for_pid removed $php_fpm_PID

        if [ -n "$try" ] ; then
            echo " failed"
            exit 1
        else
            echo " done"
        fi
    ;;

    quit)
        echo -n "Gracefully shutting down php_fpm "

        if [ ! -r $php_fpm_PID ] ; then
            echo "warning, no pid file found - php-fpm is not running ?"
            exit 1
        fi

        kill -QUIT `cat $php_fpm_PID`

        wait_for_pid removed $php_fpm_PID

        if [ -n "$try" ] ; then
            echo " failed"
            exit 1
        else
            echo " done"
        fi
    ;;

    restart)
        $0 stop $2
        $0 start  $2
    ;;

    reload)

        echo -n "Reload service php-fpm "

        if [ ! -r $php_fpm_PID ] ; then
            echo "warning, no pid file found - php-fpm is not running ?"
            exit 1
        fi

        kill -USR2 `cat $php_fpm_PID`

        echo " done"
    ;;

    logrotate)

        echo -n "Re-opening php-fpm log file "

        if [ ! -r $php_fpm_PID ] ; then
            echo "warning, no pid file found - php-fpm is not running ?"
            exit 1
        fi

        kill -USR1 `cat $php_fpm_PID`

        echo " done"
    ;;

    *)
        echo "Usage: $0 {start|stop|quit|restart|reload|logrotate}"
        exit 1
    ;;

esac


会判断 虚拟主机目录下是否有php.ini有的话则读取用户的php.ini 启动php-fpm 没有则是默认的。
使用方法:
php-fpm start user1/qq.com 启动 user1 的qq.com 的php-fpm
或者
php-fpm start 启动所有虚拟主机的php-fpm

可以将该文件复制到/etc/init.d/ 中 用 service php-fpm start 的方式开启动,或者设置成开机启动。

大体就是这样了。

四、其他


可以使用下面的命令递归修改权限:
find /home/ -type f -exec chmod 0644 {} \;  #设置文件问644
find /home/ -type d -exec chmod 0711 {} \;  #设置目录问711

下面的shell可以用来创建目录和文件还有修改文件权限等:

mkdir /home/$OWNER$/$DOMAIN$/
mkdir /home/$OWNER$/$DOMAIN$/logs/
mkdir /home/$OWNER$/$DOMAIN$/wwwroot/
touch /home/$OWNER$/$DOMAIN$/.nginx
echo "$DOMAIN$" > /home/$OWNER$/$DOMAIN$/wwwroot/index.html
chown $OWNER$:$OWNER$ /home/$OWNER$/ -R
find /home/$OWNER$/ -type f -exec chmod 0644 {} \;
find /home/$OWNER$/ -type d -exec chmod 0711 {} \; 

------------------------- 上面是 shell ---------------------------------

要配置默认主机的话在 虚拟主机的nginx.conf 文件中在server_name 下添加 :

listen 80 default

另外我写了个简单的php程序用于创建虚拟主机的配置文件,还写了个简单的shell用于移动配置文件到 /vhost (生成的文件目前是放在web目录下~), 并且执行chHosts.sh 重新遍历查看有那些虚拟主机,然后重启 nginx 和 启动 php-fpm,让配置生效。就不放出来了,呵呵。

看到网上有人说 php-fpm 和 nginx 最好用no-body执行,然后那些需要写权限的目录要用户手动设置(可以用ftp)成777。nobody似乎确实相对会安全点,但是这样就会虚拟主机常出现权限问题。
我使用目录所有者确实是为了方便(不需要设置777)。 而且也独立了每个虚拟主机的php权限,这样即时知道了其他用户的 777 目录也修改不了。这样保证了各个虚拟主机的独立,但不保证该虚拟主机的安全。 见仁见智,或者看需求了,也可能是我没理解透彻权限问题。


然后 /tmp 安全:  Google搜索  Linux临时文件目录安全配置实例 , 不知道哪里是原创所以搜索吧。


我试传了个 webshell phpspy 似乎妥妥的。


最后希望有人能指出这样配置会不会有什么问题?
特别是安全方面的!或者是有什么建议都请指出来!

原文:http://bee.glroomy.com/nginx-php-fpm-urlwrite-php-ini.html

ps:似乎这边排版好看点~我要update下我blog了~   

你可能感兴趣的:(nginx,PHP,虚拟主机,php-fpm,独立)