0%

linux学习笔记:lnmp环境的搭建和配置

写在前面

这则笔记主要整理lnmp相关的内容,主要包括3个部分:

  • LNMP简介

  • lnmp环境搭建

  • lnmp基础配置

系统环境:

  • linux: centos7.4

  • nginx:1.14

  • mysql:5.6

  • php:7

LNMP简介

LNMP架构是什么?

所谓LNMP,就是Linux系统下Nginx+MySQL+PHP这种网站服务器架构。

与LAMP不同,LNMP的工作模式:

  • 在LAMP中,提供web服务的是apache;而在LNMP中,提供web服务的是Nginx;

  • 在Apache中,PHP是作为一个模块存在的;在Nginx中,PHP是作为一个独立服务存在的,这个服务叫做php-fpm;

  • Nginx直接处理静态请求(支持的并发更高,速度比Apache快),动态请求转发给php-fpm处理。

nginx 的优缺点:

  • 优点:占用VPS资源较少,Nginx配置起来也比较简单,利用fast-cgi的方式动态解析PHP脚本。

  • 缺点:php-fpm组件的负载能力有限,在访问量巨大的时候,php-fpm进程容易僵死,容易发生502 bad gateway错误

php-fpm又是什么?

这里涉及到到一些新的概念,整理如下:

  • CGI,即公共网关接口Common Gateway Interface,简单地说,就是网页的表单和你写的程序之间通信的一种协议。CGI针对每个http请求都是fork一个新进程来进行处理,处理过程包括解析php.ini文件,初始化执行环境等,然后这个进程会把处理完的数据返回给web服务器,最后web服务器把内容发送给用户,刚才fork的进程也随之退出。

  • FastCGI,是CGI的更高级的一种方式,是用来提高CGI程序性能的。Fastcgi则会先fork一个master,解析配置文件,初始化执行环境,然后再fork多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复劳动,提高了工作效率。

  • PHP-CGI,是PHP自带的FastCGI管理器。只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理。所以,就出现了很多进程调度的工具,比如spawn-fcgi。

  • PHP-FPM,是PHP FastCGI管理器,之前是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中。从PHP5.3.3版本开始,PHP内核集成了PHP-FPM之后就方便多了,使用–enalbe-fpm这个编译参数安装即可。

系统环境准备

Linux系统环境

  • LNMP需要预留5G以上的剩余空间;

  • 安装MySQL 5.6或5.7及MariaDB 10必须1G以上内存;

  • 安装vim yum install -y vim-enhanced

  • 提前安装 好GCC编译器 yum install -y gcc

  • 系统防火墙设置,关闭firewalld;安装并配置好itables,开放80、3306端口;同时,selinux设置为disabled

必装软件:

  • vim yum install -y vim-enchanced

  • tree yum install -y tree

  • wget yum install -y wget

  • gcc yum install -y gcc gcc+

语言环境变量设置

1
2
3
4
5
vim /etc/envirment

//增加两行
LANG=en_US.utf-8
LC_ALL=en_US.utf-8

关闭firewalld

1
2
3
4
//关闭firewalld
systemctl stop firewalld.service
//禁止开机启动
systemctl disable firewalld.service

安装配置iptables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//安装iptables
yum install -y iptables-services
//编辑配置文件,重点是开放80、3306端口
vim /etc/sysconfig/iptables
# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT //开放80端口,针对httpd
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT //开放3306端口,针对mysql
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
//重启防火墙使配置生效
[root@stevey ~]# systemctl restart iptables.service
//设置防火墙开机启动
[root@stevey ~]# systemctl enable iptables.service

关闭selinux

1
2
3
vim /etc/selinux/config

//找到SELINUX=enforcing这一行,将enforcing 改为 disabled,保存退出并重启虚拟机

阶段成果

软件环境安装

mysql 安装

第一步:下载二进位制包

1
2
3
4
5
6
7
wget http://mirrors.sohu.com/mysql/MySQL-5.6/mysql-5.6.36-linux-glibc2.5-x86_64.tar.gz

//解压
tar -zvxf mysql-5.6.36-linux-glibc2.5-x86_64.tar.gz

//进入安装包
cd mysql-5.6.36-linux-glibc2.5-x86_64

第二步:创建mysql账户及目录

1
2
3
4
5
6
7
8
9
10
11
创建mysql安装目录
mkdir -p /usr/local/mysql

//创建mysql用户 -s指定shell
useradd -s /sbin/nologin mysql

//创建数据库文件
mkdir -p /data/mysql

//更改用户名和所属组权限
chown -R mysql:mysql /data/mysql

第三步:安装依赖项

1
2
3
4
5
//安装依赖包perl-Module-Install
yum install -y perl-Module-Install

//安装依赖包libaio
yum install -y libaio

第四步:编译安装

