一、WEB服务器

WEB服务器也称为WWW服务器、HTTP服务器,其主要功能是提供网上信息浏览服务。Unix和Linux平台下常用的服务器有Apache、Nginx、Lighttpd、Tomcat、IBM WebSphere等,其中应用最广泛的是Apache。而Windows平台下最常用的服务器是微软公司的IIS。

1.1 常见的WEB应用服务器

  1. IIS

IIS是Internet Information Server(信息服务)的缩写,也是微软主推的web服务器产品,适用于windows系统,很多著名网站都采用IIS搭建,ASP、.net开发的程序一般也只能在IIS上运行。
​
IIS提供了一个图形界面的管理工具,称为 Internet服务管理器,可用于监视配置和控制Internet服务,其中包括Web服务器、FTP服务器、NNTP服务器和SMTP服务器,分别用于网页浏览、文件传输、新闻服务和邮件发送等方面,IIS的使用让网络(包括互联网和局域网)上的信息发布变得非常简单。同时,IIS还提供ISAPI(Intranet Server API)作为扩展Web服务器功能的编程接口,并提供一个Internet数据库连接器,可以实现对数据库的查询和更新。

  1. Apache

Apache是目前世界上最流行的Web服务器之一,支持跨平台应用,可以运行在几乎所有的Unix、windows、linux系统平台上,尤其对linux的支持相当完美。
​
Apache是开源免费的,有很多开发者都参与了设计和改进,推动了产品的持续完善。Apache的特点是简单、高速、性能稳定,可作代理服务器使用。到目前为止,Apache仍然是世界上用的最多的Web服务器,其成功之处主要在于源码开放、强大的社区支持、跨平台应用以及可移植性等方面。不过,Apache是以进程为基础的结构,要比线程消耗更多的系统开支,不太适合于多处理器环境,还有就是并发不强,流量大了就容易出现500错误。

  1. Nginx

Nginx是一种高性能的HTTP和反向代理web服务器,支持高并发和负载均衡,以稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。
​
Nginx可以在大多数Unix/Linux上编译运行,并有Windows移植版。Nginx的安装简单、配置文件简洁(支持perl语法),同时Bug非常少,几乎可以做到7*24不间断运行,支持在不间断服务的情况下进行软件版本升级。在连接高并发的情况下,Nginx是Apache服务不错的替代品。同时Nginx的模块也非常丰富,能够满足不同的需求,适合做静态使用。另外Nginx还提供了IMAP/POP3/SMTP服务,是一个非常优秀的邮件代理服务器。

  1. Tomcat

Tomcat是一个开放源代码、运行servlet和JSP Web应用软件、并基于Java的Web应用软件容器。由于技术先进、性能稳定,而且免费,深受Java 爱好者欢迎,同时,也得到了部分软件开发商认可,成为目前比较流行的Web应用服务器。
​
Tomcat 属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。和IIS等Web服务器一样,tomcat也有处理HTML页面的功能,另外它还是一个Servlet和JSP容器(默认模式下为独立的Servlet容器)。不过,Tomcat处理静态HTML的能力不如Apache服务器,目前Tomcat最新版本为9.0。

  1. 其他

Kangle是一款跨平台、功能强大、易操作的高性能web服务器和反向代理服务器,也是一款专为做虚拟主机研发的web服务器,实现虚拟主机独立进程、独立身份运行与用户安全隔离,支持php、asp、java、ruby等多种动态开发语言。
​
WebSphere是IBM 的软件平台,包含了编写、运行和监视全天候的工业强度的随需应变Web应用程序和跨平台、跨产品解决方案所需要的整个中间件基础设施,如服务器、服务和工具。WebSphere 是一个模块化的平台,基于业界支持的开放标准,并可在 Intel、Linux 等多平台运行。
​
WebLogic是Oracle出品的一款多功能、基于标准的web应用服务器,是一款基于JAVAEE架构的中间件,用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用,将Java的动态功能和安全标准引入大型网络应用的开发、集成、部署和管理之中,为企业构建自己的应用提供了坚实的基础。

1.2 WEB服务器的工作原理

这张图,将一次Web服务的工作流程过一遍,我们假设以浏览器作为客户端

(1) 用户做出了一个操作,可以是填写网址敲回车,可以是点击链接,可以是点击按键等,接着浏览器获取了该事件。
​
(2) 浏览器与对端服务程序建立TCP连接。
​
(3) 浏览器将用户的事件按照HTTP协议格式打包成一个数据包,其实质就是在待发送缓冲区中的一段有着HTTP协议格式的字节流。
​
(4) 浏览器确认对端可写,并将该数据包推入Internet,该包经过网络最终递交到对端服务程序。
​
(5) 服务端程序拿到该数据包后,同样以HTTP协议格式解包,然后解析客户端的意图。
​
(6) 得知客户端意图后,进行分类处理,或是提供某种文件、或是处理数据。
​
(7) 将结果装入缓冲区,或是HTML文件、或是一张图片等。
​
(8) 按照HTTP协议格式将(7)中的数据打包
​
(9) 服务器确认对端可写,并将该数据包推入Internet,该包经过网络最终递交到客户端。
​
(10) 浏览器拿到包后,以HTTP协议格式解包,然后解析数据,假设是HTML文件。
​
(11) 浏览器将HTML文件展示在页面

以上为Web服务器工作基本原理。其实不难发现,这仅仅只是一个简单的网络通信。我们应该深信,作为一个服务器,其根本的工作无非有三个:接收数据,处理数据,发送数据。


二、LAMP架构

2.1 LAMP架构简述

如今,我们每次谈及web网站的架构,都会离不开一个话题就是LAMP架构和LNMP的架构,它使我们搭建网站的基础,我们可以通过各种途径和方式轻松的获取它的各类的资料和文档,使因为他们现在目前正在被广泛的应用,对于它的安装和使用,优化等也非常多的心得和体验,那LAMP架构到底使什么呢?接下来我们就一起来了解一下。

首先解释一下LAMP架构的组成部分是什么?LNMP架构我们后面再继续聊。

LAMP架构是4个基础组件的首字母组合而成的,其中:

L: Linux

A:APACHE

M: Mysql

P: PHP

2.2 各组件作用

平台:Linux

作为LAMP架构的基础,提供用于支撑Web站点的操作系统,能够与其他三个组件提供更好的稳定性,兼容性(AMP组件也支持Windows,UNIX等平台)

前台:Apache(静态页面)

作为LAMP架构的前端,是一款功能强大哦,稳定性好的Web服务器程序,该服务器直接面向用户提供网站访问,发送网页,图片等文件内容。

后台:MySQL(数据库--数据存储/读取)

作为LAMP架构的后端,是一款流行的开源关系数据库系统。在企业网站,业务系统等应用中,各种账户信息,产品信息,客户资料,业务数据库等都可以存储到MySQL数据库,其他程序可以通过SQL语句来查询,更改这些信息。

中间连接:PHP/Perl/Python(动态页面)

作为三种开发动态网页的编程语言,负责解释动态网页文件,负责沟通Web服务器和数据库系统以协同工作,并提供Web应用程序的开发和运行环境。其中PHP是一种被广泛应用的开放源代码的多用途脚本语言,它可以嵌入到HTML中,尤其适合于Web应用开发。

三、LAMP架构部署

3.1 安装APACHE

3.1.1 安装准备的软件包
httpd-2.4.28.tar.gz    #Apache主程序包
​
apr-1.5.2.tar.gz     #Apache依赖包
​
apr-util-1.5.4.tar.gz   #Apache依赖包
​
pcre-8.41.tar.gz     #Apache依赖包
下载地址:
https://dlcdn.apache.org//httpd/httpd-2.4.51.tar.gz
​
 http://archive.apache.org/dist/apr/apr-1.6.2.tar.gz
​
http://archive.apache.org/dist/apr/apr-util-1.6.0.tar.gz
​
https://sourceforge.net/projects/pcre/files/pcre/8.41/pcre-8.41.tar.gz
3.1.2 安装依赖
[root@lamp ~]# yum -y install make gcc gcc-c++ openssl openssl-devel expat-devel 
3.1.3 编译安装依赖包apr
[root@lamp ~]# tar zxvf apr-1.6.2.tar.gz 
[root@lamp ~]# cd apr-1.6.2
[root@lamp apr-1.6.2]# ./configure --prefix=/usr/local/apr
[root@lamp apr-1.6.2]# make && make install

教你一招:如果想加快编译安装的速度,可以在编译的时候加一个-j选项,如果是4个核心就是-j 4,其他类比即可

