基于Debian系统构建安全的LNMP环境(Linux+Nginx+Mysql+PHP)

之前我对lnmp组合一直诟病的是无法像lamp一样提供suexec环境,那么便有切实存在的安全隐患。今天恰好找到了近似解决途径,遂实践之。

本文基于Debian 8 jessie系统,其他素三鲜皆用apt库中的最新稳定版构成,尽最大可能不从源代码编译,本人特反感编译安装。

首先update系统的apt库以及习惯性的系统调整这些就不啰唆了,之前文章都有,直接后面的步骤:

一,安装相关软件:

apt-get install -y update-inetd nginx-extras php5-cgi php5-fpm php-pear php5-gd php5-imap php5-mcrypt php5-xmlrpc php5-xsl php5-mysql php5-curl php5-common php5-dev php5-imagick php5-memcache php5-pspell php5-recode php5-sqlite php5-tidy libnet-ssleay-perl libauthen-pam-perl libio-pty-perl proftpd ucf php-db mysql-server-5.5 mysql-client-5.5

中途会要求输入mysql的root密码和选择proftpd的运行模式。

二,根据自身需要对配置文件进行修改:

首先改动/etc/nginx/nginx.conf文件,我自用的配置如下:

user www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /run/nginx.pid;


events {
    use   epoll; 
    worker_connections  200000;
}


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"';


ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;
    sendfile     on;
    keepalive_timeout  120;
    tcp_nodelay     on;
    
    types_hash_max_size 2048;

gzip on;
gzip_min_length 1k;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
server_names_hash_bucket_size 1024; #服务器名字的hash表大小
proxy_headers_hash_max_size 51200; #设置头部哈希表的最大值,不能小于你后端服务器设置的头部总数
proxy_headers_hash_bucket_size 6400;#设置头部哈希表大小

send_timeout                600;
more_set_headers  "Server: www.tingtao.org_US_new";
server_tokens off;



include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;


}

然后在 /etc/mysql/my.cnf 文件对这几行进行修改或者增加:

       #bind-address           = 127.0.0.1

#添加
character-set-server=gbk
default-storage-engine=MYISAM
skip-name-resolve
lower_case_table_names = 1
max_connections=1000

#修改
max_allowed_packet = 10000M

授权root用户远程登录:

#授权root远程登录,密码是7758,各位自行修改
mysql -u root -p7758
grant all privileges on *.* to root@"%" identified by '7758' with grant option;
exit;

/etc/init.d/mysql restart

Proftpd的修改我忘记具体内容了,我是直接用自己编辑好的模板:

wget http://soft.tingtao.org/proftpd/proftpd_debian8.txt -O /etc/proftpd/proftpd.conf
/etc/init.d/proftpd restart

第二阶段到此结束。

三:配置nginx与php的亲密接触:

命令:

echo 'fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/:/usr/share/php/";' >> /etc/nginx/fastcgi_params
echo 'fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/:/usr/share/php/";' >> /etc/nginx/fastcgi.conf
echo "php_admin_value[open_basedir]=/var/www/:/proc/:/tmp/:/usr/share/php/" >> /etc/php5/fpm/php-fpm.conf

这些就是之前我没找到的细节,可以将php程序限定在一些特定目录,其中“:/usr/share/php/”这个路径是我有个php程序特别需要的,一般来说用不到这个。

站点配置的模板文件:

#######################################################
#                      www.tingtao.org

server {
        listen          80;
        server_name     www.tingtao.org;
        keepalive_timeout    120;
        
        listen          443 ssl;
		#修改1
        ssl_certificate      /var/www/ca/www.tingtao.org/Nginx/1_www.tingtao.org_bundle.crt;
        ssl_certificate_key  /var/www/ca/www.tingtao.org/Nginx/2_www.tingtao.org.key;

        ##############################################

		#修改2
    	access_log /var/www/logs/www.tingtao.org.log;
		error_log /var/www/logs/www.tingtao.org_err.log;
		
		#修改3
		root /var/www/www.tingtao.org;

		location ~ ^.+\.php {
        fastcgi_split_path_info ^(.+\.php)(.*)$;
		#修改4
        fastcgi_pass   unix:/var/run/php5-fpm-www.tingtao.org.sock;
        fastcgi_index  index.php;
		#修改5
        fastcgi_param  SCRIPT_FILENAME  /var/www/www.tingtao.org$fastcgi_script_name;
        include fastcgi_params;
        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 PHP_ADMIN_VALUE   "open_basedir=$document_root/:/tmp/:/proc/";
        fastcgi_intercept_errors        on;
		fastcgi_ignore_client_abort     on;
        fastcgi_read_timeout 180;
     }
	 
	 location / {
			#定义首页索引文件的名称
            index index.php index.html index.htm;
			#下面这行和后面的跟wordpress有关,非wp程序用不到
			try_files $uri $uri/ /index.php?$args;
			}
	rewrite /wp-admin$ $scheme://$host$uri/ permanent;

}

 

