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的博客”