3.1.4 编译安装依赖包apr-util
[root@lamp ~]#  tar zxvf apr-util-1.6.0.tar.gz
[root@lamp ~]# cd apr-util-1.6.0
[root@lamp apr-util-1.6.0]# ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr/bin/apr-1-config
[root@lamp apr-util-1.6.0]# make -j 8 && make -j 8 install
3.1.5 编译安装依赖包pcre
[root@lamp ~]# tar zxvf pcre-8.41.tar.gz 
[root@lamp ~]# cd pcre-8.41/
[root@lamp pcre-8.41]# ./configure --prefix=/usr/local/pcre
[root@lamp pcre-8.41]# make -j 8 && make -j 8 install

提问:怎么确保编译安装的结果是正确的呢?

3.1.6 编译安装Apache
[root@lamp ~]# tar zxvf httpd-2.4.51.tar.gz -C /usr/local/src/
[root@lamp ~]# cd /usr/local/src/httpd-2.4.51
[root@lamp httpd-2.4.51]# ./configure --prefix=/usr/local/apache --enable-so --enable-rewrite --enable-ssl --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util/ --with-pcre=/usr/local/pcre/
[root@lamp httpd-2.4.51]# make -j 8 && make -j 8 install

注:

--enable-so                      #支持动态加载模块
​
--enable-rewrite                  #支持网站地址重写
​
--enable-ssl                      #支持ssl加密
​
--with-apr=/usr/local/apr          #关联apr
​
--with-apr-util=/usr/local/apr-util   #关联apr-util
​
--with-pcre=/usr/local/pcre         #关联pcre
​
--libdir=/usr/lib64          #关联库文件

3.1.7 查看配置文件
[root@lamp ~]# ls /usr/local/apache/conf/httpd.conf  #网站的配置文件
/usr/local/apache/conf/httpd.conf
​
[root@lamp ~]# ls /usr/local/apache/htdocs/    #网站的根目录文件
index.html 
3.1.8 生成启动脚本
[root@lamp ~]# cp /usr/local/apache/bin/apachectl /etc/init.d/
[root@lamp ~]# chmod +x /etc/init.d/apachectl
写个apache系统服务脚本, 以754的权限保存此文件
vim /usr/lib/systemd/system/apache.service
[Unit]
Description=apache
After=network.target
[Service]
Type=forking
ExecStart=/etc/init.d/apachectl start
ExecReload=/etc/init.d/apachectl restart
ExecStop=/etc/init.d/apachectl stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
3.1.9 启动服务
[root@lamp ~]# systemctl start apache
[root@lamp ~]# systemctl enable apache
或者
[root@lamp ~]# /etc/init.d/apachectl start
3.1.10 测试访问

http://<IP>

3.2 mysql安装

3.2.1下载Mysql源码包

下载地址:

http://cdn.mysql.com/Downloads/MySQL-5.7/mysql-5.7.19.tar.gz
​
http://liquidtelecom.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.gz

MySQL从5.7版本之后,boost是必须的,建议把系统自带的boost库卸载,源码编译安装高版本

[root@lamp ~]# yum -y remove boost-*
卸载系统自带的mysql
[root@lamp ~]# yum -y remove mysql
3.2.2 安装依赖
[root@lamp ~]# yum install -y cmake make gcc gcc-c++ bison ncurses ncurses-devel
3.2.3 添加mysql用户和组
[root@lamp ~]# groupadd mysql
[root@lamp ~]# useradd -M -s /sbin/nologin -r -g mysql mysql
3.2.4 创建安装目录和数据存放目录

添加一块新的硬盘,创建分区sdb1并分配所有的空间

[root@lamp ~]# mkdir  -p /var/lib/mysql/
[root@lamp ~]# mkdir  -p /var/lib/mysql/data
[root@lamp ~]# mount /dev/sdb1  /var/lib/mysql
[root@lamp ~]# echo "/dev/sdb1 /var/lib/mysql ext4 defaults 0 0" >> /etc/fstab
​
注:mysql-5.7.11.tar.gz安装时占用空间比较大,虚拟机环境下建议新添加一块硬盘进行安装,真实服务器中可不需要
3.2.5 解压mysql包
[root@lamp ~]# tar zxvf mysql-5.7.19.tar.gz -C /usr/local/src/
[root@lamp ~]# cd  /usr/local/src/mysql-5.7.19
[root@lamp ~]# mkdir -p /usr/local/src/mysql-5.7.19/boost
[root@lamp ~]# tar zxvf boost_1_59_0.tar.gz -C /usr/local/src/mysql-5.7.19/boost
[root@lamp mysql-5.7.19]# cmake -DCMAKE_INSTALL_PREFIX=/var/lib/mysql \
-DMYSQL_DATADIR=/var/lib/mysql/data \
-DSYSCONFDIR=/etc \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock \
-DMYSQL_TCP_PORT=3306 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=/usr/local/src/mysql-5.7.19/boost/boost_1_59_0

编译参数详解:

DCMAKE_INSTALL_PREFIX:指定MySQL程序的安装目录,默认/usr/local/mysql
DEFAULT_CHARSET:指定服务器默认字符集,默认latin1
DEFAULT_COLLATION:指定服务器默认的校对规则,默认latin1_general_ci
ENABLED_LOCAL_INFILE:指定是否允许本地执行LOAD DATA INFILE,默认OFF
WITH_COMMENT:指定编译备注信息
WITH_xxx_STORAGE_ENGINE:指定静态编译到mysql的存储引擎,MyISAM,MERGE,MEMBER以及CSV四种引擎默认即被编译至服务器,不需要特别指定。
WITHOUT_xxx_STORAGE_ENGINE:指定不编译的存储引擎
SYSCONFDIR:初始化参数文件目录
MYSQL_DATADIR:数据文件目录
MYSQL_TCP_PORT:服务端口号,默认3306
MYSQL_UNIX_ADDR:socket文件路径,默认/tmp/mysql.sock
3.2.6 编译
[root@lamp mysql-boost-5.7.19]# make -j 8

注意:编译过程中可能存在的问题,报错如下,提示内存不足,建议至少给3-4GB

c++: internal compiler error: Killed (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
make[2]:  [libmysqld/CMakeFiles/sql_embedded.dir/__/sql/item_geofunc.cc.o] Error 4
make[2]:  Waiting for unfinished jobs....
[ 71%] Building CXX object sql/CMakeFiles/sql.dir/item_geofunc_internal.cc.o
[ 71%] Building CXX object sql/CMakeFiles/sql.dir/item_geofunc_relchecks.cc.o
[ 71%] Building CXX object sql/CMakeFiles/sql.dir/item_geofunc_relchecks_bgwrap.cc.o
[ 71%] Building CXX object sql/CMakeFiles/sql.dir/item_geofunc_setops.cc.o
c++: internal compiler error: Killed (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
make[2]:  [sql/CMakeFiles/sql.dir/item_geofunc.cc.o] Error 4
make[2]:  Waiting for unfinished jobs....
make[1]:  [libmysqld/CMakeFiles/sql_embedded.dir/all] Error 2
make[1]:  Waiting for unfinished jobs....
make[1]:  [sql/CMakeFiles/sql.dir/all] Error 2
make:  [all] Error 2
3.2.7 编译安装
[root@lamp mysql-5.7.19]# make -j 8 install
3.2.8 修改目录的权限
[root@lamp ~]# chown -R mysql:mysql /var/lib/mysql
​
# 存放PID
[root@lamp ~]# mkdir /var/run/mysqld
[root@lamp ~]# chown mysql:mysql /var/run/mysqld -R 
3.2.9 生成配置文件
[root@lamp ~]# mv /etc/my.cnf /etc/my.cnf.bak
​
自行创建my.cnf配置文件
​
[root@lamp ~]# vim /etc/my.cnf
[mysqld]
​
basedir=/var/lib/mysql
​
datadir=/var/lib/mysql/data
​
port=3306
​
socket=/var/lib/mysql/mysql.sock
​
symbolic-links=0
​
character-set-server=utf8
​
log-error=/var/log/mysqld.log
​
pid-file=/var/run/mysqld/mysqld.pid
​
[mysql]
​
socket=/var/lib/mysql/mysql.sock
​
[client]
​
socket=/var/lib/mysql/mysql.sock
​
#sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
3.2.10 添加path路径环境变量
#添加下面2行 在文件的结尾
vim /etc/profile  
​
export MYSQL_HOME=/var/lib/mysql
export PATH=$PATH:$MYSQL_HOME/bin
​
#使修改生效
source /etc/profile
3.2.11 生成服务启动脚本
[root@lamp ~]#  cp /var/lib/mysql/support-files/mysql.server /etc/init.d/mysqld
[root@lamp ~]# chmod +x /etc/init.d/mysqld
3.2.12 初始化数据库

1)然后先删除数据目录下的文件,并创建日志文件

[root@lamp ~]# rm -rf /var/lib/mysql/data/*
[root@lamp ~]# touch /var/log/mysqld.log

2)开始初始化数据库