站点相关的目录创建、用户设置等内容:

useradd www.tingtao.org -s /sbin/nologin || exit 1
echo www.tingtao.org:密码|chpasswd
groupadd -f www.tingtao.org
usermod -G www.tingtao.org -a www-data
usermod -G www.tingtao.org -a proftpd
mkdir /var/www/www.tingtao.org
usermod -d /var/www/www.tingtao.org www.tingtao.org
chown -R www.tingtao.org:www.tingtao.org /var/www/www.tingtao.org
chmod -R 755 /var/www/www.tingtao.org

www.tingtao.org这个用户我放进两个组里面,一个是跟web服务器相关的,一个是跟ftp相关的,这样会方便许多。

为这个站点搞一个独立的php配置:

cat > /etc/php5/fpm/pool.d/www.tingtao.org.conf <<- _EOF1_
[www.tingtao.org]
user = www.tingtao.org
group = www.tingtao.org
listen = /var/run/php5-fpm-www.tingtao.org.sock
listen.owner = www-data
listen.group = www-data
php_admin_value[include_path] = .:/var/www/globals/www.3ha.net/lib
php_admin_value[open_basedir] = /var/www/www.tingtao.org:/tmp
php_admin_value[upload_max_filesize] = 50M
php_admin_value[max_execution_time] = 30
php_admin_value[max_input_time] = 60
php_admin_value[memory_limit] = 128M
php_admin_value[output_buffering] = 4096
php_admin_value[disable_functions] = system,exec,shell_exec,passthru,error_log,dl,sys_getloadavg,pfsockopen,openlog,syslog,readlink,symlink,link,leak,popen,escapeshellcmd,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,escapeshellarg,pcntl_exec,show_source,highlight_file,ini_restore,apache_child_terminate,apache_get_modules,apache_get_version,apache_getenv,apache_note,apache_setenv,virtual,mb_send_mail,set_time_limit,max_execution_time,php_uname,disk_free_space,diskfreespace,stream_copy_to_stream
php_admin_flag[allow_url_fopen] = off
php_admin_flag[expose_php] = Off
php_admin_flag[display_errors] = Off
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
chdir = /
_EOF1_

 

简单解释一下。listen与nginx站点配置中的fastcgi_pass相对应,否则连不上的。listen的组和用户与nginx相同,如此方能确保不会受到权限阻碍。该站点的php永远运行在该站点自身账号权限下,这样上传什么的不会有阻碍,同时每个站点搞这么一个独立的php环境,也不会影响其他站点的安全性和稳定性。

最后,重启一下php-fpm和nginx即可:

/etc/init.d/php-fpm restart
/etc/init.d/nginx restart

 

如此这般呢,可以确认的是,首先通过ftp上传的文件是属于www.tingtao.org的,然后站点运行的身份也是这个用户,那么对于几乎所有php程序来说都不存在权限方面的问题,同时确保安全性。

确认一下是否符合预期:

基于Debian系统构建安全的LNMP环境(Linux+Nginx+Mysql+PHP)

可以看到,这个php-fpm的运行身份确实是该站点账户,那么基于文件系统的acl则会阻挡非法的跨目录权限,关于这一点我没测试,我认为也不必测试,但需要注意的是,其实上面的755权限不太适合出售空间的情况,如果你提供虚拟空间给别人的话,应该用750好些。

然后呢,这个方案可以很简单的实现php多版本,在我这没必要,各位需要的话略微修改就可以了。

 

就个人观察的情况来说,在我这两颗至强,4G内存,SSD硬盘加上200M独享带宽的服务器环境上,不知道是不是错觉,总感觉响应速度和apache+php没啥区别;内存占用方面,php-fpm似乎还高于apache的fcgid,确实有点不理解……

按照经验来推测的话,在低配服务器上的效果应该会强于lamp的。

 

 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: