LNMP环境搭建
先安装MySQL
接下来安装PHP
1.解压资源包
# cd /usr/local/src
# tar -zxf php-5.6.30.tar.gz
- 安装和配置:
# yum install -y gcc
# yum install -y libxml2-devel
# yum install -y openssl openssl-devel
# yum install -y bzip2 bzip2-devel
# yum install -y libpng libpng-devel
# yum install -y freetype freetype-devel
# yum install -y epel-release
# yum install -y libmcrypt-devel
# yum install -y libjpeg-devel
# yum install -y libcurl-devel
//提前安装好库文件,防止安装时出错。
# useradd -s /sbin/nologin php-fpm
编译参数:
#cd php-5.6.30
# ./configure \
--prefix=/usr/local/php-fpm \
--with-config-file-path=/usr/local/php-fpm/etc \
--enable-fpm \
--with-fpm-user=php-fpm \
--with-fpm-group=php-fpm \
--with-mysql=/usr/local/mysql \
--with-mysql-sock=/tmp/mysql.sock \
--with-libxml-dir \
--with-gd \
--with-jpeg-dir \
--with-png-dir \
--with-freetype-dir \
--with-iconv-dir \
--with-zlib-dir \
--with-mcrypt \
--enable-soap \
--with-gd-native-ttf \
--enable-ftp \
--enable-mbstring \
--enable-exif \
--disable-ipv6 \
--with-pear \
--with-curl \
--with-openssl
- 编辑并安装
# make && make install
- 修改配置文件
# cp php.ini-production /usr/local/php-fpm/etc/php.ini
# vim /usr/local/php-fpm/etc/php-fpm.conf
[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
[www]
listen = /tmp/php-fcgi.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
保存配置文件后,,检验是否正确的方法如下:
# /usr/local/php-fpm/sbin/php-fpm -t
如果显示“test is successful”字样,就说明配置没有问题
启动php-fpm,命令如下:
# cp /usr/local/src/php-5.6.30/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
# chmod 755 /etc/init.d/php-fpm
# useradd -s /sbin/nologin php-fpm
# service php-fpm start
# chkconfig php-fpm on
# ps aux |grep php-fpm
3. 安装Nginx
- 解压
# cd nginx-1.12.2
# ./configure --prefix=/usr/local/nginx
# make && make install
# vim /etc/init.d/nginx // 写下如下内容:
#!/bin/bash
# chkconfig: - 30 21
# description: http service.
# Source Function Library
. /etc/init.d/functions
# Nginx Settings
NGINX_SBIN="/usr/local/nginx/sbin/nginx"
NGINX_CONF="/usr/local/nginx/conf/nginx.conf"
NGINX_PID="/usr/local/nginx/logs/nginx.pid"
RETVAL=0
prog="Nginx"
start()
{
echo -n $"Starting $prog: "
mkdir -p /dev/shm/nginx_temp
daemon $NGINX_SBIN -c $NGINX_CONF
RETVAL=$?
echo
return $RETVAL
}
stop()
{
echo -n $"Stopping $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -TERM
rm -rf /dev/shm/nginx_temp
RETVAL=$?
echo
return $RETVAL
}
reload()
{
echo -n $"Reloading $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -HUP
RETVAL=$?
echo
return $RETVAL
}
restart()
{
stop
start
}
configtest()
{
$NGINX_SBIN -C $NGINX_CONF -t
return 0
}
case "$1" in
start)
start
;;
stop)
stop
;;
reload)
reload
;;
restart)
restart
;;
configtest)
configtest
;;
*)
echo $"Usage: $o {start|stop|reload|restart|configtest}"
RETVAL=1
esac
exit $RETVAL
保存该脚本后更改权限,命令如下:
# chmod 755 /etc/init.d/nginx
# chkconfig --add nginx
设置开机启动Nginx,命令如下:
# chkconfig nginx on
更改Nginx的配置文件。
首先把原来的配置文件清空,
# > /usr/local/nginx/conf/nginx.conf //“>”可以把一个文本文档快速清空。
# vim /usr/local/nginx/conf/nginx.conf // 写下如下内容:
user nobody nobody;
worker_processes 2;
error_log /usr/local/nginx/logs/nginx_error.log crit;
pid /usr/local/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
events
{
use epoll;
worker_connections 6000;
}
http
{
include mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 3526;
server_names_hash_max_size 4096;
log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]'
' $host "$request_uri" $status'
' $http_referer" "$http_user_agent"';
sendfile on;
tcp_nopush on;
keepalive_timeout 30;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 8 4k;
request_pool_size 4k;
output_buffers 4 32k;
postpone_output 1460;
client_max_body_size 10m;
client_body_buffer_size 256k;
client_body_temp_path /usr/local/nginx/client_body_temp;
proxy_temp_path /usr/local/nginx/proxy_temp;
fastcgi_temp_path /usr/local/nginx/fastcgi_temp;
fastcgi_intercept_errors on;
tcp_nodelay on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 8k;
gzip_comp_level 5;
gzip_http_version 1.1;
gzip_types text/plain application/x-javascript text/css text/htm
application/xml;
server
{
listen 80;
server_name localhost;
index index.html index.htm index.php;
root /usr/local/nginx/html;
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;
}
}
}
配置完后,用如下命令检验:
# /usr/local/nginx/sbin/nginx -t
如果显示如下内容,则说明配置文件正确。
然后让服务重新启动:
# systemctl daemon-reload
再启动服务:
测试是否正确解析PHP
首先创建文件,操作如下:
# vim /usr/local/nginx/html/2.php
其内容如下:
<?php
echo “test php scripts.”;
?>
执行下面命令测试文件:
# curl locahost/2.php
4.Nginx配置
1.默认虚拟主机
在Nginx中也有默认虚拟主机,跟httpd类似,第一个被Nginx加载的虚拟主机就是默认主机。但和httpd不相同的地方是,他还有一个配置用来标记默认虚拟主机。也就是说,如果没有这个标记,第一个虚拟主机为默认虚拟主机。
修改主配置文件nginx.conf,在结束符号}上面加一行配置,改写如下:
include vhost/*.conf; //意思是:/usr/local/nginx/conf/vhost下面的所有以.conf的文件都被加载。
}
把所有虚拟主机配置文件放到vhost目录下
# mkdir /usr/local/nginx/conf/vhost
# cd /usr/local/nginx/conf/vhost
# vim default.conf //写入如下内容:
server
{
listen 80 default_server;
server_name aaa.com;
index index.html index.htm index.php;
root /data/nginx/default;
}
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
# echo “default_server” > /data/nginx/default/index.html
# curl -x127.0.0.1:80 aaa.com
# curl -x127.0.0.1:80 1212.com
2. 用户认证
# cd /usr/local/nginx/conf/vhost/
# vim test.com.conf //内容如下:
server
{
listen 80;
server_name test.com;
index index.html index.htm index.php;
root /data/nginx/test.com;
location /
{
auth_basic "Auth";
auth_basic_user_file /usr/local/nginx/conf/htpasswd;
}
}
安装httpd
# yum install -y httpd
创建ajun用户
# htpasswd -c /usr/local/nginx/conf/htpasswd ajun
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
核心配置语句就两行,auth_basic打开认证,auth_basic_user_file指定用户密码文件,当然前提是这个用户密码文件存在。而生成用户密码文件的工具需要借助httpd的htpasswd,Nginx不自带这个工具。下面用curl进行验证。
# mkdir /data/nginx/test.com
# echo “test.com” > /data/nginx/test.com/index.html
# curl -I -x127.0.0.1:80 test.com
401表示该网站需要验证
在电脑主机的hosts文件下,加一行
虚拟机IP test.com
在电脑主机游览器上搜索test.com
3. 域名重定向
继续修改test.com.conf文件
在Nginx配置中,server_name后面可以跟多个域名,permanent为永久重定向,相当于httpd
的R=301。另外还有一个常用的redirect,相当于httpd的R=302。测试过程如下:
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
# curl -x127.0.0.1:80 test1.com/123.txt -I
- Nginx的访问日志
先看看Nginx的日志格式:
# grep -A2 log_format /usr/local/nginx/conf/nginx.conf
和httpd类似,也是在主配置文件中定义的日志格式。combined_realip为日志格式的名字,后面可以调用它;$remote_addr为访问网站的用户的出口IP;$http_x_forwarded_for为代理服务器的IP,如果使用了代理,则会记录代理的IP;$time_local为当前的时间;$host为访问的主机名;$request_uri为访问的URL地址;$status为状态码;$http_referer为referer地址;$http_user_agent为user_agent。
然后再到虚拟机主机配置文件中指定访问日志的路径;
server
{
listen 80;
server_name test.com test1.com test2.com;
index index.html index.htm index.php;
root /data/nginx/test.com;
if ($host != 'test.com' )
{
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
access_log /tmp/1.log combined_realip;
}
使用access_log来指定日志的储存路径,最后面指定日志的格式名字,测试过程如下:
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
# curl -x127.0.0.1:80 test.com/111
# cat /tmp/1.log
Nginx的日志简单,httpd有自己的切割工具,要想切割Nginx日志需要借助系统的切割工具或者自定义脚本。下面是一个Nginx的日志切割脚本:
# vim /usr/local/sbin/nginx_log_rotate.sh //写下如下内容:
#! /bin/bash
## 假设nginx的日志存放路径为/data/logs/
d=`date -d “-1 day” +%y%m%d`
logdir=”/data/logs”
nginx_pid=”/usr/local/nginx/logs/nginx.pid”
cd $logdir
for log in `ls *.log`
do
mv $log $log-$d
done
/bin/kill -HUP `cat $nginx_pid`
写完后脚本后,还需要增加任务计划:
# crontab -e //写入如下内容:
0 0 * * * /bin/bash /usr/local/sbin/nginx_log_rotate.sh
5. 配置静态文件不记录日志并添加过期时间
修改虚拟机配置文件改写如下:
server
{
listen 80;
server_name test.com test1.com test2.com;
index index.html index.htm index.php;
root /data/nginx/test.com;
if ($host != 'test.com' )
{
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 7d;
access_log off;
}
location ~ .*\.(js|css)$
{
expires 12h;
access_log off;
}
access_log /tmp/1.log combined_realip;
}
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
# echo "111111111111" > /data/nginx/test.com/1.js //创建js文件
# echo "222222222222" > /data/nginx/test.com/2.jpg //创建jpg文件
# touch /data/nginx/test.com/1.jss //创建一个对比文件
# curl -I -x127.0.0.1:80 test.com/1.js
# curl -I -x127.0.0.1:80 test.com/2.jpg
# curl -I -x127.0.0.1:80 test.com/1.jss
访问了js以及jpg,但没有记录到访问日志中,效果实现。
6. Nginx防盗链
配置文件内容如下:
server
{
listen 80;
server_name test.com test1.com test2.com;
index index.html index.htm index.php;
root /data/nginx/test.com;
if ($host != 'test.com' )
{
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 7d;
access_log off;
}
location ~ .*\.(js|css)$
{
expires 12h;
access_log off;
}
access_log /tmp/1.log combined_realip;
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.test.com ;
if ($invalid_referer) {
return 403;
}
access_log off;
}
}
将红色部分删除
# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload
# curl -x127.0.0.1:80 -I -e "http://aaa.com/1.txt" test.com/2.jpg
# curl -x127.0.0.1:80 -I -e "http://test.com/1.txt" test.com/2.jpg
7. 访问控制
和httpd一样,Nginx也需要限制某些IP不能访问或者只允许某些IP访问。配置方法和httpd很像,例如:我们有一个需求“使访问admin目录的请求只允许192.168.188.0和127.0.0.1访问”,配置文件如下:
localtion /admin/
{
allow 192.168.40.20; //自己虚拟机IP网段
allow 127.0.0.1;
deny all;
}
在配置httpd的时候,还有一个order,来定义先allow还是先deny,在Nginx里并没有,只要匹配规则就结束了。假如来源IP为192.168.188.129.它会从下到上逐一去匹配,第一个IP(192.168.188.1)不匹配,第二个IP(127.0.0.1)不匹配,直到第三行(all)的时候才匹配到,匹配的这条规则为deny(也就是拒绝访问),所以最终会返回一个403的状态码。测试如下:
# mkdir /data/nginx/test.com/admin/
# echo “123” > /data/nginx/test.com/admin/1.html
# curl -x127.0.0.1:80 test.com/admin/1.html
# curl -x192.168.40.166:80 test.com/admin/1.html //curl自己虚拟机IP
配置文件中的IP也可以为IP段,比如写成allow 192.168.40.0/24。如果只拒绝某个IP,就可以写成如下:
location /admin/
{
deny 192.168.40.1; //自己虚拟机IP网段
deny 127.0.0.1;
}
如果是黑名单的形式,就不需要写allow all 了,因为默认就是允许所有。除了这种简单的限制外,也可以根据正则匹配来限制,如下:
location ~ .*(abc|image)/.*\.php$
{
deny all;
}
小括号里面的竖线为分隔符,他们之间的是“或者”的意思。这样就可以把访问的URL中带有abc或者image字符串,并且是PHP的请求拒绝访问。上一章阿铭说过,要把可以上传文件的目录禁止解析PHP,目的是保证安全。在Nginx配置中,只需要这样几行就可以做到。
在Nginx配置里,也可以针对user_agent做一些限制,配置如下:
if ($http_user_agent ~ ‘Spider/3.0|YoudaoBot|Tomato’)
{
return 403;
}
其中~为匹配符号,只要user_agent中含有Spider/3.0或者YoudaoBot或者Tomato字符串的,都会被拒绝,return 403为直接返回403的状态码,当然也可以把它替换为deny all。
8. Nginx解析PHP
在LAMP中,PHP是作为httpd的一个模块出现的,只要PHP模块被加载,那么就能解析PHP脚本了。而在LNMP中,PHP是以一个服务(php-fpm)的形式存在的,首先要启动php-fpm服务,然后Nginx再和php-fpm通信。也就是说,处理PHP脚本解析的工作是由php-fpm来完成的,Nginx仅仅是一个搬运工,他把用户的请求传递给php-fpm。php-fpm处理完成后把结果传递给Nginx,Nginx再把结果返回给用户。下面是test.com.conf的内容,其中包含了PHP相关配置:
server
{
listen 80;
server_name test.com test1.com test2.com;
index index.html index.htm index.php;
root /data/nginx/test.com;
if ($host != 'test.com' ) {
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/nginx/test.com$fastcgi_script_name;
}
access_log /tmp/1.log combined_realip;
}
其中fastcgi_pass用来指定php-fpm的地址,如果php-fpm监听的是一个tcp:port的地址(比如127.0.0.1:9000),那么也需要在这里改成fastcgi_pass 127.0.0.1:9000。这个地址一定要和php-fpm服务监听地址匹配,否则会报502错误。
还有一个地方也需要注意,factcgi_param SCRIPT_FILENAME后面跟的路径为该站点的根目录,和前面定义的root路径保持一致。如果这里配置不对,访问PHP页面会出现404。
9. Nginx配置SSL
HTTPS通信过程:
大致过程如下:
- 游览器发送一个HTTPS请求给服务器。
- 服务器要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥。
- 服务器会把公钥传输给客户端。
- 客户端(游览器)收到公钥后,会验证其是否合法有效,无效会有警告提醒,有效则会生成一串随机字符串,并用收到的公钥加密。
- 客户端把加密后的随机字符串传输给服务器。
- 服务器收到加密随机字符串后,先用私钥解密(公钥加密,私钥解密),获取到这一穿随机字符串后,在用这随机字符串加密传输的数据(该加密为“对称加密”;所谓对称加密,就是将数据和私钥,也就是这个随机字符串通过某种算法混合在一起,这样除非知道私钥,否则无法获取数据内容)。
- 服务器把加密后的数据传输给客户端。
- 客户端收到数据后,再用自己的私钥(也就是那个随机字符串)解密。
# cd /usr/local/nginx/conf
# openssl genrsa -des3 -out tmp.key 2048
//生成key文件(私钥),输入两遍密码。
# openssl rsa -in tmp.key -out aminglinux.key
//把刚刚生成的tmp.key转换成aminglinux.key,目的是删除刚才设置的密码。
# rm -f tmp.key
# openssl req -new -key tcq.key -out aminglinux.csr
//生成证书请求文件,我们要用key文件个这个CSR文件生成最终的公钥。
# openssl x509 -req -days 365 -in aminglinux.csr -signkey aminglinux.key -out aminglinux.crt
//最终生成了CRT证书文件,也就是公钥。
# vim /usr/local/nginx/conf/vhost/ssl.conf //写入以下内容
server
{
listen 443;
server_name aming.com;
index index.html index.php;
root /data/nginx/aming.com;
ssl on;
ssl_certificate aminglinux.crt;
ssl_certificate_key aminglinux.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/nginx/aming.com$fastcgi_script_name;
}
access_log /tmp/1.log combined_realip;
}保存文件后,检查配置是否有问题,
# cd /usr/local/src/nginx-1.12.2/
# ./configure --prefix=/usr/local/nginx --with-http_ssl_module
# make && make install
# /usr/local/nginx/sbin/nginx -t
# mkdir /data/nginx/aming.com
# echo “<?php phpinfo(); ?>” > /data/nginx/aming.com/1.php
# /etc/init.d/nginx restart
再编辑hosts文件,写入一行:
192.168.40.166 aming.com
然后用游览器访问https:aming.com/1.php
php-fpm配置
php-fpm的配置文件为/usr/local/php-fpm/etc/php-fpm.conf
1. php-fpm的pool
Nginx可以配置多个虚拟主机,php-fpm同样支持配置多个pool,每个pool可以监听一个端口,也可以监听一个socket,配置/usr/local/php-fpm/etc/php-fpm.conf内容如下:
[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
include = etc/php-fpm.d/*.conf
然后需要创建配置文件目录和子配置文件:
# mkdir /usr/local/php-fpm/etc/php.fpm.d
# cd /usr/local/php-fpm/etc/php-fpm.d
# vim www.conf // 内容如下:
[www]
listen = /tmp/www.sock
listen.mode=666
user = php-fpm
group = php-fpm
pm =dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers =35
pm.max_requests = 500
rlimit_files = 1024
保持后,再编辑另外的配置文件:
# vim aming.conf //写入如下内容:
[aming]
listen = /tmp/aming.sock
listen.mode=666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers =35
pm.max_requests = 500
rlimit_files = 1024
这样就有两个子配置文件,也就是说有两个pool了,第一个pool监听了/tmp/www.sock,第二个pool监听了/tmp/aming.sock。这样,就可以在Nginx不同的虚拟主机中调用不同的pool,从而达到相互隔离的目的,两个pool互不影响。下面进行验证:
# /usr/local/php-fpm/sbin/php-fpm -t
然后重启一下php-fpm服务:
# /etc/init.d/php-fpm restart
再来查看/tmp/目录下面的sock文件:
- php-fpm的慢执行日志
php-fpm的慢执行日志用的很多,他可以帮助你快死的追踪到问题点。为理解php-fpm慢执行日志,我们举一个例子。
小红是一个运维工程师,他维护的网站是用PHP语言写,运行环境为LVMP,网站访问量不算大,一直都很稳定,但有一天,网站突然很卡,打开一个页面需要1几秒,小红发现问题后,马上登录服务器排查问题。他做的操作有,使用w命令查看服务器负载,使用free命令查看内存,使用top命令查看哪个进程占用CPU,使用nload命令查看网卡流量等等总之小红做了很多操作,种种迹象表明php-fpm进程占用了很多资源。
但php-fpm进程究竟在干什么?为什么耗费了很多资源呢?小红很想知道,只有找到问题点,才能解决php-fpm耗费资源的问题,然后网站自然就快了。小红的经验有限,不知道怎么去查看php-fpm在干神魔。在哪一步的时候卡住了呢?小红开始用游览器去搜文档,找了很久,才找到一个很有效的方法,其实就是php-fpm慢执行日志。
通过php-fpm的慢执行日志,我们可以非常清晰地了解到PHP的脚本哪里执行时间长,他可以定位到具体的行。开启和查看php-fpm的慢执行日志,操作步骤如下:
# vim /usr/local/php-fpm/etc/php-fpm.d/www.conf //在最后面加入如下内容
request_slowlog_timeout = 1
slowlog = /usr/local/php-fpm/var/log/www-slow.log
3. php-fpm定义open_basedir
# vim /usr/local/php-fpm/etc/php-fpm.d/aming.conf //在最后面加入
php_admin_value[open_basedir]=/data/www/:/tmp/
4. php-fpm进程管理
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers =35
pm.max_requests = 500