[root@lamp ~]#/var/lib/mysql/bin/mysqld --initialize-insecure --user=mysql --basedir=/var/lib/mysql --datadir=/var/lib/mysql/data --port=3306
3.2.13 启动服务
[root@lamp ~]# /etc/init.d/mysqld start

注意:启动可能存在报错

[root@lamp ~]# /etc/init.d/mysqld start
Starting MySQL.. ERROR! The server quit without updating PID file (/var/run/mysqld/mysqld.pid).

这种情况请检查/var/run/mysqld是否存在,如果没有的话请创建

完成后,如还是无法启动,则将/var/lib/mysql/data的数据全部删除,再次初始化!!!

3.2.14 修改mysql密码
[root@lamp ~]# mysqladmin -u root password "123456"
  或者
​
[root@lamp ~]# mysql 
​
mysql> set password for 'root'@'hopu01'=password('123456');
3.2.14 修改mysql密码
[root@lamp ~]# mysqladmin -u root password "123456"
  或者
​
[root@lamp ~]# mysql 
​
mysql> set password for 'root'@'hopu01'=password('123456');
3.3.7 添加测试页
[root@lamp php-7.1.10]#  cd /usr/local/apache/htdocs/
[root@lamp htdocs]# vim index.php
<?php
        phpinfo();
?>

至此,LAMP架构就完全搭建好了。

3.4 扩展:yum方式安装LAMP架构

#安装
[root@client html]#  yum -y install httpd mysql mysql-server php php-mysql    #centos6
[root@client html]# yum –y install httpd mariadb mariadb-server php php-mysql  #centos7
#测试apache是否支持php,创建一个文件
[root@client html]## vim index.php
<?php
        phpinfo();
?>
#启动服务
[root@client html]# systemctl start httpd
[root@client html]# systemctl start mariadb

四、APACHE的优化

4.1 隐藏版本

隐藏版本的重要性在于黑客可以扫描出 Apache 版本信息,可以查看对应的版本信息的漏洞,然后攻击。

4.1.1 查看版本
[root@client ~]# curl -I 192.168.1.100
HTTP/1.1 200 OK
Date: Wed, 10 May 2023 07:27:23 GMT
Server: Apache/2.4.51 (Unix) PHP/7.1.10     #可以看到具体的版本
Last-Modified: Wed, 10 May 2023 06:24:44 GMT
ETag: "10-5fb50ed86435c"
Accept-Ranges: bytes
Content-Length: 16
Content-Type: text/html

4.1.2 优化方法

打开http的配置文件,在文件的结尾加入

ServerTokens  Prod
ServerSignature  off
4.1.3 重启APACHE
[root@lamp conf]# systemctl restart apache
4.1.4 查看
[root@client ~]# curl -I http://192.168.1.100
HTTP/1.1 200 OK
Date: Wed, 10 May 2023 07:56:00 GMT
Server: Apache                #没有具体的版本信息。
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html

4.2 启用压缩模块

网站随着用户访问量的增加和内容量的增加,网站的带宽会不断的增加,随之就是网站成本的增加。 并且当内容量增大的时候,客户端如果带宽小,就会影响用户的体验。因此从这两方面考虑,网站的某些内容必须经过压缩之后再传给用户,然后在用户客户端进行解压,来实现双方共赢的效果。

Apache 的压缩要用到 mod_deflate 模块,该模块提供了 DEFLATE 输出过滤器,允许服务器在将输出内容发送到客户端以前进行压缩,以节约带宽。它的核心思想就是把文件先在服务器进行压缩,然后再进行传输,这样可以显著减少文件传输的大小。当传输完毕后,客户端游览器会重新对压缩过的内容进行解压缩。如果没特殊情况的话,所有的文本内容都应该能被 gzip 压缩,例如:html(php),js,css,xml,txt 等

4.2.1 mod_deflate 模块检查及安装
[root@lamp ~]# /usr/local/apache/bin/apachectl -M |grep deflate  #如果没有弹出任何内容,说明没有安装。

安装了的话,就可以直接进行压缩配置了,如果没有安装,下面为安装方法

a)编译时安装方法
编译的时候跟上--enable-deflate 即可实现安装
b)DSO 方式安装。
DSO: Dynamic shared object 动态共享对象 。DSO 模块可以在编译服务器之后编译,也可以用 Apache 扩展工具(apxs)编译并增加

使用 DSO 方式安装,/usr/local/apache2.4-xuegod/bin/apxs 后跟的参数详解

-c 此选项表明需要执行编译操作。
-i 此选项表示需要执行安装操作,以安装一个或多个动态共享对象到服务器的 modules 目录。
-a 此选项自动增加一个 LoadModule 行到 httpd.conf 文件中,以激活此模块,或者,如果此行 已经存在,则启用之。
[root@lamp filters]# /usr/local/src/httpd-2.4.51/modules/filters       #apache源码包 mod_deflate 所在的目录
[root@lamp filters]# /usr/local/apache/bin/apxs -c -i -a  /usr/local/src/httpd-2.4.51/modules/filters/mod_deflate.c    #以 dso 的方式编译安装到apache 中
[root@lamp filters]# ll /usr/local/apache/modules/mod_deflate.so   #成功安装这里会显示出该文件 mod_deflate.so 
-rwxr-xr-x 1 root root 98632 5月  11 09:03 /usr/local/apache/modules/mod_deflate.so
4.2.2 查看是否安装了模块
[root@lamp filters]# /usr/local/apache/bin/apachectl -M |grep deflate
httpd: Syntax error on line 105 of /usr/local/apache/conf/httpd.conf: Cannot load modules/mod_deflate.so into server: /usr/local/apache/modules/mod_deflate.so: undefined symbol: inflate

解决方法:

[root@lamp filters]# vim /usr/local/apache/conf/httpd.conf
​
LoadModule deflate_module modules/mod_deflate.so    #上面一行,插入以下内容:
LoadFile /usr/lib64/libz.so
[root@lamp filters]# /usr/local/apache/bin/apachectl -M |grep deflate
 deflate_module (shared)
4.2.3 压缩模块配置
[root@lamp ~]# vim /usr/local/apache/conf/httpd.conf
​
#在以下内容后,插入
</IfModule> 之后添加以下内容:
<Ifmodule mod_deflate.c>
DeflateCompressionLevel 9 
SetOutputFilter DEFLATE 
DeflateFilterNote Input instream 
DeflateFilterNote Output outstream
DeflateFilterNote Ratio ratio 
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript 
​
</Ifmodule>

注释:

<ifmodule mod_deflate.c>
DeflateCompressionLevel 9 #压缩等级,越大效率越高,消耗 CPU 也越高。
    DeflateCompressionLevel 9 是指压缩程度的等级,从 1 到 9,9 是最高等级。据了解,这样做最高可以减少 8 成大小的传输量(看档案内容而定),最少也能够节省一半。
    DeflateCompressionLevel   预设可以采用 6 这个数值,以维持耗用处理器效能与网页压缩质量的平衡。
注:一般压缩等级使用 6 或 8
 SetOutputFilter DEFLATE #启用压缩
 DeflateFilterNote Input instream #声明输入流的 byte 数量
 DeflateFilterNote Output outstream #声明输出流的 byte 数量
 DeflateFilterNote Ratio ratio #声明压缩的百分比
#LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate #声明日志类型
 #CustomLog logs/deflate_log.log deflate #声明日志类型
 AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript #仅压缩,限制特定的 MIME 类型文件
</ifmodule>

注释:

1、如果是虚拟主机,需要在<VirtualHost*:80></VirtualHost>中添加配置即可实现压缩
2、图片和视频本身就是压缩格式,一般不需要压缩的。有些小图片和视频压缩后还会变大。
4.2.4 创建测试文件
[root@lamp htdocs]# cp /etc/passwd /usr/local/apache/htdocs/passwd.html
[root@lamp htdocs]# ll -h
总用量 8.0K
-rw-r--r-- 1 root root   45 6月  12 2007 index.html
-rw-r--r-- 1 root root 2.8K 5月  11 09:22 passwd.html
4.2.5 测试

