Nginx虚拟主机配置,支持独立urlwrite 文件,php-fpm独立用户
  • 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 似乎妥妥的。


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

    作者“Qianfeng的博客”
     

     

  • 点这里复制本页地址发送给您QQ/MSN上的好友
  • 300*300广告