1
2
3
4
5
6
7
8
9
10
11
12
//将编译好的二进位制包移动到/usr/local/mysql目录下
mv /usr/local/src/mysql-5.6.36-linux-glibc2.5-x86_64/* /usr/local/mysql/

//进入mysql目录
cd /usr/local/mysql/

//编译参数
./scripts/mysql_install_db --user=mysql --datadir=/data/mysql

//校验结果
[root@VM_0_14_centos mysql]# echo $?
0 //返回0说明成功

第五步:修改环境变量

1
2
3
4
5
//修改配置文件
vim ~/.bash_profile

//将mysql路径加入环境变量
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin

第六步:配置mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//复制配置文件
cp support-files/my-default.cnf /etc/my.cnf

//编辑配置文件
vim /etc/my.cnf

//修改以下配置
log_bin = root //15行
basedir = /usr/local/mysql
datadir = /data/mysql
port = 3306
server_id = 128
socket = /tmp/mysql.sock

//去掉以下配置前面的的型号
innodb_buffer_pool_size = 128M
join_buffer_size = 128M
sort_buffer_size = 2M
read_rnd_buffer_size = 2M

第七步:配置启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd /usr/local/mysql

//复制启动脚本到/etc/init.d/mysqld
cp support-files/mysql.server /etc/init.d/mysqld

//修改文件权限
chmod 755 /etc/init.d/mysqld

//编辑启动脚本
vim /etc/init.d/mysqld

//更改data保存目录
basedir=/usr/local/mysql
datadir=/data/mysql

第八步:设置开机启动

1
2
3
4
5
6
7
8
9
10
11
//进入系统服务目录 /etc/init.d/
cd /etc/init.d/

//将mysqld 服务加入系统服务列表
chkconfig --add mysqld

//设置开机启动
chkconfig mysqld on

//启动mysqld
service mysqld start

校验是否启动

方法一:查看进程,结果应大于2行

方法二:查看端口监听情况

1
netstat -lnp |grep mysqld

TroubleShooting:mysqld服务未启动

重启服务即可

nginx 安装

第一步:下载源码包

1
2
3
4
5
6
7
8
//源码包放到/usr/local/src目录
cd /usr/local/src

//下载
wget https://nginx.org/download/nginx-1.14.0.tar.gz

//解压
tar -zxvf nginx-1.14.0.tar.gz

第二步:安装依赖包

  • gcc、gcc+ 安装方法:yum install -y gcc gcc-c++

  • PCRE库 安装方法:yum install -y pcre pcre-devel

  • zlib库 安装方法:yum install -y zlib zlib-devel

  • OpenSSL开发库(支持https) 安装方法:yum install -y openssl openssl-devel

第三步:创建用户及安装目录

1
2
3
4
5
6
//创建安装目录
mkdir -p /usr/local/nginx

//创建用户
groupadd nginx
useradd -M -s /sbin/nologin -g nginx nginx

第四步:编译安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//进入源码包
cd nginx-1.14.0

//编译参数
./configure \
--prefix=/usr/local/nginx \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre

//编译安装
make && make install

第五步:启动nginx

1
2
3
4
5
6
7
8
9
10
//设置软链接
ln -s /usr/local/nginx/sbin/nginx /usr/sbin

//语法检查
[root@VM_0_14_centos nginx-1.14.0]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

//启动nginx
nginx

校验成果

1
2
3
4
5
6
[root@VM_0_14_centos nginx-1.14.0]# ps -aux | grep nginx
root 12551 0.0 0.1 45928 1120 ? Ss 17:09 0:00 nginx: master process nginx
nginx 12552 0.0 0.1 48460 1976 ? S 17:09 0:00 nginx: worker process
root 12557 0.0 0.0 112704 976 pts/3 R+ 17:09 0:00 grep --color=auto nginx
[root@VM_0_14_centos nginx-1.14.0]# netstat -lnp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 12551/nginx: master

第六步:编写启动脚本并加入系统服务

  • 编写启动脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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: $0 {start|stop|reload|restart|configtest}"
RETVAL=1
esac
exit $RETVAL
  • 更改脚本权限
1
chmod a+x /etc/init.d/nginx
  • 启动脚本
1
2
chkconfig --add nginx
chkconfig nginx on

注:这里遇到一个很奇怪的错误,nginx启动失败;restart也不行,后来尝试init 6 重启主机后成功。

测试结果如下,nginx成功启动

php安装

第一步:下载并解压源码包

1
2
3
4
5
6
7
cd /usr/local/src/

//wget命令下载
wget http://cn2.php.net/distributions/php-7.2.6.tar.gz

//解压源码包
tar -zxvf php-7.2.6.tar.gz

第二步:安装依赖包

1
2
//安装依赖包
yum install -y libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel gmp gmp-devel libmcrypt libmcrypt-devel readline readline-devel libxslt libxslt-devel

第三步:创建账号

1
useradd -s /sbin/nologin php-fpm

第四步:编译安装

1
2
3
4
5
6
7
8
//进入安装目录
cd /usr/local/src/php-7.2.6

//编译参数
./configure --prefix=/usr/local/php-fpm --with-config-file-path=/usr/local/php-fpm/etc --with-fpm-user=php-fpm --with-fpm-group=php-fpm --enable-mysqlnd --with-mysqli --with-pdo-mysql --enable-fpm --with-gd --with-iconv --with-zlib --enable-xml --enable-shmop --enable-sysvsem --enable-inline-optimization --enable-mbregex --enable-mbstring --enable-ftp --with-openssl --enable-pcntl --enable-sockets --with-xmlrpc --enable-zip --enable-soap --without-pear --with-gettext --enable-session --with-curl --with-jpeg-dir --with-freetype-dir --enable-opcache

//编译安装
make && make install
TroubleShooting:虚拟内存不足导致make失败

因为php的安装包比较大,因此经常会在make的时候出现虚拟内存不够报错的情况。笔者在本地虚拟机和云主机的配置都是1G内存,也都遇到了这个情况,解决的办法是手动增加swap交换空间。

手动增加swap空间的步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//建立swapfile
[root@tencentcvm php-7.2.6]# mkdir -p /usr/img/
[root@tencentcvm php-7.2.6]# rm -rf /usr/img/swap
[root@tencentcvm php-7.2.6]# dd if=/dev/zero of=/usr/img/swap bs=1024 count=2048000
2048000+0 records in
2048000+0 records out
2097152000 bytes (2.1 GB) copied, 19.5733 s, 107 MB/s

//格式化swap
[root@tencentcvm php-7.2.6]# mkswap /usr/img/swap
Setting up swapspace version 1, size = 2047996 KiB
no label, UUID=0d8a402b-11d0-4e0d-afa0-05c002b3df07

//挂载swap
[root@tencentcvm php-7.2.6]# swapon /usr/img/swap
swapon: /usr/img/swap: insecure permissions 0644, 0600 suggested.

修改文件夹权限
[root@tencentcvm php-7.2.6]# chmod 0600 /usr/img/swap

修改完成后,在重新执行make

1
2
3
make clean

make && make install

注:安装完成别忘记修改环境变量,将/usr/local/php-fpm/sbin/usr/local/php-fpm/bin 加入环境变量。

这两个目录下分别有这些命令:

1
2
3
4
5
6
7
vi .bash_profile

//加入以下变量,变量之间用英文冒号隔开
/usr/local/php-fpm/bin:/usr/local/php-fpm/sbin

[root@steve ~]# source !$
source .bash_profile

第五步:修改 php配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//查看php配置信息
php -i | head

//移动php.ini文件
[root@steve php-7.2.6]# mv php.ini-production /usr/local/php-fpm/etc/php.ini

//进入配置文件
cd /usr/local/php-fpm/etc

//重命名配置文件
cp php-fpm.conf.default ./php-fpm.conf

//修改配置文件
vi 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

//检查语法错误
php-fpm -t

注意:这里有一个提示:

之所以出现这一行,是因为下面红框中的内容,即include=/usr/local/php-fpm/etc/php-fpm.d/*.conf。 lnmp环境支持虚拟主机,也就是同一台服务器上运行多个网站,每个网站的配置信息,联通php的配置文件都可以分开写,/usr/local/php-fpm/etc/php-fpm.d/目录下就是关于php-fpm的配置文件。

第六步:设置开机启动

1
2
3
4
5
6
7
8
9
10
11
//复制启动脚本
cp /usr/local/src/php-7.2.6/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm

//更改权限
chmod 755 /etc/init.d/php-fpm

//启动服务
service php-fpm start

//开机启动
chkconfig php-fpm on

补充:mariaDB安装

mariaDB跟mysql一样,但是是开源的,可以用来替代mysql。

centos7本身自带了mariaDB5.5版,我们需要先把这个卸载掉,之后再安装最新的MariaDB10.2版。

实现步骤:

第一步:备份数据库

1
cp -a /var/lib/mysql/ /var/lib/mysql.bak

第二步:添加MariaDB存储库

按照mariaDB官方给的方法,修改yum配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//升级yum
yum update

//编辑yum源
vim /etc/yum.repos.d/MariaDB10.repo

//加入以下内容:
# MariaDB 10.2 CentOS repository list - created 2018-05-15 06:14 UTC
# http://downloads.mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.2/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

//先清除之前到缓存
yum clean all

//生成缓存
yum makecache

第三步:删除系统自带的MariaDB 5.5

1
yum remove mariadb-server mariadb mariadb-libs

第四步:安装MariaDB 10

1
yum install -y MariaDB-server MariaDB-client

注:mariaDB有170多M,但是是从国外的服务器下载,所以超级慢,此处可以休息休息。

第五步:启动服务

1
2
3
4
5
6
7
8
//启动服务
systemctl start mariadb

//设置开机启动
systemctl enable mariadb

//检查服务状态
systemctl status mariadb

第六步:初始化密码设定

1
mysql_secure_installation

根据提示,设置以下内容:

  • 设置root密码

  • 是否禁止远程 root访问

  • 是否禁止 test数据库的访问

  • 是否禁用匿名用户

  • 是否重新加载privilleges-table信息

第七步:创建用户以及设置权限

1
2
//数据库登陆
mysql -u[用户名,默认是root] -p[密码,输入刚刚初始化设定的密码]

第八步:测试是否启动

1
2
3
4
5
6
7
8
//检测进程是否启动
[root@steve ~]# ps -aux | grep mysqld
root 5460 0.0 0.0 112704 976 pts/1 R+ 13:28 0:00 grep --color=auto mysqld
mysql 30064 0.0 4.1 1307692 78408 ? Ssl 11:27 0:02 /usr/sbin/mysqld

//查看端口情况
[root@steve ~]# netstat -lnp | grep 3306
tcp6 0 0 :::3306 :::* LISTEN 30064/mysqld

至此,安装部分暂告一段落,下面是配置部分


lnmp基础配置

nginx 配置

配置文件简介

路径 类型 作用
/etc/nginx/conf.d/default.conf 配置文件 nginx主配置文件
/etc/logrotate.d/nginx 配置文件 用于logrotate服务的日志切割
/etc/nginx/nginx.conf
/etc/nginx/fastcgi_params
/etc/nginx/uwsgi_params
/etc/nginx/scgi_params
配置文件 cgi配置相关、fastcgi配置
/etc/nginx/koi-utf
/etc/nginx/win-utf
/etc/nginx/koi-win
配置文件 编码转换映射转化文件
/etc/nginx/mime.types 配置文件 设置http协议的Content-Type与扩展名对应关系 ,处理一些识别不了的扩展名的时候需要用到
/usr/lib/systemd/system/nginx.service
/usr/lib/systemd/system/nginx-debug.service
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
配置文件 用于配置出系统守护进程管理器管理方式
/usr/sbin/nginx
/usr/sbin/nginx-debug
命令 nginx服务终端命令
/usr/share/doc/nginx-1.12.2/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
文件、目录 nginx的手册和帮助文件
/var/cache/nginx/ 目录 nginx的缓存目录
/var/log/nginx/ 目录 nginx的日志目录

nginx.conf 为主配置文件;

inlcude是一个指令,当一个服务器上有多个网站共享时,通过设置include可以很方便的对虚拟主机站点进行管理。

Standard name Description
nginx.conf 主配置文件
fastcgi.conf FastCGI相关配置
proxy.conf 代理相关配置
sites.conf 虚拟主机配置

修改配置文件后需要重启nginx

1
2
3
4
5
//重启nginx
systemctl restart nginx.service

//重新记载配置文件
systemctl reload nginx.service

nginx 的基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
vi /usr/local/nginx/conf/nginx.conf

//加入以下内容
user nginx nginx;
worker_processes 2;
error_log /usr/local/nginx/logs/nginx_error.log crit;
pid /usr/local/nginx/logs/nginx.pid;
worker_rlimit_nofile 65535;

events {
worker_connections 1024;
}

http {
include 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"';
server_names_hash_bucket_size 3526;
server_names_hash_max_size 4096;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 8m;
server_tokens off;
client_body_buffer_size 512k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
fastcgi_intercept_errors on;
gzip off;
gzip_min_length 1k;
gzip_buffers 32 4k;
gzip_http_version 1.0;
gzip_comp_level 5;
gzip_types text/css text/xml application/javascript application/atom+xml application/rss+xml text/plain application/json;
gzip_vary on;

server
{
listen 80;
server_name localhost;
index index.html index.htm index.php;
root /usr/local/nginx/html;
#charset koi8-r;

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;
}
}
}

检查语法并重新加载服务

1
2
3
4
5
6
7
//语法检查
[root@tencentcvm ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

//重新加载服务
[root@tencentcvm ~]# nginx -s reload

配置虚拟主机

同一台服务器,可以设置多个网站,每个网站采用单独的配置文件;

  • 第一步:编辑配置文件
1
2
3
4
vi /usr/local/nginx/conf/nginx.conf

//在最后一个大括号之前加一行
include vhost/*.conf;
  • 第二步:新建虚拟主机配置文件夹
1
2
3
4
5
//新建虚拟主机文件夹
//该目录下所有配置文件均会被加载
mkdir -p /usr/local/nginx/conf/vhost

cd /usr/local/nginx/conf/vhost
  • 第三步:配置虚拟主机
1
2
3
4
5
6
7
8
9
10
11
12
vi default.conf

//加入如下配置
server
{
listen 80 default_server; //default_server 表示默认虚拟主机
server_name steve.discuz.com;
index index.html index.htm index.php;
root /data/ngix/default;
}

//保存退出
  • 第四步:创建测试文件
1
2
3
4
5
6
7
8
//创建项目目录
mkdir -p /data/nginx/default/

//创建索引页
touch index.html

//添加内容到测试页面
echo 'default_server' > /data/nginx/default/index.html
  • 第五步:重新加载服务
1
2
3
4
5
//检查语法错误
nginx -t

//重新记载服务
nginx -s reload
  • 第六步:测试效果
1
2
//测试
curl -x172.16.155.128:80 steve-discuz.com

TroubleShooting:拒绝访问

解决思路:

  • 首先,检查了防火设置,firewalld已关闭,iptables已安装启动,并已开放80、3306端口;

  • 其次,selinux已关闭,重启虚拟机问题依旧;

  • 再次,检查虚拟机配置文件,指定监听80端口;

  • 最后,突然想到会不会是网络的问题,surge改为直连模式 direct mode,之后开启ihost,问题解决。

如下所示:

1
2
steve:~ steveyuan$ curl -x 172.16.155.128:80 steve-discuz.com/index.html
default_server

再测一个并不存在的域名,如下图所示,依然返回默认虚拟主机的页面内容,说明虚拟主机配置成功。

用户认证

  • 第一步:创建新的虚拟主机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cd /usr/local/nginx/conf/vhost

vi test.com.conf

//添加以下配置
server
{
listen 80;
server_name steve-test.com;
index index.html index.htm index.php;
root /data/ngix/test.com;

location /
{
auth_basic 'Auth';
auth_basic_user_file /usr/local/nginx/conf/htpasswd;
}
}
  • 第二步:创建项目目录
1
2
3
4
5
6
7
8
9
10
11
//创建项目文件夹
mkdir -p /data/nginx/test.com

//创建index.html
touch index.html

//安装httpd
yum install -y httpd

//生成用户密码文件
htpasswd -c /usr/local/nginx/conf/htpasswd steve
  • 第三步:重新加载服务
1
2
3
4
5
//语法检查
nginx -t

//重新加载服务
nginx -s reload
  • 第四步:校验成果
1
echo 'test' > /data/nginx/test.com/index.html
  • 如下图所示:用户认证已配置成功

域名重定向

前提准备:

  • 清空虚拟主机配置文件
1
> /usr/local/nginx/conf/vhost/test.com.conf
  • 第一步:修改配置
1
2
3
4
5
6
7
8
9
10
11
12
13
vi test.com.conf

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; //permanent为永久重定向,相当于httpd中的R=301;还有一个常用选项叫做redirect,相当于httpd 的 R=301;
}
}
  • 第二步:重新加载服务
1
2
3
4
5
//检查语法
nginx -t

//重新加载服务
nginx -s reload
  • 第三步:校验结果
1
curl -x 172.16.155.128:80 test1.com

如下图所示,域名重定向成功

拓展知识:rewrtie的四种flag

上面例子当中的重定向也是通过rewrite模块实现的,这里补充一些rewrite模块的知识。

对于rewrtie有四种不同的flag,分别是redirect、permanent、break和last,具体如下:

flag 说明
redirect 临时跳转
permanent 永久跳转,一般是为了对搜索引擎友好
last 将rewrite后的地址重新在server标签执行
break 将rewrite后地址重新在当前的location标签执行

静态文件不记录日志和过期时间

  • 第一步:修改虚拟主机配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
vim /usr/local/nginx/conf/vhost/test.com.conf

//增加如下内容:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ //匹配脱义静态文件
{
expires 7d; //配置过期时间
access_log off;
}
location ~ .*\.(js|css)$ //匹配js,css文件
{
expires 12h;
access_log off;
}

如下图所示:

  • 第二步:重新加载nginx服务
1
2
3
nginx -t

nginx -s reload
  • 第三步:测试结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//创建测试文件
cd /data/nginx/test.com

//创建测试文件
[root@stevey test.com]# echo 'js' > /data/nginx/test.com/1.js
[root@stevey test.com]# echo 'jpeg' > /data/nginx/test.com/1.jpeg

//测试访问
steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 test1.com/1.js
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 test1.com/1.jpeg
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

//查看访问日志 (没有js和jpeg的访问记录)
[root@stevey test.com]# cat /tmp/nginx/test.log
172.16.155.1 - - [10/Jun/2018:22:30:21 +0800] "HEAD http://test1.com/123.html HTTP/1.1" 301 0 "-" "curl/7.54.0"
172.16.155.1 - - [10/Jun/2018:22:30:35 +0800] "HEAD http://test1.com/asdasd.html HTTP/1.1" 301 0 "-" "curl/7.54.0"

Nginx防盗链

防盗链的目的在于节约服务器资源,防止揩油行为。

  • 第一步:编辑配置文件

vim /usr/local/nginx/conf/vhost/test.com.conf

1
2
3
4
5
6
7
8
9
10
11
//增加如下配置:

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;
} //如果不是白名单里就返回403
access_log off;
}
  • 第二步:重新加载 nginx 服务
1
2
3
nginx -t

nginx -s reload
  • 第三步:测试效果

注:这里有个问题,为什么定义的是403,返回的是404呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
steve:steveBlog steveyuan$ curl -e "http://www.test.com/1.txt" -x 172.16.155.128:80 -I test.com/1.gif
HTTP/1.1 404 Not Found
Server: nginx
Date: Mon, 11 Jun 2018 05:37:47 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive


steve:steveBlog steveyuan$ curl -e "http://www.test.com/" -x 172.16.155.128:80 -I test.com/1.gif
HTTP/1.1 404 Not Found
Server: nginx
Date: Mon, 11 Jun 2018 05:39:34 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

Nginx访问控制

  • 第一步:编辑配置文件(根据实际情况,白名单或黑名单任选其一)
1
2
3
4
5
6
7
8
9
10
//配置白名单
vi /usr/local/nginx/conf/vhost/test.com.conf

//增加白名单,只允许以下几个ip访问

location /admin/
{
allow 127.0.0.1;
deny all;
}
1
2
3
4
5
6
7
8
9
//配置黑名单
vi /usr/local/nginx/conf/vhost/test.com.conf

//增加黑名单,不允许以下几个ip访问

location /admin/
{
deny 172.16.157.0/24; //禁止一个网段
}

针对user-agent 进行限制

1
2
3
4
5
6
7
8
9
vi /usr/local/nginx/conf/vhost/test.com.conf 

//增加白名单,只允许以下几个ip访问
//这里制定目录,该配置针对全站生效

if ($http_user_agent ~ 'spider|romato')
{
return 403; //等同于deny all
}

注:在配置httpd的时候,需先定义order顺序;在Nginx里并没有这个选项,它就会从上到下逐一去匹配,一旦找到匹配项,就会做deny 处理,返回403错误。

  • 第二步:重新加载 nginx 服务
1
2
3
nginx -t

nginx -s reload
  • 第三步:测试效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//白名单测试(虚拟机本机访问)
[root@stevey admin]# curl -x 127.0.0.1:80 test.com/admin/test.html
123,ok

//白名单测试(宿主机访问,此ip不在白名单上)
steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 -I test.com/admin/test.html
HTTP/1.1 403 Forbidden
Server: nginx
Date: Mon, 11 Jun 2018 06:09:38 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

//黑名单测试
[root@stevey admin]# curl -x 127.0.0.1:80 test.com/admin/test.html
123,ok

//限制user-agent访问的测试
steve:steveBlog steveyuan$ curl -A 'spider' -x 172.16.155.128:80 test.com/admin/test.html
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>

目录访问限制

除了对全站进行配置,还可以对指定的目录进行配置,主要用到location语句,配置语句类似于

1
2
3
4
location ~ [目录]
{
配置规则
}

示例:

目的:upload目录下的.php文件不能访问,但是除了.php的其他后缀文件就能访问。

1
2
3
4
5
6
7
8
vim /usr/local/nginx/conf/vhost/test.com.conf

//增加如下内容:

location ~ .*(upload|image)/.*\.php$ //意思是匹配upload或者image目录下的.php文件
{
deny all;
}
nginx中location的基本语法

语法

命令行格式:

1
2
3
location [=|~|~*|^~] patt {

}

常用符号含义:

  • =开头表示精确匹配;

  • ^~开头表示uri以某个常规字符串开头,不是正则匹配;

  • ~开头表示区分大小写的正则匹配;

  • ~* 开头表示不区分大小写的正则匹配;

  • !~ 区分大小写不匹配;

  • !~*不区分大小写不匹配的正则;

  • /通用匹配,任何请求都会匹配到。

匹配顺序

  • 精确匹配 location = /abc { }

  • 匹配路径的前缀,如果找到停止搜索 location ^~ /abc { }

  • 不区分大小写的正则匹配 location ~* /abc { }

  • 正则匹配 location ~ /abc { }

  • 普通路径前缀匹配 location /abc { }

举例说明:

  • 第一类:精准匹配
1
2
3
4

location = / {
# 只匹配"/".
[ configuration A ]
  • 第二类:一般匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ocation ^~ /images/ {
# 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
[ configuration D ]
}

location /documents/ {
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration C ]
}

location / {
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# 但是正则和最长字符串会优先匹配
[ configuration B ]
}
  • 第三类:正则匹配
1
2
3
4
5
location ~* \.(gif|jpg|jpeg)$ {
# 匹配所有以 gif,jpg或jpeg 结尾的请求
# 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
[ configuration E ]
}

Nginx代理

ipv4时代,公网ip资源稀缺,假设公司有多台服务器,但只有一个ip,就可以通过代理的方式,让没有公网ip的服务器提供web服务。

  • 第一步:修改配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd /usr/local/nginx/conf/vhost

vim proxy.conf

//增加如下内容:

server
{
listen 80;
server_name test.com;

location /
{
proxy_pass http://172.16.155.128/; //指定要代理的域名所在的服务器IP,即Web服务器的地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

注:该配置文件没有设置root文件目录的路径,因为它是代理服务器,不需要访问本地服务器上的任何文件;

  • 第二步:重新加载 nginx 服务
1
2
3
nginx -t

nginx -s reload

Nginx访问日志

跟apache一样,nginx也有访问日志的功能。相比较而言,nginx访问日志的设定还要更简洁明了一些。

日志格式

  • combined log_format

注:combined日志格式,相当于apache的combined日志格式。

1
2
3
log_format  combined   '$remote_addr - $remote_user  [$time_local]  '
' "$request" $status $body_bytes_sent '
' "$http_referer" "$http_user_agent" ';
  • main log_format

注:lof_format的默认值

1
2
3
4
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'"$status" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$gzip_ratio" $request_time $bytes_sent $request_length';
  • proxy log_format

注:nginx位于负载均衡器,squid,nginx反向代理之后,web服务器无法直接获取到客户端真实的IP地址了。 $remote_addr获取反向代理的IP地址。反向代理服务器在转发请求的http头信息中,可以增加X-Forwarded-For信息,用来记录 客户端IP地址和客户端请求的服务器地址。

1
2
3
log_format  porxy   '$http_x_forwarded_for - $remote_user  [$time_local]  '
' "$request" $status $body_bytes_sent '
' "$http_referer" "$http_user_agent" ';

常用的配置参数

参数 注释
$remote_addr 客户端IP地址
$http_x_forwarded_for 代理服务器IP
$remote_user 客户端用户名称
$request 请求的URL和HTTP协议
$status 请求返回的状态码,例如:200、301、404等
$body_bytes_sent 发送给客户端的字节数,不包括响应头的大小;
$bytes_sent 发送给客户端的总字节数。
$connection 连接的序列号。
$connection_requests 当前通过一个连接获得的请求数量。
$msec 日志写入时间,单位为秒。
$pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
$http_referer 记录从哪个页面链接访问过来的,可以根据该参数进行防盗链设置
$http_user_agent 客户端浏览器相关信息
$request_length 请求的长度,包括请求行,请求头和请求正)。
$request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601 ISO8601标准格式下的本地时间。
$time_local 通用日志格式下的本地时间。
$sent_http_content_range 这是一个传递到客户端的头,这类头的前缀为”sent_http_” 。
$upstream_http_ 这是有upstream模块产生了日志,因此它的前缀将会是这个前缀。

日志相关命令

access_log

access_log 设定日志的路径、格式、buffer大小,是否压缩等。如果不想启用日志则access_log off ;

语法:

1
2
access_log  path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;

示例:

1
access_log logs/access.log combined;

注:该命令分为三个字段:

  • 关键字:其中关键字access_log不能更改;

  • 日志文件:可以指定存放日志的路径;

  • 格式标签:给日志文件套用指定的日志格式;

log_format

设置日志格式

语法:

1
log_format name [escape=default|json] string ...;

示例:

1
2
3
log_format  combined   '$remote_addr - $remote_user  [$time_local]  '
' "$request" $status $body_bytes_sent '
' "$http_referer" "$http_user_agent" ';

注:该命令分为三个部分:

  • 关键字:其中关键字error_log不能改变;

  • 格式标签:格式标签是给一套日志格式设置一个独特的名字;

  • 日志格式:日志设置格式具体包含的元素;

open_log_file_cache

该命令为频繁使用的日志文件描述符所在的路径变量设置缓存。

语法:

1
open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time] | off

指令选项:

  • max - 缓存中存储的最大文件描述符数;

  • inactive - 设置缓存中在某个时间段内没有使用的文件描述符将被移除,默认为10秒;

  • min_uses - 在一定时间内(inactive指定),一个文件描述符最少使用多少次后被放入缓存,默认为1;

  • valid - 设置检查同名文件存在的时间,默认是60秒;

  • off - 关闭 cache;

示例

1
open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;

nginx 日志配置:以test.com为例

  • 第一步:编辑配置文件
1
2
3
4
vi /usr/local/nginx/conf/vhost/test.com.conf

//加入一行配置
access_log /tmp/nginx/test.log combined
  • 第二步:新建日志目录
1
mkdir -p /tmp/nginx
  • 第三步:重新加载服务
1
2
3
nginx -t

nginx -s reload
  • 第四步:测试成果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//测试访问
steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 test1.com/123.html -I
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 10 Jun 2018 14:30:21 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://test.com/123.html

steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 test1.com/asdasd.html -I
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 10 Jun 2018 14:30:35 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://test.com/asdasd.html

//查看日志
[root@stevey test.com]# cat /tmp/nginx/test.log
172.16.155.1 - - [10/Jun/2018:22:30:21 +0800] "HEAD http://test1.com/123.html HTTP/1.1" 301 0 "-" "curl/7.54.0"
172.16.155.1 - - [10/Jun/2018:22:30:35 +0800] "HEAD http://test1.com/asdasd.html HTTP/1.1" 301 0 "-" "curl/7.54.0"

Nginx日志切割

  • 第一步:撰写脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
vi /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` //跟Nginx的-s重新加载配置文件一样
  • 第二步:修改脚本权限
1
chomod u+x /usr/local/sbin/nginx_log_rotate.sh
  • 第三步:添加系统任务
1
2
3
4
5
crontab -e //添加任务计划

//增加如下内容:

0 0 * * * /bin/bash /usr/local/sbin/nginx_log_rotate.sh

Nginx的负载均衡

负载均衡,是很多大型网站必备的服务器资源分配策略,从字面上的意思来理解,就是N台服务器分担负载,合理使用资源,获得更好的用户体验。

比如,如果你在运营一个类似京东、淘宝、12306这样的大型网站,假设只有一台服务器,当用户访问量过大,服务器处理不了时就会宕机,用户访问就会很慢甚至卡死。为了避免这种情况,很多大型网站都有很多台服务器,同时来提供服务。

当然,这些服务不可能是完全一致的,有的配置高,有的配置稍微差一点;如果做到既能够充分利用服务器的资源,不浪费;又不会让服务器压力过大呢?这就是均衡负载做的工作。

nginx均衡负载的实现方法

Nginx负载均衡是通过upstream模块来实现的,内置实现了三种负载策略:

方法一:轮循(默认)

Nginx根据请求次数,将每个请求均匀分配到每台服务器

示例:

同一个应用有3个实例分别运行在srv1-srv3。当没有特别指定负载均衡方法时, 默认为round-robin/轮询。所有请求被代理到服务器集群myapp1, 然后nginx实现HTTP负载均衡来分发请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http {
upstream myapp1 {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}

server {
listen 80;

location / {
proxy_pass http://myapp1;
}
}
}
方法二:最少连接

将请求分配给连接数最少的服务器。Nginx会统计哪些服务器的连接数最少。

示例:

1
2
3
4
5
6
upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
方法三:IP Hash

利用URI HASH绑定处理请求的服务器。具体而言,第一次请求时,根据该客户端的IP算出一个HASH值,将请求分配到集群中的某一台服务器上。后面该客户端的所有请求,都将通过HASH算法,找到之前处理这台客户端请求的服务器,然后将请求交给它来处理。

1
2
3
4
5
6
upstream myapp1 {
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}

基于权重的负载均衡

上述的三种默认策略,并没有制定服务器的权重,这意味着所有列出的服务器被认为是完全平等的。但实际上并非如此,有的机器使用时间久,配置低;有的则是新机器,内存大、配置过,两者的处理能力显然是不同的,所以可以通过使用服务器权重来影响nginx的负载均衡算法。

举例来说:

下列配置中,配置最好的服务器101被赋予了最高权重,被分配的任务最多;其次是100;最后是102;

1
2
3
4
5
upstream tomcats {
server 192.168.0.100:8080 weight=2; // 每6次访问有2次分配到该服务器
server 192.168.0.101:8080 weight=3; // 这台机器配置最好,每6次访问有3次分配到该服务器
server 192.168.0.102:8080 weight=1; // 每6次访问有1次分配到该服务器
}

配置中的参见参数

参数 说明
max_fails 默认为1。某台Server允许请求失败的次数,超过最大次数后,在fail_timeout时间内,新的请求将不会分配给这台机器。如果设置为0,Nginx会将这台Server置为永久无效状态
fail_timeout 默认为10秒,某台Server请求失败次数达到max_fails后,在fail_timeout期间内,nginx会认为这台Server暂时不可用,不会将请求分配给它
backup 备份机,所有服务器挂了之后才会生效
down 标识某一台server不可用
max_conns 限制分配给某台Server处理的最大连接数量,超过这个数量,将不会分配新的连接给它。默认为0,表示不限制
resolve 将server指令配置的域名,指定域名解析服务器。需要在http模块下配置resolver指令,指定域名解析服务

nginx配置ssl

基础从http 到 https

http的工作原理

HTTP协议,是互联网上应用最广泛的一种网络传输协议,默认使用80端口,主要用来在计算机网络之间进行通信。

HTTP请求/响应的步骤:

  1. 客户端连接到Web服务器,默认端口为80,建立一个TCP套接字连接;

  2. 通过TCP套接字,发送HTTP请求;

  3. 服务器接受请求并返回HTTP响应;

  4. Web服务器主动关闭TCP套接字,释放TCP连接;客户端被动关闭TCP套接字,释放TCP连接;

  5. 客户端浏览器解析HTML内容;

HTTP协议的缺点:

由于HTTP协议采用明文传输,所以天生有两大弊端:

  • 隐私泄露:因为全都是明文传输;

  • 安全隐患:页面劫持、中间人攻击;

为了克服上述弊端,HTTPS应运而生。

HTTPS的工作原理

  • 客户使用HTTPS的URL访问Web服务器,要求与Web服务器建立SSL连接;  
  • Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端;  
  • 客户端的浏览器与Web服务器开始协商SSL/TLS连接的安全等级,也就是信息加密的等级;

  • 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站;

  • Web服务器利用自己的私钥解密出会话密钥;

  • Web服务器利用会话密钥加密与客户端之间的通信;

这里涉及到一些加密的概念:

  • 对称加密:

形象的解释,就是加密和解密用的是同一把钥匙,采用相同的秘钥进行加密和解密。

  • 非对称加密

与对称加密算法不同的是,非对称加密算法使用的加密密钥和解密密钥是不同的。

  • RSA加密

RSA公钥密码算法是公钥密码算法中的一种,RSA中的加密和解密都可以使用公钥或者私钥,但是用公钥加密的密文只能使用私钥解密,用私钥加密的密文智能使用公钥解密。

SSL证书

上述过程看起来已经比较安全了,但还是有可能出现中间人攻击。举例来说,如有有人伪造了服务器的公钥与客户端进行握手,那后面的过程进行看似很“安全”,其实已经失去意义了。

为了进一步提升安全性,就催生了由第三方权威机构颁发的SSL证书。

SSL证书大概是这样的:

操作系统在出厂时会内置这个机构的机构信息和公钥。在实践过程中,A网站得到这张证书后,会在与用户通信的过程中将证书发送给客户端,客户端会检测证书的颁发机构。

如果是受信任的证书机构,应用程序会使用预置的 CA证书的公钥去解密最后的指纹内容和指纹算法,之后与网站发来的证书指纹内容进行比对,如果一致,就可以放心进行下一步的通信过程。

实现步骤:

  • 第0步:安装openssl
1
2
3
4
5
//检测是否安装openssl
rpm -qf `which openssl`

//如没有,执行以下命令安装
yum install -y openssl
  • 第一步:生成秘钥key
1
2
3
4
5
//秘钥放在配置文件夹下
cd /usr/local/nginx/conf/

//生成秘钥
openssl rsa -in server.key -out server.key
  • 第二步:创建服务器证书的申请文件server.csr
1
openssl req -new -key server.key -out server.csr
  • 第三步:创建CA证书
1
penssl req -new -x509 -key server.key -out ca.crt -days 3650
  • 第四步:创建自当前日期起有效期为期十年的服务器证书server.crt
1
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey server.key -CAcreateserial -out server.crt

至此,一共生成5个文件,其中,server.crt和server.key就是你的nginx需要的证书文件.

  • 第五步:配置nginx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//修改nginx配置文件

//将ssl_certificate改为server.crt的路径,将ssl_certificate_key改为server.key的路径.

server {

listen 443;
server_name localhost;
ssl on;
ssl_certificate /root/Lee/keys/server.crt;#配置证书位置
ssl_certificate_key /root/Lee/keys/server.key;#配置秘钥位置
#ssl_client_certificate ca.crt;#双向认证
#ssl_verify_client on; #双向认证

ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
  • 第六步:重新加载配置
1
2
3
nginx -t

nginx -s reload

Nginx解析php

在LAMP中,PHP是作为httpd的一个模块出现的;而在LNMP中,PHP是以一个服务(php-fpm)的形式存在的,首先要启动php-fpm服务,然后Nginx再和php-fpm通信。也就是说,处理PHP脚本解析的工作是由php-fpm处理完成后把结果传递给Nginx,Nginx再把结果返回给用户。

什么是php-fpm?

php进程管理的基本概念:

  • CGI:是 Web Server 与 Web Application 之间数据交换的一种协议;

  • FastCGI:同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化。同样,SCGI 协议与 FastCGI 类似;

  • PHP-CGI:是 PHP (Web Application)对 Web Server 提供的 CGI 协议的接口程序;

  • PHP-FPM:是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能一些任务管理;

php-cgiphp-fpm的关系

PHP-CGI就是PHP实现的自带的FastCGI管理器,但是它本身不给力,有明显的不足:

  • 只能解析请求,返回结果,不会进程管理;

  • php-cgi变更php.ini配置后,需重启php-cgi才能让新的php-ini生效,不可以平滑重启;

  • 直接杀死php-cgi进程,php就不能运行了;

基于上述因素,就出现了一些第三方补充解决方案,比如PHP-FPM,它的优点包括:

  • 用于调度管理PHP解析器php-cgi的管理程序;

  • PHP-FPM通过生成新的子进程可以实现php.ini修改后的平滑重启;

如上图所示,当nginx收到 index.php 这个请求后,会启动对应的 CGI 程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP Web访问流程。

nginx支持php

  • 第一步:修改配置文件
1
2
3
4
5
6
7
8
9
10
11
vim /usr/local/nginx/conf/vhost/test.com.conf

//增加配置如下:

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;
}

说明:

  • fastcgi_pas用来指定php-fpm的地址,如果php-fpm监听的是127.0.0.1:9000,那么这里也要改成相同地地址,否则会报502错误。

  • factcgi_parm SCRIPT_FILENAME后面的路径为该站点根目录,与之前root定义的路径一致,否则会报404错误。

502错误常见原因:

  • 一是配置错误:nginx找不到php-fpm了,所以报错;

正确做法:astcgi_pass后面可以是socket或者是ip:port

1
2
3
fastcgi_pass unix:/tmp/php-fcgi.sock; 
//或者
fastcgi_pass 127.0.0.1:9000;
  • 二是资源耗尽:nmp架构在处理php时,nginx直接调取后端的php-fpm服务,如果nginx的请求量偏高,又没有给php-fpm配置足够的子进程,那么一旦资源耗尽,就会出现502错误,

正确做法:调整php-fpm.conf中的pm.max_children数值,一般4G内存机器可以设置为150,8G为300以此类推;

  • 第二步:重新加载 nginx 服务
1
2
3
nginx -t

nginx -s reload
  • 第三步:准备测试文件
1
2
3
4
5
6
7
8
9
10
//进入文件目录
cd /data/nginx/test.com

//建立测试php网页
touch 1.php

//编辑测试网页,加入以下内容
<?php
echo 'this is a php test';
?>
  • 第四步:测试结果
1
2
steve:steveBlog steveyuan$ curl -x 172.16.155.128:80 test.com/1.php
this is a php

php-fpm进程管理

命令行格式:

1
nginx -s [signal]

其中,signal常用选项如下:

  • quit - 处理完当前请求再关闭;

  • reload - 重新载入配置文件;

  • reopen - 重新打开日志文件;

  • stop - 立即关闭;

php-fpm的pool

前面提到过,php-fpm的一个重要功能,就是可以管理进程,这里涉及到一个pool的概念,nginx启动服务后,会产生1个master进程+N个worker进程,共同构成一个进程池(pool),其中

  • master进程主要负责读取配置文件,并控制管理workder进程;

  • worker进程具体负责处理请求;

先看目前的php-fpm 的pool,执行以下命令:

1
ps -aux | grep php-fpm

配置文件解读

php-fpm的配置文件在 /usr/local/php-fpm/etc/php-fpm.conf,查看该文件

1
cat /usr/local/php-fpm/etc/php-fpm.conf

如上图所示:

[global] 全局配置
  • pid 指定pid路径;

  • error_log 指定php-fpm的错误日志;

[www] 当前的pool设定
  • listen = /tmp/php-fcgi.sock 以sock的方式监听

  • user = php-fpm 指定运行的用户

  • group = php-fpm 指定运行的组

  • pm = dynamic //定义php-fpm的子进程启动模式,dynamic为动态进程管理,一开始只启动少量的子进程,根据实际需求,动态地增加或者减少子进程,最多不会超过pm.max_children定义的数值。另外一种模式是static,这种模式下子进程数量由pm.max_children决定,一次性启动这么多,不会减少也不会增加;

  • pm.max_children = 50 //最大子进程数,ps -aux可以查看;

  • pm.start_servers = 20 //针对dynamic模式,它定义php-fpm服务在启动服务时产生的子进程服务时产生的子进程数量;

  • pm.min_spare_servers = 5 //针对dynamic模式,定义在空闲时段,子进程数的最少数量,如果达到这个数值时,php-fpm服务会自动派生新的子进程;

  • pm.max_spare_servers = 35 //针对dynamic模式,定义在空闲时段,子进程数的最大值,如果高于这个数值就开始清理空闲的子进程;

  • pm.max_requests = 500 //针对dynamic模式,定义一个子进程最多处理的请求数,也就是说在一个php-fpm的子进程最多可以处理这么多请求,当达到这个数值时,它会自动退出;

此外,在配置文件的末尾,还有一行很关键的配置;

与nginx虚拟主机的配置类似,当同一台服务器上多个网站是,我们可以把;include=/usr/local/php-fpm/etc/php-fpm.d/*.conf 注释分号去掉,这样就可以在/usr/local/php-fpm/etc/php-fpm.d 下,为每个虚拟主机配置不同的pool,各个网站之间的pool进程池彼此独立,互不影响。

设置多个pool
方法一:在/usr/local/php-fpm/etc/php-fpm里面增加pool
  • 第一步:修改配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@hanfeng etc]# vi /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

[steve.com]
listen = /tmp/steve.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
  • 第二步:重新加载 nginx 服务
1
2
3
nginx -t

nginx -s reload
  • 第三步:检测效果
1
ps -aux | grep php-fpm
  • 第四步:在nginx 中启用pool

默认主机的pool设定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//进入nigix虚拟主机配置文件夹
[root@stevey etc]# cd /usr/local/nginx/conf/vhost/
[root@stevey vhost]# ls
default.conf test.com.conf

//配置test.com.conf
vi test.com.conf

//相关配置
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fcgi.sock; //这个就是www的默认pool
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/nginx/test.com$fastcgi_script_name;
}

新建steve.com的pool设定(假设已经有新的steve.com虚拟主机)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@hanfeng vhost]# vim steve.com.conf

server
{
listen 80 default_server;
server_name steve.com;
index index.html index.htm index.php;
root /data/nginx/steve.com;
}
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/steve.com.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/nginx/steve.com$fastcgi_script_name;
}
方法二:跟nginx虚拟主机类似,php-fpmye也支持把配置文件拆分出来。
  • 第一步:修改php-fpm.conf
1
2
3
4
5
6
7
vi php-fpm.conf

//主文件只保留global设定
[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 //这行很关键,修改后各个虚拟主机的pool设定会保存在 `etc/php-fpm.d/` 目录下。
  • 第二步:创新配置目录
1
2
3
4
5
6
7
//创建/php-fpm.d/的目录
mkdir -p etc/php-fpm.d
进入配置目录
cd etc/php-fpm.d

//新建www.conf,并修改设定
vim www.conf
  • 第三步:创建配置文件

修改www的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
[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

新建steve.com.conf,并修改相关设定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vim steve.com.conf

[steve.com]
listen = /tmp/steve.com.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
  • 第四步:重新加载服务
1
2
3
4
//检查语法
/usr/local/php-fpm/sbin/php-fpm -t
重启服务
/etc/init.d/php-fpm restart
  • 第五步:校验结果
1
ps -aux | grep php-fpm

php-fpm慢执行日志slow log

慢执行日志是php-fpm提供的一个很有用的功能,通过查询和分心慢执行日志,方便我们有针对性滴进行优化。

开启slow log步骤:

第一步:编辑php-fpm配置文件

1
2
3
4
5
6
7
//PHP 5.3.3 之前设置如下:
<value name="request_slowlog_timeout">5s</value>
<value name="slowlog">logs/php-fpm-slowlog.log</value>

//PHP 5.3.3 之后设置以下如下:
request_slowlog_timeout = 5s
slowlog = /usr/local/php/log/php-fpm-slowlog.log

注:

  • request_slowlog_timeout 是脚本超过多长时间 就可以记录到日志文件;

  • slowlog 是日志文件的路径;

第二步:重启php-fpm服务

1
2
3
4
//检查语法
/usr/local/php-fpm/sbin/php-fpm -t
重启服务
/etc/init.d/php-fpm restart

第三步:查看slow log

1
2
3
4
5
6
cat /usr/local/php/log/php-fpm-slowlog.log

[19-Dec-2013 16:54:49] [pool www] pid 18575
script_filename = /home/web/htdocs/sandbox_canglong/test/tt.php
[0x0000000003a00dc8] curl_exec() /home/web/htdocs/sandbox_canglong/test/tt.php:2
[0x0000000003a00cd0] exfilter_curl_get() /home/web/htdocs/sandbox_canglong/test/tt.php:6

说明:

  • script_filename 是入口文件;

  • curl_exec() : 说明是执行这个方法的时候超过执行时间的;

  • exfilter_curl_get() :说明调用curl_exec()的方法 ;

  • 每行冒号后面的数字是行号;

注:开启slow log后,在错误日志文件中也有相关记录

open_basedir

open_basedir 是php的一个安全设定,就是就访问权限限定在某个文件夹;就算该网站被黑,也只能在特定的文件夹内操作,而不会危及整个服务器的安全。

可以配置open_basedir的地方一共有以下三处,修改方法如下:

  • 方法一:编辑php-fpm.conf
1
php_admin_value[open_basedir]=/home/wwwroot/:/proc/:/tmp/
  • 方法二:编辑nginx fastcgi_param
1
2
# set php open_basedir 
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";
  • 方法三:编辑php.ini
1
2
3
4
[HOST=www.iamle.com]
open_basedir=/home/wwwroot/www.iamle.com/:/proc/:/tmp/
[PATH=/home/wwwroot/www.iamle.com/]
open_basedir=/home/wwwroot/www.iamle.com/:/proc/:/tmp/
open_basedir 安全设置建议

三管齐下:

  1. 先设置fpm-php中pool池中的总open_basedir;

  2. 再对nginx中单个server 通过 fastcgi_param PHP_ADMIN_VALUE 设置;

  3. 最后对php.ini设置 [HOST=XXX] [PATH=XXX]

1
2
3
4
5
6
7
8
9
10
11
12
13
//第一步:在php-fpm.conf对应的pool池中行尾配置
php_admin_value[open_basedir]=/home/wwwroot/:/proc/:/tmp/

//第二步:在nginx fastcgi fastcgi_param配置
#这里用$document_root是一种取巧的方法,也可以设置绝对路径
# set php open_basedir
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";

//第三步:在php.ini行尾配置
[HOST=www.iamle.com]
open_basedir=/home/wwwroot/www.iamle.com/:/proc/:/tmp/
[PATH=/home/wwwroot/www.iamle.com/]
open_basedir=/home/wwwroot/www.iamle.com/:/proc/:/tmp/
-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!