总结:我们在企业生产环境中时,在启用 mod_deflate 时,一定要注意,对于太小的文件和某些格式的图片不要对它们进行压缩,有可能越压越大。

扩展:AddOutputFilterByTypeDEFLATE 后跟的所有的压缩文件类型,后期可以参照选择。

text/plain text/html text/php text/xml text/css text/javascript
application/xhtml+xml application/xml application/rss+xml application/atom_xml 
application/x-javascript application/x-httpd-php image/svg+xml image/gif image/png image/jpe image/swf image/jpeg image/bmp

4.3 Apache 缓存

所说的静态文件指的是图片、js、css等文件,用户访问一个站点,其实大多数元素都是图片、js、css等,这些静态文件其实是会被客户端的浏览器缓存到本地电脑上的,目的就是为了下次再请求时不再去服务器上下载,这样就加快了速度,提高了用户体验。但这些静态文件总不能一直缓存,它总有一些时效性,那么就得设置这个过期时间。

4.3.1 配置静态缓存
vim /usr/local/apache/conf/httpd.conf
<IfModule mod_expires.c>  #此模块默认未启用,请手动启用
​
ExpiresActive on
​
ExpiresByType image/gif "access plus 1 days"
​
ExpiresByType image/jpeg "access plus 24 hours"
​
ExpiresByType image/png "access plus 24 hours"
​
ExpiresByType text/css "now plus 2 hours"
​
ExpiresByType application/x-javascript "now plus 2 hours"
​
ExpiresByType application/javascript "now plus 2 hours"
​
ExpiresByType application/x-shockwave-flash "now plus 2 hours"
​
ExpiresDefault "now plus 0 min"
​
</IfModule>

4.3.2 开启模块

或者使用 mod_headers模块实现:该模块默认启用

<IfModule mod_headers.c>

案例1:htm,html,txt类的文件缓存一个小时

<filesmatch  "\.(html|htm|txt)$">
header set cache-control  "max-age=3600"
</filesmatch>

案例2: css, js, swf类的文件缓存一个星期

<filesmatch  "\.(css|js|swf)$">
​
header set cache-control  "max-age=604800"
​
</filesmatch>

案例3:jpg,gif,jpeg,png,ico,flv,pdf等文件缓存一年

<filesmatch  "\.(ico|gif|jpg|jpeg|png|flv|pdf)$">
​
header set cache-control  "max-age=29030400"
​
</filesmatch>
​
</IfModule>

说明:这里的时间单位可以days、hours甚至是min,两种不同的方法,上面使用的是mod_expires,而下面用的是mod_headers,要想使用这些模块,必须要事先已经支持。如何查看是否支持,使用命令:

# /usr/local/apache/bin/apachectl -M
4.3.3 重启服务器并验证
/usr/local/apache/bin/apachectl -t
​
/usr/local/apache/bin/apachectl stop
​
/usr/local/apache/bin/apachectl start
[root@localhost htdocs]#  curl -x192.168.1.101:80 '192.168.1.101/b.png' -I
HTTP/1.1 200 OK
Date: Sat, 30 Oct 2021 13:41:33 GMT
Server: Apache/2.4.51 (Unix) PHP/7.1.10
Last-Modified: Wed, 07 Jul 2021 02:32:26 GMT
ETag: "53954-5c67f595d8280"
Accept-Ranges: bytes
Content-Length: 342356
Cache-Control: max-age=86400                  #这里显示了缓存时间
Expires: Sun, 31 Oct 2021 13:41:33 GMT
Content-Type: image/png

4.4 开启长连接功能

KeepAlive Off/On 保持连接,会减少三次握手,但是会消耗内存,是否打开,取决于单位时间内是否进行多次连接(三次握手),一个连接有多次请求的,建议打开,并适当调整 KeepAliveTimeout 时间在 APACHE 的 httpd.conf 中,KeepAlive 指的是保持连接活跃,如果将 KeepAlive 设置为 On,那么来自同一客户端的请求就不需要再一次连接,避免每次请求都要新建一个连接而加重服务器的负担。

KeepAlive 的连接活跃时间当然是受 KeepAliveTimeOut 限制的。如果第二次请求和第一次请求之间超过 KeepAliveTimeOut 的时间的话,第一次连接就会中断,再新建第二个连接。

所以,一般情况下,图片较多的网站应该把 KeepAlive 设为 On。但是 KeepAliveTimeOut 应该设置为多少秒就是一个值得讨论的问题了。

如果 KeepAliveTimeOut 设置的时间过短,例如设置为 1 秒,那么 APACHE 就会频繁的建立新连接,当然会耗费不少的资源;反过来,如果 KeepAliveTimeOut 设置的时间过长,例如设置为 300秒,那么 APACHE 中肯定有很多无用的连接会占用服务器的资源,也不是一件好事。

所以,到底要把 KeepAliveTimeOut 设置为多少,要看网站的流量、服务器的配置而定。

4.4.1 开启长连接

打开/usr/local/apache/conf/httpd.conf

添加如下内容:
 KeepAlive On    #如果已经为 On,开启长链接功能。那么就不需要再开启了
 KeepAliveTimeout 30  #时间到了断开连接。
    注:考虑到如果网站上有不少的图片,所以将 KeepAlive 设为 On,一般的页面两次请求间隔不会超过 30 秒,所以这样设置,至尽运行状况良好。如果是艺术品网站, 需要看的时间长,那么就设置长一些。
MaxKeepAliveRequests 100   默认:100
    注:一个建立好的 Keep-Alive 连接,允许发送的请求的个数。一旦建立连接,要么就是个数达到了断开,要么就是等 ,MaxKeepAliveRequests 指令限制了当启用 KeepAlive 时,每个连接允许的请求数量。如果将此值设为"0",将不限制请求的数目。我们建议最好将此值设为一个比较大的值,以确保最优的服务器性能。",这个数字的设置,必须考虑在一个时间段内,同一个用户访问你的服务会发多少请求。要结合KeepAliveTimeout 参数来考虑
4.4.2 案例分析
   假设 KeepAlive 的超时时间为 10 秒钟,服务器每秒处理 50 个独立用户访问,那么系统中Apache 的总进程数就是 10 * 50 = 500 个,如果一个进程占用 4M 内存,那么总共会消耗 2G 内存,所以可以看出,在这种配置中,相当消耗内存,但好处是系统只处理了 50 次 TCP 的握手和关闭操作。
   如果关闭 KeepAlive,如果还是每秒 50 个用户访问,如果用户每秒的并发请求数为 3 个,那么Apache 的总进程数就是 50 * 3 = 150 个,如果还是每个进程占用 4M 内存,那么总的内存消耗为600M,这种配置能节省大量内存,但是,系统处理了 150 次 TCP 的握手和关闭的操作,因此又会多消耗一些 CPU 资源。

4.5 对 worker、event 模式性能优化

Apache2.0 以后的版本在性能方面改进最明显的变化就在于使用 worker 模式。

优点:内存占用比 prefork 模式低,适合高并发高流量 HTTP 服务。
缺点:假如一个线程崩溃,整个进程就会连同其他任何线程一起“死掉”。由于线程共享内存空间,所以一个程序在运行时必须被系统识别为“每个线程都是安全的”。服务稳定性不如prefork 模式。后期根据每个进程处理的请求数,重启 worker 进程
4.5.1 主配置文件必须开启引用 httpd-mpm.conf
[root@lamp conf]# vim /usr/local/apache/conf/httpd.conf
#开启httpd-mpm.conf配置
Include conf/extra/httpd-mpm.conf
4.5.2 各种模式详解

1)prefork模式

<IfModule mpm_prefork_module>
    StartServers             5    #启动时进程数
    MinSpareServers          5      #最小空闲线程数。
    MaxSpareServers         10      #最大空闲线程数
    MaxRequestWorkers      250       # 最大并发进程数。
    MaxConnectionsPerChild   0     #最大连接数限制。
</IfModule>

  1. worker模式

</IfModule>
<IfModule mpm_worker_module>
    StartServers            3    #启动时进程数
    MinSpareThreads         75    #最小空闲线程数。
    MaxSpareThreads        250    #最大空闲线程数。
    ThreadsPerChild         25   #每个进程可以启动的线程数量。
    MaxRequestWorkers      400    #所有线程数量的最大值,通常表示了一个 web 服务可以同时处理的请求数。
    MaxConnectionsPerChild   0    #最大连接数限制。
</IfModule>

配置参数详细说明:

<IFModule mpm_worker_module>
StartServers              3      #最初建立的子进程
MinSpareThreads   75      #基于整个服务器监视的最小空闲线程数,如果空闲的线程小于设定值,Apache 会自动建立线程,如果服务器负载大的话,可以考虑加大此参考值。
MaxSpareThreads   250    #基于整个服务器监视的最大空闲线程数,如果空闲的线程大于设定值,Apache 会自动 kill 掉多余的线程,如果服务器负载大的话,可以考虑加大此参考值。
ThreadsPerChild 25          #表示每个进程包含的线程数,如果是并发量比较大,可以考虑加大这个值。此参数在 worker 模式中,是影响最大的参数。
MaxRequestWorkers 400   #所有线程数量的最大值,通常表示了一个 web 服务的最大并发值。MaxRequestWorkers 必须是 ThreadsPerChild 的整数倍,否则 Apache 会提示调整到一个相近的值。MaxRequestWorkers=StartServers* ThreadsPerChild
MaxConnectionsPerChild 0   #每个子进程可以处理的最大请求数。达到该数目后,进程将死掉。如果设置为 0,表示没有限制。
    如:MaxConnectionsPerChild 25000。当进程处理了 25000 个请求后,Apache 管理进程会去终止此进程继续处理新的请求,当此进程处理完所有的已建立的请求后,管理进程会杀掉此进程,重新生成一个新的进程。
  1. event模式

</IfModule> 
<IfModule mpm_event_module>
    StartServers            3   #启动时进程数
    MinSpareThreads         75   #最小空闲线程数。
    MaxSpareThreads        250  #最大空闲线程数。
    ThreadsPerChild            25   #每个进程可以启动的线程数量。
    MaxRequestWorkers      400  #所有线程数量的最大值,通常表示了一个 web 服务可以同时处理的请求数。
    MaxConnectionsPerChild   0  #最大连接数限制。
</IfModule>

配置参数详细说明:

MinSpareServers  # 指令设置空闲子进程的最小数量。所谓空闲子进程是指没有正在处理请求的子进程。如果当前空闲子进程数少于 MinSpareServers那么 Apache 将以第一秒一个,第二秒两个,第三秒四个,按指数递增个数的速度产生新的子进程。如此按指数级增加创建的进程数,最多达到每秒 32个,直到满足 MinSpareServers 设置的值为止;这就是预派生(prefork)的由来;这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能
MaxSpareServers   #指令设置空闲子进程的最大数量。所谓空闲子进程是指没有正在处理请求的子进程。如果当前有超过 MaxSpareServers 数量的空闲子进程,那么父进程将杀死多余的子进程。
可以调整 MinSpareServers 和 MaxSpareServers 这两个参数,但是这两个参数的值不能设得太大,否则 Apache 进程太多,会导致内存占用太多。
注:在一台压力大(并发访问 2000)的服务器上,MaxSpareServers 这个值设置的是 200。保留最大并发数的 11 分之一。设置了这个值的好处是不会有太多的空闲的进程在消耗资源,关闭空闲 Apache进程的同时,会释放内存,进而减少系统资源消耗。
MaxRequestWorkers   #最大同时处理请求的进程数量,也是最大的同时连接数,表示了 Apache的最大请求并发能力,超过该数目后的请求,将排队。
MaxConnectionsPerChild  #进程生命周期内,处理的最大请求数目。达到该数目后,进程将死掉。如果设置为 0,表示没有限制。该参数的意义在于,避免了可能存在的内存泄露带来的系统问题。
将 MaxRequestsPerChild 设置成非零值有两个好处:
    * 可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。
    * 给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。
如:MaxConnectionsPerChild 25000。当进程处理了 25000 个请求后,Apache 管理进程会去终止此进程继续处理新的请求,当此进程处理完所有的已建立的请求后,管理进程会杀掉此进程,重新生成一个新的进程
    注:当 KeepAlive 为 On, 开启长链接时,发送的请求,在 MaxRequestsPerChild 里面只算一个,不管这个连接发送了多少个请求。

示例1:

[root@lamp bin]# ./httpd -V | grep -i "server mpm"
Server MPM:     worker
​
​
<IfModule mpm_worker_module>
    StartServers             8
    MinSpareThreads         128
    MaxSpareThreads        256
    ThreadsPerChild         64
    MaxRequestWorkers      4000
    MaxConnectionsPerChild   10000
</IfModule>
​
#重启apache后查看新的配置
[root@lamp extra]# ps -aux |grep -E "^apache" |wc -l
8
[root@lamp extra]# ps -aux|grep -E "^apache"|awk '{print $6}' 
5764
5780
5776
5780
5776
5772
5768
5760

注:默认单位是 K,可以看到进程大概使用的是 5764K 内存,一共使用了 5764K*8=46.1MB内存,这是初始的内存大小。 后期随着 Apache 进程处理的 web 请的增加,每个进程使用的内存数量还会增加的。 因为每个网站和业务不一样。所以每个 Apache 进程使用的内存大小也不一样

查看进程使用的内存的总大小

[root@lamp extra]# ps -axu | grep -E "apache" | awk '{sum += $6;n++};END{print sum}'
884336
4.5.3 实战场景

假设:一台服务器,16 核心 CPU,64G内存。 Apache 最大可以设置多少个 work 进程。

思路:先减去服务器系统本身所需要的资源,剩下的才能给 Apache 使用。具体分配内存场景,可以参考以下案例。

例 1:当一台服务器是 8G 内存时,  2G留给系统使用, 6G留给 Apache 使用。
例 2:当一台服务器是 16G 内存时,4G留给系统使用,12G留给 Apache 使用。
例 3:当一台服务器是 32G 内存时,8G留给系统使用,24G留给 Apache 使用。
例 4:当一台服务器是 64G 内存时,8G留给系统使用,56G留给 Apache 使用。

总结:系统最多使用 8G 内存,就足够了稳定运行了。

那么对于 64G 内存的服务器,Apache 可以使用 56G 内存,假如每个 work 进程稳定运行时,平均使用 46M 内存。最大 work 进程数为:56*1024/46=1246 个。 根据上述情况,修改后的 http-mpm.conf的 worker 的配置后为:

<IfModule mpm_worker_module>
ServerLimit   2000
StartServers          1246    <!--apache启动时默认开始的子进程数-->
MinSpareThreads     1000    <!--最小空闲数量的工作线程-->
MaxSpareThreads   2500     <!--最大空闲数量的工作线程-->
ThreadsPerChild       250    <!--每个子进程产生的线程数量-->
MaxRequestWorkers 25000
MaxConnectionsPerChild 25000
</IfModule>

注意:

在上面的配置项中,各个配置项的值都是有默认的限制的,若想改变其限制,则需要在配置项的上一行增加ServerLimit配置项,而ServerLimit配置项也是有最大限制的,若要修改各种值,建议仔细阅读下面的内容,再进行更改。
​
worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的ThreadsPerChild 线程数,各个线程独立地处理请求。同样, 为了不在请求到来时再生成线程,MinSpareThreads 和 MaxSpareThreads 设置了最少和最多的空闲线程数。而 MaxRequestWorkers 设置了同时连入的 clients 最大总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程MinSpareThreads 和 MaxSpareThreads 的最大缺省值分别是 75 和 250。这两个参数对 Apache的性能影响并不大,可以按照实际情况相应调节 。
​
ThreadsPerChild 是 worker MPM 中与性能相关最密切的指令。ThreadsPerChild 的最大缺省值是 64,如果负载较大,64 也是不够的。这时要显式使用 ThreadLimit 指令,它的最大缺省值是 20000。
​
Worker 模式下所能同时处理的请求总数是由子进程总数乘以 ThreadsPerChild 值决定的,应该大于等MaxRequestWorkers。如果负载很大,现有的子进程数不能满足时,控制进程会派生新的子进程。默认最大的子进程总数是 16,加大时 也需要显式声明 ServerLimit(系统配置的最大进程数量,最大值是20000)。需要注意的是,如果显式声明了 ServerLimit,那么它乘以 ThreadsPerChild的值必须大于等于MaxRequestWorkers,而且MaxRequestWorkers必须是 ThreadsPerChild 的整数倍,否则 Apache 将会自动调节到一个相应值。

4.5.4 生产环境配置实例

一台服务器 cpu 是 8 核心,物理是内存 32G ,想达到 2000 并发的 apache

worker模式的配置参数如下:

 <IfModule mpm_worker_module>
 StartServers 16 
 MinSpareThreads 75 
 MaxSpareThreads 1250 
 ThreadsPerChild 125 
 MaxRequestWorkers 2000 
 MaxConnectionsPerChild 12500 
</IfModule>

详解每个参数的配置合理性如下:

<IfModule mpm_worker_module>
 StartServers 16 #启动时进程数。一般设同 cpu 核心数一样或是 cpu核心数的 2 倍。这里调成 16 和 cpu 核心一样。
 MinSpareThreads 75 #最小空闲线程数。假设一个网站每天正常被用户使用的时间为早上 7:00 到晚上 2:00。那么 MinSpareThreads 应该配置为,这一时间段,最小并发访问量的 3 倍。比如 7:00 最少并发为 25,那就配置成 75。
 MaxSpareThreads 1250 #最大空闲线程数。一般配置为 1 天中最大并发量的 1半。如这台服务器能处理的最大并量为 2500。那么此值应该为 1250。因为内存闲着也是闲着,可以按linux 下尽可能使用内存的原则,配置成 1250.这样在突然到来更多访问量时,响应会更及时。
 ThreadsPerChild 125 #每个进程可以启动的线程数量。生成环境中,在带宽和硬盘性能充足的情况下,希望这个这台可以完成 2000 左右的并发。那么此值应该为:2000/StartServers 的值(这里是 16)=125 。但是一个进程不可能包括无数的线程,包括太多,会导致进程不稳定,容易崩溃。所以我们认为一个进程最多包括 125 线程,就很好了。所以如果还想处理更多的请求,可以把 StartServers 的值增加,而不是增大 ThreadsPerChild 的值。 因为 ThreadsPerChild值过大,会导致 Apache 运行不稳定。
<p>MaxRequestWorkers 2000 #所有线程数量的最大值,通常表示了一个 web 服务的最大并发值。MaxRequestWorkers 必须是 ThreadsPerChild 的整数倍,否则 Apache 会提示调整到一个相近的值。MaxRequestWorkers=StartServers* ThreadsPerChild。 这里是:16<em>125=2000
MaxConnectionsPerChild 12500 # 最大连接数限制。每个子进程可以处理的最大请求数。如果设置为 0,表示没有限制。 我们设置为 MaxConnectionsPerChild 12500。当进程处理了 12500 个请求后,Apache 管理进程会去终止此进程继续处理新的请求,当此进程处理完所有的已建立的请求后,管理进程会杀掉此进程,重新生成一个新的进程。结合当前的配置,得出结论:
Apache 一个进程中有 125 个线程。 Apache 一个进程处理 12500 个请求。 平均一个线程处理12500/125=110 个请求。这样配置还是合理的。一个线程处理太多的请求,也会出现内存溢出,导致进程崩溃
[root@lamp extra]# ps -aux |grep -E "^apache" |wc -l
16

4.6 Apache 的 Rewrite

4.6.1 Rewrite 规则简介

Rewirte 主要的功能就是实现 URL 的跳转,它的正则表达式是基于 Perl 语言。可基于服务器级的(httpd.conf)和目录级的 (.htaccess)两种方式。如果要想用到 rewrite 模块,必须先安装或加载rewrite 模块。

RewriteEngine on #开启引擎
RewriteCond 字符串1 正则条件1 [标识符1] #重写条件
RewriteRule 正则条件2 字符串2 [标识符2]    #重写规则

mod_rewrite是按照从上到下的顺序执行重写的规则,如果URL匹配了第一条规则,则按照第一条规则进行重写,如果不匹配,就执行第二条规则,直到最后。通过流程控制,可以定义在不同情况下采用不同的重写规则

4.6.2 安装 Rewirte 模块的方式
方法一:是编译 Apache 的时候就直接 安装 rewrite 模块。
方法二:编译 Apache 时以 DSO 模式安装 Apache,然后再利用源码和 apxs 来安装 rewrite 模块。

基于服务器级的(httpd.conf)有两种方法:

方法 1:在 httpd.conf 的全局下 直接利用 RewriteEngine on 来打开 rewrite 功能;
方法 2:在局部里利用 RewriteEngine on 来打开 rewrite 功能,下面将会举例说明,需要注意的是,必须在每个 virtualhost 里用 RewriteEngine on 来打开 rewrite 功能。否则 virtualhost 里没有RewriteEngine on 它里面的规则也不会生效。
4.6.3 重写标志说明
1) R[=code](force redirect) 强制外部重定向。
强制在替代字符串加上 http://thishost[:thisport]/前缀重定向到外部的 URL.如果 code 不指定,将用缺省的 302 HTTP 状态码。
2) F(force URL to be forbidden)禁用 URL,返回 403HTTP 状态码。
3) G(force URL to be gone) 强制 URL 为 GONE,返回 411HTTP 状态码。
4) P(force proxy) 强制使用代理转发。
5) L(last rule) 表明当前规则是最后一条规则,停止分析以后规则的重写。
6) N(next round) 重新从第一条规则开始运行重写过程。
7) C(chained with next rule) 与下一条规则关联。如果规则匹配则正常处理,该标志无效,如果不匹配,那么下面所有关联的规则都跳过。
8) T=MIME-type(force MIME type) 强制 MIME 类型。
9) NS (used only if no internal sub-request) 只用于不是内部子请求。
11) NC(no case) 不区分大小写
11) QSA(query string append) 追加请求字符串。
12) NE(no URI escaping of output) 不在输出转义特殊字符
例如:RewriteRule /foo/(.</em>) /bar?arg=P1%3d$1 [R,NE] 将能正确的将/foo/zoo 转换成/bar?arg=P1=zed
13) PT(pass through to next handler) 传递给下一个处理。
14) S=num(skip next rule(s)) 跳过 num 条规则。
15) E=VAR:VAL(set environment variable) 设置环境变量。

 

4.6.4 mod_rewrite 模块检查及安装
[root@lamp extra]# /usr/local/apache/bin/apachectl -M |grep rewrite  #没有任何输出说明没有安装这个模块

如果之前安装 Apache 时,没有添加--enable-rewrite 选项,那需要使用下面的方法手动编译出来这个模块。 具体如下:

a)编译方式安装
编译的时候跟上--enable-rewrite 即可实现安装。
​
b)DSO 方式安装
以 dso 的方式编译安装到 Apache 中
[root@lamp extra]# /usr/local/apache/bin/apxs -c -i -a /usr/local/src/httpd-2.4.51/modules/mappers/mod_rewrite.c
​
[root@lamp extra]# /usr/local/apache/bin/apachectl -M |grep rewrite  #再次查看模块加载情况
rewrite_module (shared)
4.6.5 实战案例

1、访问特定url,跳转到www.baidu.com

RewriteEngine On      
RewriteCond %{HTTP_HOST} ^www.bestit.com$ [NC]      
RewriteRule ^(.<em>)$ http://www.baidu.com [R=301,L]      

解释一下上述代码:

  • RewriteEngine On:开启重定向模式。

  • RewriteCond %{HTTP_HOST} ^www.bestit.com$ [NC]:判断请求的主机名是否等于 [www.bestit.com],如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写。

  • RewriteRule ^(.</em>)$ http://www.baidu.com [R=301,L]:将请求重定向到 [www.baidu.com],R=301表示永久重定向,L表示立即重定向。

2、仅允许特定IP地址访问特定页面,不匹配跳转到指定页面

RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^192.168.1.1$ [NC]
RewriteCond %{REQUEST_URI} ^/myhome/ [NC]
RewriteRule ^(.<em>)$ /404/index.html [L,QSA]

解释一下上述代码:

  • RewriteEngine On:开启重定向模式。

  • RewriteCond %{REMOTE_ADDR} !^192.168.1.1$ [NC]:判断请求的 IP 地址是否等于 192.168.1.1,如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写。

  • RewriteCond %{REQUEST_URI} ^/myhome/ [NC]:判断请求的 URI 是否等于 /myhome/,如果是则执行重定向,否则继续执行下面的内容。

  • RewriteRule ^(.</em>)$ /404/index.html [L,QSA]:将请求重定向到/404/index.html 页面,其中$1表示重定向的 URI,L表示立即重定向,QSA表示保留请求参数和标头。

3、实现请求的主机前缀不是 www.bestit.com和 192.168.1.1 都跳转到主机前缀为http://www.bestit.com。例如当用户在地址栏写入 http://wuhan.bestit.com 和 shanghai.bestit.com 直接跳转到 http://www.bestit.com

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www.bestit.com$ [NC]
RewriteCond %{HTTP_HOST} !^192.168.1.1$ [NC]
RewriteRule ^(.<em>)$ http://www.bestit.com [R=301,L]

解释一下上述代码:

  • RewriteEngine On:开启重定向模式。

  • RewriteCond %{HTTP_HOST} !^www.bestit.com$ [NC]:判断请求的主机名是否不等于 [www.bestit.com],如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写

  • RewriteCond %{HTTP_HOST} !^192.168.1.1$ [NC]:判断请求的主机名是否不等于 192.168.1.1,如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写。

  • RewriteRule ^(.</em>)$ http://www.bestit.com/$1 [R=301,L]:将请求重定向到 [www.bestit.com],其中$1表示重定向的URI,R=301表示永久重定向,L表示立即重定向。

4、当访问wuhan.bestit.com子域名时,在前面加上www标记

RewriteEngine On          
RewriteCond %{HTTP_HOST} ^wuhan.bestit.com$ [NC]          
RewriteRule ^(.<em>)$ http://www.wuhan.bestit.com [R=301,L]          

解释一下上述代码:

  • RewriteEngine On:开启重定向模式。

  • RewriteCond %{HTTP_HOST} ^wuhan.bestit.com$ [NC]:判断请求的主机名是否等于 Wuhan.bestit.com,如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写。

  • RewriteRule ^(.</em>)$ http://www.wuhan.bestit.com/$1 [R=301,L]:将请求重定向到 [www.wuhan.bestit.com],其中$1表示重定向的 URI,R=301表示永久重定向,L表示立即重定向。

5、当访问www.wuhan.bestit.com子域名时,去掉www标记,但是保存子域名

RewriteEngine On              
RewriteCond %{HTTP_HOST} ^www.wuhan.bestit.com$ [NC]              
RewriteRule ^(.<em>)$ http://wuhan.bestit.com [R=301,L]              

解释一下上述代码:

  • RewriteEngine On:开启重定向模式。

  • RewriteCond %{HTTP_HOST} ^www.wuhan.bestit.com$ [NC]:判断请求的主机名是否等于 [www.wuhan.bestit.com],如果是则拒绝重定向,否则继续执行下面的内容。NC表示不分大小写。

  • RewriteRule ^(.</em>)$ http://wuhan.bestit.com/$1 [R=301,L]:将请求重定向到 wuhan.bestit.com,同时将原始域名保留在请求中,其中$1表示重定向的 URI,R=301表示永久重定向,L表示立即重定向。

6、当访问www.bestit.com/index.html的时候,将.html后缀名转换成.php

RewriteEngine On
RedirectMatch ^/index.html$ /index.php
RedirectMatch ^/(.<em>).html$ /(.</em>).php

解释一下上述代码:

  • 这些规则将在 Apache 服务器响应请求时执行。首先,RewriteEngine On指令将开启重定向功能。

接下来,第一个 RedirectMatch 规则将匹配 /index.html 请求,并将其重定向到 /index.php^/index.html$ 表示匹配 /index.html 开头的 URL,/index.php 表示重定向到的 URL。

  • 第二个 RedirectMatch 规则将匹配 /(.<em>).html$ 开头的 URL,并将其重定向到 /(.</em>).php。这里,^/(.<em>).html$ 表示匹配 /(.</em>).html 开头的 URL,/(.<em>).php 表示重定向到的 URL。

7、判断是否是443端口,如果不是则重定向到www.bestit.com/index.php的443端口

RewriteEngine On
​
RewriteCond %{HTTP_PORT} !^443$
RewriteRule ^/index.html$ https://www.bestit.com/index.php [R=301,L]

解释一下上述代码:

  • 这个规则使用 RewriteEngine On 指令来启用重定向功能

  • 接下来,RewriteCond %{HTTP_PORT} !^443$ 指令将判断请求的端口是否为 443。如果不是,则使用 RewriteRule 指令将 URL 重定向到 https://www.bestit.com/index.phpR=301 参数表示将请求重定向到新 URL,L 参数表示强制立即执行重定向操作。

8、防止图片盗链

防止别人直接从你网站引用图片等链接,消耗了你的资源和网络流量

注意:需要2台服务器测试

RewriteEngine On    
​
RewriteCond %{HTTP_REFERER} !^http://www.bestit.com/ [NC]    # 防止盗链    
RewriteCond %{HTTP_REFERER} !^http://www.bestit.com/index.html [NC]    # 防止盗链    
RewriteCond %{HTTP_REFERER} !^http://www.bestit.com/index.php [NC]    # 防止盗链    
RewriteRule ^/?(.</em>).png$ http://www.bestit.com/index.php [R=301,L]    # 重定向到 PHP 处理    

解释一下上述代码:

  • 这个规则使用 RewriteEngine On 指令来启用重定向功能。

  • 接下来,RewriteCond %{HTTP_REFERER} !^http://www.bestit.com/ 指令将判断请求的 referrer 是否为 www.bestit.com/。如果不是,则使用 RewriteRule 指令将 URL 重定向到 http://www.bestit.com/(.*).phpR=301 参数表示将请求重定向到新 URL,L 参数表示强制立即执行重定向操作。

新开一个服务器,安装http服务,添加如下内容

[root@client htdocs]# cat index.html
< html>
<h1>TEST Apache PNG </h1>
<img src="http://www.bestit.com/a.png">
</html>
[root@client htdocs]# 

解释一下上述代码:

  • 这个静态文件中主要作用是当用户访问当前这台服务器的时候,会引用/www.bestit.com/a.png这个图片,在服务端已经做了防盗链的设置,最后的效果如下:

4.7 常见的Apache的环境变量

Apache中有很多环境变量,以下是一些常见的变量

变量名称

变量类型

描述

HTTP_USER_AGENT

String

发送请求的用户代理字符串

HTTP_REFERER

String

发送请求的页面的 referer

HTTP_COOKIE

String

包含在请求中的目标 Cookie

HTTP_FORWARDED

Bool

指示请求是否通过代理服务器发送

HTTP_HOST

String

发送请求的服务器主机名

HTTP_PROXY_CONNECTION

Bool

指示请求是否通过代理服务器发送

HTTP_ACCEPT

String

发送请求的可接受的内容类型列表

REMOTE_ADDR

IP 地址

发送请求的客户端 IP 地址

REMOTE_HOST

主机名

发送请求的客户端主机名

REMOTE_USER

用户名

发送请求的客户端用户名

REMOTE_IDENT

String

发送请求的客户端 IP 地址和客户端机器名的字符串表示

REQUEST_METHOD

String

发送请求的方法,例如 GET 或 POST

SCRIPT_FILENAME

String

当前脚本的文件名

PATH_INFO

String

当前请求的路径信息

QUERY_STRING

String

当前请求的查询字符串

AUTH_TYPE

String

发送请求的认证类型

DOCUMENT_ROOT

String

当前文档根目录

SERVER_ADMIN

String

服务器管理员的电子邮件地址

SERVER_NAME

主机名

服务器主机名

SERVER_ADDR

IP 地址

服务器 IP 地址

SERVER_PORT

端口号

服务器端口号

SERVER_PROTOCOL

String

服务器使用的 HTTP 协议版本

SERVER_SOFTWARE

String

服务器使用的软件版本

TIME_YEAR

Integer

当前年份

TIME_MON

Integer

当前月份

TIME_DAY

Integer

当前日期的当天日期

TIME_HOUR

Integer

当前小时数

TIME_MIN

Integer

当前分钟数

TIME_SEC

Integer

当前秒数

TIME_WDAY

Integer

当前日期的当天星期几 (0 表示星期日,1 表示星期一,以此类推)

TIME

Integer

当前时间戳

API_VERSION

String

当前 API 版本号

THE_REQUEST

String

当前请求的详细信息

REQUEST_URI

String

当前请求的 URI

五、实战:部署Discuz论坛

官方网站:https://www.discuz.vip

5.1 下载Discuz论坛

下载地址:https://www.discuz.vip/download.html

请根据要求完成如下架构内容:

1.1 部署一套LAMP网站架构
​
1.2 前端的网页数据存放在NFS服务器中,为了避免NFS的单点故障导致数据异常,因此需要部署一个备份服务器时刻同步NFS主服务器的数据
​
1.3 动态数据需要存在Mysql数据中
​
1.4 为了确保网站的数据的安全性,因此需要部署SSL证书
​
1.5 域名解析使用DNS自动完成,并使用DNS来实现访问负载均衡

IP

用途

10.0.0.8

Client

10.0.0.9

DNS

10.0.0.10

Web1

10.0.0.11

Web2

10.0.0.12

NFS-Server

10.0.0.13

NFS-Backup-server

10.0.0.14

MySQL

=========================================NFS-Rsync=========================================</p>
<h1 id="NFS">NFS</h1>
<p>[root@nfs-server~]$ yum install nfs-utils -y
[root@nfs-backup~]$ yum install nfs-utils -y
​
[root@nfs-server~]$ useradd -u 1500 nfs
[root@nfs-backup~]$ useradd -u 1500 nfs
​
[root@nfs-server~]$ cat /etc/exports
[root@nfs-backup~]$ cat /etc/exports
/var/www/html 10.0.0.0/24(rw,all_squash,anonuid=1500,anongid=1500)
​
[root@nfs-server~]$ systemctl start nfs.service
[root@nfs-backup~]$ systemctl start nfs.service
​
[root@nfs-server~]$ cat rsync_inotify.sh
#!/bin/bash
/usr/bin/yum install  -y epel-release &&
/usr/bin/yum install inotify* -y</p>
<h1 id="服务端密码">服务端密码</h1>
<p>PASS=123456
rpm -q sshpass &> /dev/null || yum -y install sshpass &> /dev/null
rm -rf .ssh/id_rsa .ssh/id_rsa.pub
ssh-keygen  -t rsa -P "" -f /root/.ssh/id_rsa &> /dev/null && echo "ssh key is created"
​</p>
<h1 id="定义目标主机">定义目标主机</h1>
<p>host="10.0.0.13"
for IP in $host ;do
       {
       sshpass -p$PASS ssh-copy-id -i /root/.ssh/id_rsa.pub root@$IP -o StrictHostKeyChecking=no &>/dev/null
       echo $IP is ready
       }&
done
wait
​</p>
<h1 id="Client 本地同步目录">Client 本地同步目录</h1>
<p>SRC=/var/www/html/    
​</p>
<h1 id="Server 远程目录">Server 远程目录</h1>
<p>DST1=root@10.0.0.13:/var/www/html
​</p>
<h1 id="D C E 接收三个输出的变量">D C E 接收三个输出的变量</h1>
<p>inotifywait -mrq -e modify,delete,create,attrib ${SRC}|while read D E F
   do
       /usr/bin/rsync -avz --delete $SRC $DST1
  done
 
[root@nfs-server~]$ chmod a+x rsync_inotify.sh
[root@nfs-server~]$ nohup ./rsync_inotify.sh &
​
=========================================Web=========================================
​</p>
<h1 id="Web">Web</h1>
<p>[root@web1~]$ vim /etc/fstab && mount -a
10.0.0.12:/var/www/html   /var/www/html       nfs       _netdev  0 0
​
[root@web2~]$ vim /etc/fstab && mount -a
10.0.0.13:/var/www/html   /var/www/html       nfs       _netdev  0 0
​
[root@web1~]$ yum -y install httpd php php-mysql mod_ssl openssl
​
[root@web2~]$ yum -y install httpd php php-mysql mod_ssl openssl</p>
<p>[root@web1/etc/ssl/certs]$ ls
ca-bundle.crt        ca.key         make-dummy-cert  renew-dummy-cert
ca-bundle.trust.crt  localhost.crt  Makefile</p>
<h2 id="[root@web1/etc/ssl/certs]$ openssl req -new -key ca.key -out https.csr 
...">[root@web1/etc/ssl/certs]$ openssl req -new -key ca.key -out https.csr
...</h2>
<p>Country Name (2 letter code) [XX]:CN      #国家
State or Province Name (full name) []:HB    #省份
Locality Name (eg, city) [Default City]:wh    #城市
Organization Name (eg, company) [Default Company Ltd]:wuhan      #组织单位名称
Organizational Unit Name (eg, section) []:wuhan<br />
Common Name (eg, your name or your servers hostname) []:www.myx.com   #域名
Email Address []:myx@qq.com     #邮箱地址</p>
<p>Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:     #回车
An optional company name []:   #回车</p>
<p>[root@web1/etc/ssl/certs]$ openssl x509 -req -days 365 -sha256 -in https.csr -signkey ca.key -out https.crt
Signature ok
subject=/C=CN/ST=WH/L=wh/O=wh/OU=wh/CN=www.myx.com/emailAddress=myx@qq.com
Getting Private key</p>
<p>[root@web1/etc/httpd/conf.d]$ vim ssl.conf
SSLCertificateFile /etc/ssl/certs/https.crt
SSLCertificateKeyFile /etc/ssl/certs/ca.key
​
=========================================DNS=========================================
​</p>
<h1 id="DNS">DNS</h1>
<p>[root@DNS/var/named]$ vim /etc/named.conf
options {
//      listen-on port 53 { 127.0.0.1; };
       listen-on-v6 port 53 { ::1; };
       directory       "/var/named";
       dump-file       "/var/named/data/cache_dump.db";
       statistics-file "/var/named/data/named_stats.txt";
       memstatistics-file "/var/named/data/named_mem_stats.txt";
       recursing-file  "/var/named/data/named.recursing";
       secroots-file   "/var/named/data/named.secroots";
//      allow-query     { localhost; };
​
[root@DNS/var/named]$ vim /etc/named.rfc1912.zones
zone "myx.com" IN {
       type master;
       file "myx.com.zone";
};
​
[root@DNS/var/named]$ cat myx.com.zone
$TTL 1D
@       IN SOA master smtp.myx.com. (01 1D 1H 1W 1H )
​
       NS      master
master  A       10.0.0.9
www     CNAME   webser
​
webser  A       10.0.0.10
webser  A       10.0.0.11
​
=========================================NFS=========================================
​</p>
<h1 id="NFS-Server">NFS-Server</h1>
<p>[root@NFS-Server/var/www/html]$ if [ -f /usr/bin/curl ];then curl -sSLO https://www.discuz.vip/install/X3.4.sh;else wget -O X3.4.sh https://www.discuz.vip/install/X3.4.sh;fi;bash X3.4.sh
​
=========================================MySQL=========================================
​</p>
<h1 id="Mysql">Mysql</h1>
<p>[root@db~]$ yum install mariadb -y
​
[root@DB~]$ mysql
mysql> grant all privileges on db.* to root@'localhost' identified by '123456' with grant option;
​
mysql> GRANT ALL PRIVILEGES ON <em>.</em> TO 'root'@'10.0.0.%' IDENTIFIED BY '123456' WITH GRANT OPTION;
​
​
=========================================Client=========================================
​</p>
<h1 id="Client">Client</h1>
<p>[root@client~]$ cat /etc/resolv.conf
nameserver 10.0.0.9
​</p>
<h1 id="Windows">Windows</h1>
<p>C:\WINDOWS\system32\drivers\etc\hosts
10.0.0.9 www.myx.com    # DNS-Server
[root@client~]$ dig www.myx.com
​
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.13 <<>> www.myx.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37581
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 2
​
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.myx.com.           IN  A
​
;; ANSWER SECTION:
www.myx.com.        86400   IN  CNAME   webser.myx.com.
webser.myx.com.     86400   IN  A   10.0.0.10
webser.myx.com.     86400   IN  A   10.0.0.11
​
;; AUTHORITY SECTION:
myx.com.        86400   IN  NS  master.myx.com.
​
;; ADDITIONAL SECTION:
master.myx.com.     86400   IN  A   10.0.0.9
​
;; Query time: 1 msec
;; SERVER: 10.0.0.9#53(10.0.0.9)
;; WHEN: 六 11月 11 13:06:15 CST 2023
;; MSG SIZE  rcvd: 130
​
[root@client~]$ ping www.myx.com
PING www.myx.com (10.0.0.11) 56(84) bytes of data.
64 bytes from 10.0.0.11 (10.0.0.11): icmp_seq=1 ttl=64 time=0.553 ms
64 bytes from 10.0.0.11 (10.0.0.11): icmp_seq=2 ttl=64 time=0.691 ms
^C
--- www.myx.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.553/0.622/0.691/0.069 ms
​
​
[root@client~]$ ping www.myx.com
PING www.myx.com (10.0.0.10) 56(84) bytes of data.
64 bytes from 10.0.0.10 (10.0.0.10): icmp_seq=1 ttl=64 time=0.542 ms
64 bytes from 10.0.0.10 (10.0.0.10): icmp_seq=2 ttl=64 time=0.727 ms
^C
--- www.myx.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.542/0.634/0.727/0.095 ms