WEB 服务基础
Internet 因特网
因特网是 Internet 的中文译名
在 20 世纪 60 年代(冷战时期),美国国防部高等研究计划署(ARPA)出于军事上的目的,建立了 ARPA 网络,该网络由四个分布在不同地方的节点组成(最早的异地多活),其目的是为了防止美国军 方的网络系统受到攻击后,还能保持通信
1969年正式启用阿帕网,当时仅连接了4台计算机,供科学家们进行计算机联网实验用,这就是因特网 的前身
到70年代,阿帕网己经连接了好几十个计算机网络,但每个网络只能在网络内部的计算机之间互联通 信,不同计算机网络之间仍然不能互通,研究人员决定开发出一种新的技术将不同的计算机局域网互相 联通,从而形成 互联网(Internet Net Work,简称 Internet)
WWW 万维网
在现实生活中,常说的上网,实际上访问的只是互联网的一个子集 万维网(World Wide Web)
万维网是基于 HTTP 协议,传输 HTML 等超文本资源的一个分布式超媒体系统,基于 B/S 架构实现,当然,其能力也被限制在 HTTP 协议之内
互联网上还有许多万维网之外的资源,例如常用的电子邮件,BT 网络 和 Magnet 点对点下载,FTP 文 件下载,SSH 安全登录等,这些服务都需要有各自的专有协议来支持
不过由于 HTTP 协议非常灵活、易于扩展,而且"超文本"的表述能力很强,所以很多其他原本不属于 HTTP 的资源也可以 包装 成 HTTP 来访问,这就是我们为什么能够总看到各种 网页应用,例如 微信网 页版,邮箱网页版
HTTP 协议
HTTP 协议介绍
HTTP:(H yperT ext T ransfer Protocol)超文本传输协议
HTTP 是一个工作在应用层的通信协议,它允许将超文本标记语言(HTML)文档从 WEB 服务器传送到 客户端的浏览器
HTTP 不是一个孤立的协议:
在互联网世界里,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可 靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外,还有一些协议依赖于HTTP, 例如 WebSocket、HTTPDNS 等。这些协议相互交织,构成了一个协议网,而HTTP 则处于中心地位
HTTP 协议版本和发展历史
初始阶段
在 20 世纪 60 年代(冷战时期),美国国防部高等研究计划署(ARPA)出于军事上的目的,建立了 ARPA 网络,该网络由四个分布在不同地方的节点组成(最早的异地多活),其目的是为了防止美国军 方的网络系统受到攻击后,还能保持通信
ARPA 网络 被认为是今天流行的因特网的开始
到 20 世纪 70 年代,基于对 ARPA 网络的实践和思考,研究人员发明了著名的 TCP/IP 协议,由于具有 良好的分结构和稳定的性能,TCP/IP 协议迅速流行起来,并在 80 年代中期进入了 UNIX 系统内核,促 使更多的计算机接入了互联网
萌芽阶段
1989 年,任职于欧洲核子研究中心 (CERN) 的蒂姆伯纳斯-李(Tim Berners-Lee) 发表了一篇论文,提出 了在互联网上构建超链接文档系统的构想。这篇论文中他确立了三项关键技术
-
URI:统一资源标识符,作为互联网上资源的唯一身份
-
HTML:超文本标记语言,描述超文本文档
-
HTTP:超文本传输协议,用来传输超文本
这三项技术在如今的我们看来已经是稀松平常,但在当时却是了不得的大发明。基于它们,就可以把超 文本系统完美地运行在互联网上,让各地的人们能够自由地共享信息,蒂姆把这个系统称为 "万维 网"(World Wide Web) ,也就是我们现在所熟知的 Web
HTTP / 0.9
20 世纪 90 年代初期的互联网世界非常简陋,计算机处理能力低,存储容量小,网速很慢,网络上绝大 多数的资源都是纯文本,很多通信协议也都使用纯文本,所以 HTTP 的设计也不可避免地受到了时代的 限制。
这一时期的 HTTP 被定义为 0.9 版,结构比较简单,为了便于服务器和客户端处理,HTTP 协议采用了纯 文本的格式,在 蒂姆 最初设想的系统里的文档都是只读的,所以只允许用 GET 动作从服务器上获取 HTML 文档,并且在响应请求之后立即关闭连接,功能非常有限
HTTP / 1.0
1993 年,NCSA(美国国家超级计算应用中心)开发出了 Mosaic,是第一个可以图文混排的浏览器, 随后又在 1995 年开发出了服务器软件 Apache,简化了 HTTP 服务器的搭建工作
同一时期,计算机多媒体技术也有了新的发展,1992 年发明了 JPEG 图像格式,1995 年发明了MP3 音 乐格式
这些新的软件和技术一出现就吸引了大量用户,更多的人开始使用互联网,研究 HTTP 并提出意见,从 而从用户需求的角度促进了 HTTP 的发展,基于此,在经过一系列的草案之后,HTTP/1.0 版本在 1996 年正式发布,它在多方面增强了 0.9 版,形式上己经和当前的 HTTP 差别不大了,比如:
-
增加了 HEAD、POST 等新方法;
-
增加了响应状态码,标记可能的错误原因;
-
引入了协议版本号概念;
-
引入了 HTTP Header (头部) 的概念,让HTTP 处理请求和响应更加灵活;
-
专输的数据不再仅限于文本;
但 HTTP/1.0 并不是一个标准,只是记录已有实践和模式的一份参考文档,不具有实际的约束力,相当 于一个 备忘录
HTTP / 1.1
1995 年,网景的 Netscape Navigator 和微软的 Internet Explorer 的浏览器大战,再一次极大的推动 了 WEB 的发展,HTTP/1.1 也是在这个过程中经受了实践检验,在此后的 1999 年,HTTP/1.1 发布了 RFC 文档,编号为 2616,相对于 HTTP/1.0 而言,HTTP/1.1 是一个正式的标准,其主要变更点有:
-
增加了 PUT、DELETE 等新的方法;
-
增加了缓存管理和控制;
-
明确了连接管理,允许持久连接;
-
允许响应数据分块 (chunked),利于传输大文件;
-
强制要求 Host 头,让互联网主机托管成为可能;
自 HTTP/1.1 开始,互联网开启了飞速发展的阶段,陆续进入了 Web 1.0,Web 2.0 时代,现在的许多 知名的互联网公司都是在这个时间点左右成立的,例如 google,新浪,搜狐,网易,腾迅等
由于 HTTP/1.1 太过庞大和复杂,在 2014 年其 RFC 文档被拆分成了六份较小的文档,编号为 7230 -- 7235,并优化了一些细节
HTTP / 2
HTTP/1.1 发布之后的十多年里,互联网行业呈现了爆发式的增长,出现了一大批著名的互联网公司,例 如 Facebook,Twitter,淘宝,京东等,这期间也出现了一些对 HTTP 不满的意见,主要就是连接慢, 无法跟上互联网行业的发展速度,但 HTTP/1.1 标准一直没有对这些不足之处进行迭代
在这种情况下,Google 先是发布了自研浏览器 Chrome,然后推出了新的 SPDY 协议,并在 Chrome 浏览器中将 SPDY 协议应用于自有的服务器中,由于 Chrome 浏览器的市场占有率持续增长,互联网标 准化组织以 SPDY 协议为基础,在 2015 年发布了 HTTP/2 标准,RFC 文档编号为 7540,2022年6月 HTTP/2 的 RFC 文档更新为 9113
HTTP/2 标准充分考虑了当前的互联网行业现状,在高度兼容 HTTP/1.1 的同时,在性能改善方面做了很 大努力,主要有以下几方面:
-
进制协议,不再是纯文本;
-
可发起多个请求,废弃了 1.1 里的管道;
-
使用专用算法压缩头部,减少数据传输量;
-
允许服务器主动向客户端推送数据;
-
增强了安全性,"事实上"要求加密通信;
虽然 HTTP/2 到今天己经发布很久了,也衍生出了 gRPC 等新协议,但由于 HTTP/1.1 实在太于过经典和 强势,目前大多数网站还是使用 HTTP/1.1 标准与客户端进行通信
HTTP / 3
在 HTTP/2 还处于草案之时,Google 又发明了一个新的协议,叫做 QUIC,而且还是相同的套路,继续 在 Chrome 和自家服务器里试验,依托Chrome庞大用户量和数据量,持续地推动路 QUIC 协议成为互 联网上的既成事实,在2018年,互联网标准化组织 IETF 提议将 HTTP over QUIC 更名为 HTTP/3,并获 得批准,HTTP/3 正式进入了标准化制度阶段,经过多年努力,HTTP/3 的 RFC 文档于 2022年6月6日正 式发布,文档编号为 9144
HTTP 协议相关概念和技术
URI 和 URL
URI:(Uniform Resource Identifier),统一资源标识符,是一个用来唯一标识互联网上某一特定资源 的字符串
URL:(Uniform Resource Locator),统一资源定位符
URN:(Uniform Resource Name),统一资源名称
WEB 上的可用的每种资源,HTML文档,图片文件,音视频文件,压缩包等,都可以用一个全网唯一的 URI 来标识出来,该标识充许用户对任何资源通过特定的协议进行交互操作
简单来说,URI 是抽象的定义,不管用什么方法表示,只要能定位一个资源,就叫 URI
在早期的设计中,用来定位资源的方式有两种,用地址定位(URL)和 用名称定位(URN),不管用哪 种方式定位,只要能保证全网唯一即可,只是使用 URN 的场景较少,导致在 WEB 应用上,几乎所有的 URI 都是 RUL 形式的
URL 组成
bash
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
http://www.baidu.com:8080/images/logo.jpg
ftp://mage:password@172.16.0.1/pub/linux.ppt
rtsp://videoserver/video_demo/
gcomm://10.0.0.8,10.0.0.18,10.0.0.28
http://www.baidu.com/bbs/hello;gender=f/send;type=title
https://list.jd.com/list.html?
cat=670,671,672&ev=14_2&sort=sort_totalsales15_desc&trans=1
http://apache.org/index.html#projects-list
字段 | 说明 |
---|---|
scheme | 方案,获取资源的协议,有多种 |
user | 用户名,某些资源需要权限才能获取 |
password | 密码,权限凭证 |
host | 主机,资源所在服务器的 IP 或域名 |
port | 端口,根据协议,不同协议通常有默认端口 |
path | 路径,资源在服务器上的相对路径 |
params | 参数,客户端提交的参数,键值对形式,key/value,多个参数用 ; 分隔 |
query | 查询,客户端提交的查询参数,键值对形式,key=value,多个查询参数用 & 分隔 |
frag | 片段,用来锚定资源的一部份 |
前端页面技术
前端页面技术:HTML + CSS + JAVASCRIPT
HTML:(Hyper Text Markup Language),超文本标记语言
HTML 是由 Tim Berners-Lee 和同事 Daniel W. Connolly 于1990年创立的一种标记语言,它是标准通 用化标记语言SGML的应用。用HTML 编写的超文本文档称为HTML文档,它能独立于各种操作系统平台 (如UNIX, Windows等),使用 HTML 将所需要表达的信息按某种规则写成 HTML 文件,通过浏览器 解析,就是我们所见到的网页
CSS:(Cascading Style Sheets),层叠样式表
CSS 定义了如何显示(装扮) HTML 元素,比如:字体大小和颜色属性等。样式通常保存在外部的 .css 文件中,用于存放一些HTML文件的公共属性,从而通过仅编辑一个简单的 CSS 文档,可以同时改变站点中所有页面的布局和外观
JS:(Javascript)
JavaScript 是一种属于网络的高级脚本语言,已经被广泛用于 Web 应用开发,常用来为网页添加各式各 样的动态功能,为用户提供更流畅美观的浏览效果。通常JavaScript脚本是通过嵌入在HTML中来实现自 身的功能的
MIME 类型
MIME:(Multipurpose Internet Mail Extensions),多用途互联网邮件扩展
MIME 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式,浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理资源,因此,WEB 服务器会在响应头中配置正确的 MIME 值,保证资源被客户端正确处理
MIME 类型通常仅包含两个部分:类型(type)和 子类型(subtype),中间由斜杠 / 分割,中间没有 空白字符
类型代表数据类型所属的大致分类,例如 video 或 text,子类型标识了 MIME 类型所代表的指定类型的 确切数据类型,以 text 类型为例,它的子类型包括:plain(纯文本)、html(HTML 源代码)、 calender(iCalendar/.ics 文件)等,每种类型都有自己的一组可能的子类型。一个 MIME 类型总是包 含类型与子类型这两部分,且二者必需成对出现
有一个可选的参数,能够提供额外的信息
bash
type/subtype
type/subtype;parameter=value
静态资源和动态资源
客户端通过 URI 锚定服务端的一个唯一资源,WEB SERVER 服务将该资源返回给客户端,资源可以分为 静态资源和动态资源两类,在 Web 服务中,静态资源和动态资源是根据其内容和生成方式来定义的, 它们在处理和提供方式上有一些显著的区别
静态资源
-
定义:静态资源是指在服务器上事先存在,不需要在请求时进行动态生成的文件,这些文件包括 HTML、CSS、JavaScript、图像(如 JPEG、PNG)等
-
生成方式:静态资源是直接从服务器上的文件系统提供的,没有经过服务器端的处理或计算,它们 的内容在创建时已经确定,不会根据每个请求而变化
-
特点:静态资源适用于那些内容较为固定,不经常变化的情况,它们可以被直接缓存,以提高访问 速度,并减轻服务器的负载
动态资源
-
定义:动态资源是在服务器上根据用户请求动态生成的内容。这通常涉及到使用服务器端脚本(如 PHP、Python、Node.js)进行处理,并根据用户请求的参数生成不同的内容
-
生成方式:动态资源的内容在请求时动态生成,可能涉及到数据库查询、计算或其他与用户请求相 关的操作,每次请求可能产生不同的结果
-
特点:动态资源适用于需要根据用户输入或其他动态条件生成内容的情况。它们通常涉及更多的计 算和服务器端的处理,可能会引起更高的服务器负载
相同点
-
都是 Web 服务的一部份:静态资源和动态资源都是 WEB 服务中的一部份
-
都是通过 HTTP 协议访问:静态资源和动态资源都是通过 HTTP 协议来传输和访问
不同点
-
内容生成方式:静态资源是事先存在并直接提供的,而动态资源是根据用户请求时动态生成的
-
性能和缓存:由于静态资源是固定的,它们可以更容易地被缓存,从而提高性能。相反,动态资源 可能需要更多的计算,可能无法被缓存,因此可能对服务器产生更大的负载
-
适用场景:静态资源适用于内容较为固定、不经常变化的场景,而动态资源适用于需要根据用户请 求生成不同内容的情况
在实际的 Web 应用中,通常会同时使用静态资源和动态资源,以充分利用它们各自的优势,例如,静 态资源可以用于提供页面的基本框架、样式和脚本,而动态资源可以用于提供个性化的、与用户交互的 内容
网站流量指标
网站流量指标是常用来对网站效果进行评价,主要指标包括独立访问者数量、重复访问者数量、页面浏 览数、每个访问者的页面浏览数和某些具体文件或页面的统计指标。
-
UV:(unique visitors),独立访客量,独立访问者数量,一天内来自相同客户端的访问只计算一 次
-
PV:(page views),页面浏览数量,网站点击量,访客每打开一个页面或刷新一次页面都计算一 次,
-
IP:独立IP数量,一天内来自相同IP地址的客户端的访问只计算一次,是衡量网站流量的重要指标
浏览器访问网站的过程
-
在浏览器地址栏中输入网址
-
DNS 服务解析域名,客户端获得服务器 IP 地址
-
浏览器用 TCP 的三次握手与服务器建立连接
-
浏览器向服务器发送拼好的报文
-
服务器收到报文后处理请求,同样拼好报文再发给浏览器
-
浏览器解析报文,渲染输出页面
HTTP 协议报文头部结构
HTTP 工作机制
HTTP 是一种允许浏览器向服务器获取资源的协议,是 WEB 的基础,通常由浏览器发起请求,用来获取 不同类型的资源,比如 HTML 文件,CSS 文件,Javascript 文件,图片,视频,压缩包等
一次完整的 HTTP 事务包括 客户端发起 HTTP 请求,服务端响应请求两部份组成
一个页面通常有多个资源组成,浏览器打开一个页面,通常要发起多次请求,分别加载不同的资源
HTTP 请求报文
HTTP 协议的请求报文由三大部份组成
-
起始行:(start line),开始行,请求行,描述了请求的基本信息
-
头部字段合集:(header),首部行,使用 key: value 格式详细的说明报文
-
消息正文:(entity),实体(body),请求数据,可以没有
在命令行下查看请求头,用浏览器或抓包工具同样可以查看
bash
[root@ubuntu ~]# curl -v http://www.baidu.com
* Trying 220.181.38.150:80...
* Connected to www.baidu.com (220.181.38.150) port 80 (#0)
> GET / HTTP/1.1 #请求行
> Host: www.baidu.com #首部行
> User-Agent: curl/7.81.0 #首部行
> Accept: */* #首部行
> #空格+换行
#请求数据为空
HTTP 响应报文
HTTP 协议的响应报文由三大部份组成
-
起始行:(start line),开始行,状态行,描述了响应的基本信息
-
头部字段合集:(header),首部行,使用 key: value 格式详细的说明报文
-
消息正文:(entity),实体(body),响应数据,可以没有
HTTP 请求方法
在 蒂姆 最初的设计中,是要用 HTTP 协议构建一个超链接文档系统,使用 URI 来定位这些文档,也就 是资源,为了让客户端可以使用不同的方式来操作服务器上的资源,相应的,就设计出了不同的请求方法
其实际含义就是让客户端向服务器发出一个特定的动作指令,要求服务端对指定的URI 资源执行相应的 动作
由于资源并不在客户端,所以最终决定是否对资源执行操作,由服务端决定,服务端收到客户端的请求 报文后,得到请求方法,可以执行,也可拒绝,还可以改变请求方法的含义
根据 HTTP 标准,HTTP 请求可以使用多种请求方法
HTTP1.0 定义了三种请求方法: GET,POST,HEAD
HTTP1.1 新增了六种请求方法:OPTIONS,PUT,PATCH,DELETE,TRACE,CONNECT
在后续其它版本的 HTTP 协议中,还陆续增加了 MKCOL,COPY,MOVE,LOCK,UNLOCK 等方法
在这些方法中,最常用的只有 GET,POST,HEAD,PUT 等有限的几种
请求方法 | 协议版本 | 说明 |
---|---|---|
GET | 0.9 | 获取资源,可以理解为读取或者下载数据 |
HEAD | 1.0 | 获取资源,和 GET 类似,不返回具体数据,只需要头信息 |
POST | 1.0 | 向服务端提交数据,数据通常交由后端程序处理 |
PUT | 1.1 | 向服务端提交数据,数据直接存储在服务器上 |
PATCH | 1.1 | 对PUT方法的补充,用来对己知资源进行局部更新 |
DELETE | 1.1 | 请求服务端删除指定资源 |
CONNECT | 1.1 | 建立一个到服务端的隧道 |
OPTIONS | 1.1 | 请求服务端返回对指定资源支持使用的请求方法 |
TRACE | 1.1 | 追踪请求到达服务器中间经过的代理服务器 |
HTTP 响应状态码
服务器收到请求报文,解析后需要进行处理,具体的业务逻辑多种多样,但最后必定是拼出一个响应报 文发回客户端
响应报文由响应头加响应体数据组成,响应头又由状态行和头字段构成,状态行包括 协议版本,响应状 态码,与响应码对应的状态短语 三部份内容
状态码是一个十进制的数字,以代码的形式表示服务端对请求的处理结果,客户端可以根据此值转换处 理状态,比如继续发送请求,切换协议,重定向跳转等,在 RFC 文档中规定的状态码是三位数,所以可 用值为 000 到 999,但实际上,RFC 把状态码分成了五类,用数字的第一位表示分类,而且仅仅只明确 定义了41个状态码
状态码分类
分类 | 取值范围 | 说明 |
---|---|---|
1** | 100 - 199 | 提示信息,表示服务器收到请求,目前是协议处理的中间状态,需要客户端继 续执行操作 |
2** | 200 - 299 | 成功,报文已经收到并被正确处理 |
3** | 300 - 399 | 重定向,资源位置发生变动,需要客户端重新发送请求 |
4** | 400 - 499 | 客户端错误,请求报文有误,服务器无法处理 |
5** | 500 - 599 | 服务器错误,服务器在处理请求时内部发生了错误 |
常用状态码及对应短语
状态码 | 状态短语 | 说明 |
---|---|---|
200 | OK | 请求成功,一般用于GET与POST请求 |
301 | Moved Permanently | 永久重定向,客户端请求的资源被移动到新的URI,返回信息中包含新 的URI,客户端自动请求 |
302 | Found | 临时重定向,其它与301相同 |
304 | Not Modified | 自上次访问以来,该资源没有发生更改,客户端直接使用本地缓存 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解,此状态码是一个通用错误码,并不能准确描述错误 |
401 | Unauthorized | 请求要求用户的身份认证 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求,原因有多样, 通常是没有权限 |
404 | Not Found | 服务器上没有找到客户端需要访问的资源 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
502 | Bad Gateway | 服务端网关错误 |
503 | Service Unavailable | 服务器当前很忙,暂时无法响应请求(网络服务正忙,请稍后重试) |
504 | Gateway Time-out | 服务端网关超时 |
bash
https://www.runoob.com/http/http-status-codes.html #完整的41个状态码列表
在 HTTP 协议中,正确地理解并应用这些状态码不是客户端或服务器单方的责任,而是双方共同的责任
客户端作为请求的发起方,获取响应报文后,需要通过状态码知道请求是否被正确处理,是否要再次发 送请求,如果出错了原因又是什么,这样才能进行下一步的动作,要么发送新请求,要么改正错误重发 请求
服务器端作为请求的接收方,也应该很好地运用状态码。在处理请求时,选择最恰当的状态码回复客户 端,告知客户端处理的结果,指示客户端下一步应该如何行动,特别是在出错的时候,尽量不要简单地 返 400、500 这样意思含糊不清的状态码
目前 RFC 标准里总共有 41 个状态码,但状态码的定义是开放的,允许自行扩展。所以 Apache,Nginx 等 Web 服务器都定义了一些专有的状态码。如果你自己开发 Web 应用,也完全可以在不冲突的前提下 定义新的代码
COOKIE 和 SESSION
HTTP 是一种无状态协议,这意味着每个HTTP请求都是相互独立的,服务器在处理请求时不会保留先前 请求的任何状态信息,每个请求都是独立的、不相关的操作。
这无状态的特性有助于简化协议的设计和实现,同时也使得它更具可伸缩性,每个请求都包含所有必要 的信息,而服务器无需维护每个客户端的状态,从而降低了服务器的负担。
如果客户端需要在多次请求之间保持状态,通常会使用一些机制,如Cookie或Session。
Cookies 和 Sessions 都是用于在Web应用程序中管理用户状态的机制,它们的作用主要涉及用户身份验 证、跟踪会话信息以及存储用户偏好等方面
Cookie
Cookie 是一小段存储在用户计算机上的数据,由服务器通过 HTTP 协议发送给用户的浏览器,然后浏览 器将其保存。每次用户访问同一站点时,浏览器都会将相应的 Cookie 发送回服务器,从而实现在客户 端和服务器之间存储和传递信息的功能。Cookies 通常包含一些键值对,用于存储少量文本数据,例如 用户的身份认证信息、首选语言、个性化设置等
Session
Session 是服务器端的一种机制,用于在用户和服务器之间存储信息。与 Cookie 不同,Session 数据并 不直接存储在用户计算机上,而是存储在服务器上。通常,服务器会为每个用户创建一个唯一的会话标 识符(Session ID),该标识符通过 Cookie 或者 URL 参数的形式发送给用户。在服务器端,与每个会 话相关的数据都会被存储,这样在用户的不同请求之间可以保持状态。 Sessions 通常用于存储用户的登 录状态、购物车内容、权限信息等
session 共享和 session 复制
session 是以文件的形式保存在服务器中的,在只有一台 WEB 服务器的情 况下,这种方式没有任何问题,但是如果在负载均衡场景下,session 文件只存在于后端某一台服务器 上,如果客户端请求被负载到其它服务器上,那么,该客户端的状态就无法维持
session 共享是指 session 不再只存在某一台服务器上,而是放在某个共享存储中,后端服务器共用所 有的 session 信息,session 共享可以用 NFS,MYSQL,REDIS 等方式实现
session 复制是指 当后端某台主机上对 cookie 数据产生了写操作(包括新增,修改,删除等),然后将 修改后的数据同步到该集群中其它 WEB 服务器上,保证所有 WEB 服务器上都有全量且状态统一的 session 数据,那么,无论将客户端请求调度到任何一台 WEB 服务器上,该服务器上都有 session 数据
网络IO模型
网络IO相关概念
IO:(INPUT,OUTPUT),输入输出,分为IO设备和IO接口两部份,在 POSIX 兼容的系统上,IO 操作可 以有多种实现方式
IO 主要分为 文件IO 和 网络IO 两种,这里重点学习 网络IO
同步和异步
同步和异步关注的是消息的通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成 状态的通知
-
同步:sychronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事件是否处理完成
-
异步:asynchronous,被调用者通过状态,通知或者回调机制主动通知发起调用者相关的运行状态
阻塞和非阻塞
阻塞和非阻塞关注的是调用发起者在等待结果返回之前所处的状态
-
阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂 起,干不了别的事情。
-
非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完 成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
五种网络IO模型
阻塞 IO(blocking IO)
阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
用户线程通过系统调用 read 发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然后 将接收的数据拷贝到用户空间,完成 read 操作,用户需要等待 read 将数据读取到buffer后,才继续处 理接收的数据。整个I/O请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何 事情,对CPU的资源利用率不够
优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销 较大,apache 的 prefork 使用的是这种模式。
非阻塞 IO(non-blocking IO)
阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
用户线程通过系统调用 read 发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然后 将接收的数据拷贝到用户空间,完成 read 操作,用户需要等待 read 将数据读取到buffer后,才继续处 理接收的数据。整个I/O请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何 事情,对CPU的资源利用率不够
优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销 较大,apache 的 prefork 使用的是这种模式。
非阻塞 IO(non-blocking IO)
多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自 的IO,即复用同一个线程
一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLL 或 EPOLL 等系 统调用,从而实现多路复用IO,这三个系统调用的好处就在于单个 process 可以同时处理多个网络连接 IO,其基本原理是不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
当用户进程调用了select,那么整个进程会被 block,而同时,kernel会 监视 所有 select 负责的 socket,当任何一个 socket 中的数据准备好了,select 就会返回。这个时候用户进程再调用 read 操 作,将数据从 kernel 拷贝到用户进程
Apache prefork是此模式的 select,worker 是 poll 模式。
信号驱动 IO(signal driven I/O, SIGIO)
信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知 进程
调用的步骤是,通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后 主程序可以继续向下执行,当有IO操作准备就绪,即内核数据就绪时,内核会为该进程产生一个 SIGIO 信 号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据,将用户 进程所需要的数据从内核空间拷贝到用户空间
此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处 理函数的通知,在信号驱动式 IO 模型中,应用程序使用套接口进行信号驱动 IO,并安装一个信号处理 函数,进程继续运行并不阻塞,当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中 调用 IO 操作函数处理数据
优点:线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求, 因此可以提高资源的利用率
缺点:信号 IO 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
异步 IO(Asynchronous I/O)
异步IO 与 信号驱动IO最大区别在于,信号驱动是内核通知用户进程何时开始一个IO操作,而异步IO是 由内核通知用户进程IO操作何时完成,两者有本质区别
相当于不用去饭店场吃饭,直接点个外卖,把等待上菜的时间也给省了
相对于同步IO,异步IO不是顺序执行。用户进程进行 aio_read 系统调用之后,无论内核数据是否准备 好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到 socket 数据准备好了,内核直 接复制数据给进程,然后从内核向进程发送通知。IO 两个阶段,进程都是非阻塞的
信号驱动IO当内核通知触发信号处理程序时,信号处理程序还需要阻塞在从内核空间缓冲区拷贝数据到 用户空间缓冲区这个阶段,而异步IO直接是在第二个阶段完成后,内核直接通知用户线程可以进行后续 操作了
优点:异步 IO 能够充分利用 DMA 特性,让 IO 操作与计算重叠
缺点:要实现真正的异步 IO,操作系统需要做大量的工作,目前 Windows 下通过 IOCP 实现了真正的 异步 IO,在 Linux 系统下,Linux 2.6才引入,目前 AIO 并不完善,因此在 Linux 下实现高并发网络编 程时以 IO 复用模型模式 + 多线程任务的架构基本可以满足需求
Linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、 libuv。
IO 模型对比
上述五种 IO 模型中,越往后,阻塞越少,理论上效率也是更好
常用的 WEB 服务器
主流的 WEB 服务器介绍
Web服务器是提供Web信息服务的软件,它通过HTTP或HTTPS协议与客户端通信,接受客户端请求, 处理请求,然后返回响应数据,Web 服务器的主要工作是通过存储、处理和交付网页给用户来显示网站 内容,一个成熟的WEB服务器软件不仅仅只是处理客户端请求,还要有良好的安全性和稳定性,以满足 用户不断变化和增长的需求
以下是一些主流的Web服务器以及它们的特点,这些Web服务器都有各自特点和优势,在使用的时候, 要取决于项目需求,性能要求及开发人员偏好等
Apache
Apache 是目前市场占有率最高的WEB服务器,它免费开源,功能强大,支持多种操作系统,可在多平 台上运行,包括Unix、Linux、Windows等,同时具有强大的模块化体系结构,提供了丰富的模块,也 支持许多第三方模块,允许用户自定义服务器功能,另外也支持虚拟主机配置
Nginx
Nginx是一个高性能的Web服务器,广泛应用于高并发、大流量的互联网应用场景中,Nginx还可以作为 反向代理服务器、负载均衡服务器,其优异的静态处理能力,使其在处理静态文件时具有很高的效率, 由于选择了高效的网络IO模型,使其在高并发大流量的工作场景下,对于资源(CPU,内存等)的要求 非常低,且运行非常稳定
Microsoft IIS(Internet Information Services)
Microsoft IIS 是微软公司开发的一种Web服务组件,其中包括WEB服务器, FTP服务器,NNTP服务器 和SMTP服务器,分别用于网页浏览,文件传输,新闻服务和邮件服务等业务,它提供ISAPI作为扩展 WEB服务器功能的编程接口,对ASP、NET等微软技术有很好的支持,同时还提供了Internet,可以实现 对数据库的查询和更新
Tomcat
Tomcat是一个开放源代码、运行servlet和JSP Web应用软件,它不仅仅是一个WEB服务器,也是一个 Servlet和JSP容器,但其对静态文件和高并发的处理能力较弱
Apache2 的安装和使用
Apache 介绍
Apache 通常可以指代两个相关但不同的概念,分别是 Apache 软件基金会和 Apache HTTP Server
Apache软件基金会(Apache Software Foundation,简称 ASF)
Apache软件基金会(ASF)的前身起源于一个从事服务器开发与维护的 "Apache 组织",该组织开发了 一个 HTTP Server 项目,这个项目被命名为 Apache,为了更好的运作这个项目,该组织逐渐发展起 来,成为了今天的 Apache 软件基金会
Apache HTTP Server(简称Apache)
Apache HTTP Server 是一个开源的、跨平台的Web服务器软件,它是最著名的ASF项目之一,广泛用于 互联网上的Web服务器
关系和区别
-
Apache HTTP Server 是 ASF 的一个具体项目,是由ASF托管和支持的
-
ASF 是一个独立的组织,它不仅仅与Apache HTTP Server 有关,还包括其他各种开源项目
-
Apache软件基金会为 Apache HTTP Server 提供法律实体和基础设施支持,同时也支持其他项目
Apache2 特点
apache2 特性
-
高度模块化:core + modules
-
DSO:Dynamic Shared Object 动态加载/卸载
-
MPM:multi-processing module 多路处理模块
apache2 功能
-
虚拟主机:IP,Port,FQDN
-
CGl:Common Gateway lnterface,通用网关接口
-
反向代理
-
负载均衡
-
路径别名
-
丰富的用户认证机制:basic,digest
-
支持第三方模块
apache2-2.4 新特性
-
MPM支持运行为DSO机制,以模块形式按需加载
-
eventMPM生产环境可用
-
异步读写机制
-
支持每模块及每目录的单独日志级别定义
-
每请求相关的专用配置
-
增强版的表达式分析式
-
毫秒级持久连接时长定义
-
基于FQDN的虚拟主机不需要NameVirutalHost指令
-
新指令
-
支持用户自定义变量
-
更低的内存消耗
Apache2 的 MPM 工作模式
在 Apache2 中有三种工作模式,使用者可以根据不同的业务场景来进行选择
prefork 模型
预派生模式,有一个主控制进程,然后生成多个子进程,每个子进程有一个独立的线程响应用户请求, 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数,是最古老的一种模式,也是最稳定的 模式,适用于访问量不是很大的场景
优点:工作稳定
缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
worker 模型
一种多进程和多线程混合的模型,有一个控制进程,启动多个子进程,每个子进程里面包含固定的线 程,使用线程来处理请求,当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线 程处理请求,由于其使用了线程处理请求,因此可以承受更高的并发
优点:相比prefor模型,其占用的内存较少,可以同时处理更多的请求
缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超 时才会被释放。如果过多的线程被这样占据,也会导致在高并发场景下的无服务线程可用。(该问题在 prefork模式下,同样会发生)
event 模型
Apache2 中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型 (epoll),每个进程响应多个请求,在现在版本里的已经是稳定可用的模式,它和worker模式很像,最大 的区别在于,它解决了keepalive场景下,长期被占用的线程的资源浪费问题(某些线程因为被 keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)。event MPM中,会有一个专 门的线程来管理这些keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完 毕后,又允许它释放。这样增强了高并发场景下的请求处理能力
优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理 keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制
Apache2 安装
软件安装
bash
#ubuntu 中安装
[root@ubuntu24 ~]# apt update;apt install apache2 -y
#rocky9 中安装
[root@rocky ~]# yum install httpd -y
#默认启动,己经监听80端口了,在浏览器中直接访问IP,可以看到默认页面
[root@ubuntu24 ~]# ss -tnlp | grep 80
LISTEN 0 511 *:80 *:* users:(("apache2",pid=1575,fd=4),("apache2",pid=1574,fd=4),("apache2",pid=1573,fd=4))
#一个父进程,两个子进程
[root@ubuntu24 ~]# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apache2 1573 root 4u IPv6 17063 0t0 TCP *:http (LISTEN)
apache2 1574 www-data 4u IPv6 17063 0t0 TCP *:http (LISTEN)
apache2 1575 www-data 4u IPv6 17063 0t0 TCP *:http (LISTEN)
#此命令也可以查看
[root@ubuntu24 ~]# pstree -p
管理工具
bash
#服务管理
[root@ubuntu24 ~]# systemctl status apache2.service
● apache2.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: active (running) since Sun 2024-09-08 17:59:17 CST; 2h 29min ago
Docs: https://httpd.apache.org/docs/2.4/
Main PID: 1573 (apache2)
Tasks: 55 (limit: 4556)
Memory: 7.6M (peak: 7.8M)
CPU: 598ms
CGroup: /system.slice/apache2.service
├─1573 /usr/sbin/apache2 -k start
├─1574 /usr/sbin/apache2 -k start
└─1575 /usr/sbin/apache2 -k start
#自带的控制脚本
[root@ubuntu24 ~]# which apachectl
/usr/sbin/apachectl
[root@ubuntu24 ~]# apachectl
Usage: /usr/sbin/apachectl start|stop|restart|graceful|graceful-stop|configtest|status|fullstatus|help
/usr/sbin/apachectl <apache2 args>
/usr/sbin/apachectl -h (for help on <apache2 args>)
[root@ubuntu24 ~]# ll /usr/sbin/apache*
-rwxr-xr-x 1 root root 754232 Jul 18 02:55 /usr/sbin/apache2* #主程序
-rwxr-xr-x 1 root root 7434 Mar 18 20:35 /usr/sbin/apache2ctl* #自带控制脚本
lrwxrwxrwx 1 root root 10 Jul 18 02:55 /usr/sbin/apachectl -> apache2ctl* #自带控制脚本
Apache2 配置和使用
Apache2 配置说明
Apache2 的配置主要分为三部份,分别是全局配置,虚拟主机配置,模块配置,这些配置项分散在不同 的目录和文件中,在主配置文件中以文件包含的形式引用它们
配置文件中每一行包含一个配置指令,并指定值,配置指令不区分大小写,但值区分大小写
以"#"开头的行是注释行,注释不能出现在指令的后边,空白行和指令前的空白字符将被忽略,因此可以 采用缩进以保持配置层次的清晰
bash
#配置文件语法检查
[root@ubuntu24 ~]# apachectl configtest
Syntax OK
[root@ubuntu24 ~]# apachectl -t
Syntax OK
配置文件
bash
#配置目录
[root@ubuntu24 ~]# ll /etc/apache2/
-rw-r--r-- 1 root root 7224 Oct 26 21:44 apache2.conf #主配置文件
drwxr-xr-x 2 root root 4096 Dec 21 14:35 conf-available/ #子配置文件目录
drwxr-xr-x 2 root root 4096 Dec 21 14:35 conf-enabled/ #生效的子配置文件,链接到 conf-available中
-rw-r--r-- 1 root root 1782 May 4 2023 envvars #全局环境变量配置文件
-rw-r--r-- 1 root root 31063 May 4 2023 magic #配合mod_mime_magic模块判断 MIME 类型的配置文件
drwxr-xr-x 2 root root 12288 Dec 21 14:35 mods-available/ #可用的模块配置文件
drwxr-xr-x 2 root root 4096 Dec 21 14:35 mods-enabled/ #生效的模块配置文件,链接到 mods-available中
-rw-r--r-- 1 root root 320 May 4 2023 ports.conf #默认端口配置文件
drwxr-xr-x 2 root root 4096 Dec 21 14:35 sites-available/ #可用的虚拟主机配置文件
drwxr-xr-x 2 root root 4096 Dec 21 14:35 sites-enabled/ #生效的虚似主机配置文件,链接到 sites-available中
#主配置文件中的包含
[root@ubuntu24 html]# cat /etc/apache2/apache2.conf | grep "^Include"
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
#全局配置
[root@ubuntu24 html]# ll -L /etc/apache2/conf-enabled/
total 28
-rw-r--r-- 1 root root 269 Mar 18 20:35 charset.conf #默认编码,全部注释
-rw-r--r-- 1 root root 3178 Mar 18 20:35 localized-error-pages.conf #自定义错误页面,全注释
-rw-r--r-- 1 root root 143 Mar 18 20:35 other-vhosts-access-log.conf #未定义的虚拟主机访问日志
-rw-r--r-- 1 root root 1827 Mar 18 20:35 security.conf #安全设置配置文件
-rw-r--r-- 1 root root 409 Mar 18 20:35 serve-cgi-bin.conf #CGI配置
常用全局配置
主配置文件中的指令对整个服务器都生效,如果只想改变某一部分的配置,则可以把指令嵌入到 <Directory>,<DirectoryMatch>、<Files>,<FilesMatch>,<Location>,<LocationMatch>配置段 中,这样就可以限制指令的作用域为文件系统中的某些位置或特定的URL,这些配置段还可以进行嵌套,以进行更精细的配置
Apache2 还具备同时支持多个站点的能力,称为虚拟主机,配置段中的指令仅对该段中 的特定站点(虚拟主机)有效
虽然大多数指令可以包含在任意的配置段中,但是某些指令仅在某些特定的范围内才有意义,一个指令 可以被作用于哪些配置段中,取决于该指令的作用域
作用域:表示该指令出现在配置文件的什么位置才是合法的
作用域 | 说明 |
---|---|
server config | 该指令全局生效,不能写在<VirtualHost> ,<Directory>,.htAccess 中 |
virtual host | 可以写在<VirtualHost>中 |
directory | 可以写在 <Directory>,<Location>,<Files>,<Proxy> 中 |
.htaccess | 可以写在目录及其子目录的 .htaccess 文件中,但可能会因overrides的设置而不 起作用 |
常用配置项(作用域列说明:S 代表 server config,V 代表 virtual host,D 代表 directory,H 代表 .htaccess)
配置项 | 默认值 | 作用域 | 说明 |
---|---|---|---|
ServerRoot | S | apache2 安装目录 | |
DefaultRuntimeDir | ${APACHE_RUN_DIR} | S | 默认运行时相关文件 目录 |
PidFile | ${APACHE_PID_FILE} | S | PID 文件路径 |
Timeout | 300 | S,V | 连接超时时长 |
KeepAlive | On | S,V | 是否启用持久连接 |
MaxKeepAliveRequests | 100 | S,V | 一个持久连接中最多 可以处理的资源数 |
KeepAliveTimeout | 5 | S,V | 持久连接超时时长 |
User | ${APACHE_RUN_USER} | S | 工作进程属主 |
Group | ${APACHE_RUN_GROUP} | S | 工作进程属组 |
HostnameLookups | Off | S,V,D | 日志中以主机名或IP 地址显示客户端 |
ErrorLog | ${APACHE_LOG_DIR}/error.log | S,V | 错误日志路径 |
LogLevel | warn | S.V.D | 错误日志级别 |
AccessFileName | .htaccess | S,V | 每个目录单独的控制 规则的文件名 |
LogFormat | S,V | 定义不同的日志格式 | |
ServerName | S,V | apache2所在的服务 器名 | |
DocumentRoot | /var/www/html | S,V | 默认内容目录 |
Listen | 80 | S | 默认监听端口 |
ErrorDocument | S, V, D,H | 自定义错误页面 | |
Alias | S, V,D | 路径别名 | |
CustomLog | S,V | 访问日志路径和格式 |
主配置文件
bash
[root@ubuntu24 html]# cat /etc/apache2/apache2.conf | grep -Ev '^#|^$'
DefaultRuntimeDir ${APACHE_RUN_DIR} #默认运行目录
PidFile ${APACHE_PID_FILE} #PID 文件路径
Timeout 300 #超时时长默认300S
KeepAlive On #默认开启keepalive
MaxKeepAliveRequests 100 #keepalive保持的最大连接数
KeepAliveTimeout 5 #keepalive 超时时长5S
User ${APACHE_RUN_USER} #进程属主
Group ${APACHE_RUN_GROUP} #进程属组
HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log #错误日志路径
LogLevel warn #日志级别
IncludeOptional mods-enabled/*.load #文件包含
IncludeOptional mods-enabled/*.conf #文件包含
Include ports.conf #文件包含
<Directory /> #目录权限设置
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share> #目录权限设置
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/> #目录权限设置-默认网站配置,默认 DocumentRoot 是/var/www/html,从此处继承
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
AccessFileName .htaccess #定义htaccess文件
<FilesMatch "^\.ht"> #用正则定义 htaccess 文件权限
Require all denied
</FilesMatch>
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined #日志格式之一
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
IncludeOptional conf-enabled/*.conf #文件包含
IncludeOptional sites-enabled/*.conf
默认虚拟主机配置文件
bash
[root@ubuntu24 html]# cat /etc/apache2/sites-enabled/000-default.conf | grep -Ev "^.*#|^$"
<VirtualHost *:80> #监听本机所有IP 80端口
ServerAdmin webmaster@localhost #管理员邮箱
DocumentRoot /var/www/html #网站根目录,要先授权
ErrorLog ${APACHE_LOG_DIR}/error.log #错误日志
CustomLog ${APACHE_LOG_DIR}/access.log combined #访问日志路径和格式
</VirtualHost>
全局默认页面配置文件
bash
[root@ubuntu24 html]# cat /etc/apache2/mods-enabled/dir.conf #默认主页,第一优先级为 index.html,第二优先级为 index.cgi...
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
默认内容目录
bash
#默认工作目录 /var/www/html,修改默认页面再次测试
[root@ubuntu24 html]# mv index.html index.html.bak
[root@ubuntu24 html]# touch test.txt
[root@ubuntu24 html]# ls
index.html.bak test.txt
#在浏览器中查看,能看到列出了当前目录
Listen 配置监听IP和端口
Listen 选项用来配置Httpd服务监听的IP地址和端口,可以写多条
bash
[root@ubuntu24 html]# cat /etc/apache2/ports.conf
Listen 80
[root@ubuntu24 html]# ss -tnlp | grep apache2
LISTEN 0 511 *:80 *:* users:(("apache2",pid=1472,fd=4),("apache2",pid=1471,fd=4),("apache2",pid=1470,fd=4))
#修改,并重载生效
[root@ubuntu24 ~]# cat /etc/apache2/ports.conf
Listen 127.0.0.1:88
Listen 10.0.0.161:888
Listen 8888
[root@ubuntu24 html]# ss -tnlp |grep apache2
LISTEN 0 511 127.0.0.1:88 0.0.0.0:* users:(("apache2",pid=3184,fd=3),("apache2",pid=3182,fd=3),("apache2",pid=3181,fd=3))
LISTEN 0 511 10.0.0.161:888 0.0.0.0:* users:(("apache2",pid=3184,fd=4),("apache2",pid=3182,fd=4),("apache2",pid=3181,fd=4))
LISTEN 0 511 *:8888 *:* users:(("apache2",pid=3184,fd=6),("apache2",pid=3182,fd=6),("apache2",pid=3181,fd=6))
配置数据压缩
启用 apache2 的数据压缩功能能减少网络IO的数据量,提高服务器的网络吞吐能力
默认己开启数据压缩
bash
#需要模块支持,默认己加载
[root@ubuntu24 ~]# apache2ctl -M | grep deflate
deflate_module (shared)
#压缩规则
[root@ubuntu24 html]# cat /etc/apache2/mods-enabled/deflate.conf
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/wasm
AddOutputFilterByType DEFLATE application/xml
#DeflateCompressionLevel 9 #设置压缩比 9为最高
</IfModule>
ServerTokens 配置响应头中的Server 字段信息
ServerTokens 选项用来配置 HTTP 响应头中的 Server 字段信息,其取值如下
取值 | 效果 | 备注 |
---|---|---|
Full | Server: Apache/2.4.2 (Unix) PHP/4.2.2 MyMod/1.2 | 最详细,默认值 |
OS | Server: Apache/2.4.2 (Unix) | |
Minimal | Server: Apache/2.4.2 | |
Minor | Server: Apache/2.4 | |
Major | Server: Apache/2 | |
Prod | Server: Apache | 最简单,生产环境下使用 |
bash
[root@ubuntu24 html]# vim /etc/apache2/conf-enabled/security.conf
...
ServerTokens Full
...
[root@ubuntu24 html]# systemctl restart apache2
[root@ubuntu24 html]# curl -I 127.1
HTTP/1.1 200 OK
Date: Tue, 10 Sep 2024 02:23:58 GMT
Server: Apache/2.4.58 (Ubuntu) #效果
Last-Modified: Tue, 10 Sep 2024 01:47:59 GMT
ETag: "c-621ba1030fa57"
Accept-Ranges: bytes
Content-Length: 12
Content-Type: text/html
[root@ubuntu24 html]# vim /etc/apache2/conf-enabled/security.conf
...
ServerTokens Prod
...
[root@ubuntu24 html]# systemctl restart apache2
[root@ubuntu24 html]# curl -I 127.1
HTTP/1.1 200 OK
Date: Tue, 10 Sep 2024 02:25:51 GMT
Server: Apache #效果
Last-Modified: Tue, 10 Sep 2024 01:47:59 GMT
ETag: "c-621ba1030fa57"
Accept-Ranges: bytes
Content-Length: 12
Content-Type: text/html
配置持久连接
持久连接是指,建立连接后,每个资源获取完后不会立即断开连接,而是保持一段时间后断开,默认是 开启了持久连接
配合持久连接的有一个时间限制选项,单位为秒,apache2.4之后支持毫秒级设置
对并发量大的服务器,持久连接会使有些请求得不到响应
bash
#默认设置
[root@ubuntu24 ~]# cat /etc/apache2/apache2.conf | grep -vE "^#" | grep
"KeepAlive"
KeepAlive On #默认开启了持久连接
MaxKeepAliveRequests 100 #在一个持久连接内,最多可以累计处理100次请求
KeepAliveTimeout 5 #持久连接保持时间
#示例
[root@ubuntu24 ~]# echo "aaa" > /var/www/html/a.html
[root@ubuntu24 ~]# echo "bbb" > /var/www/html/b.html
[root@ubuntu ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /a.html HTTP/1.1
host: 1.2.3.4
HTTP/1.1 200 OK
Date: Fri, 22 Dec 2023 02:25:09 GMT
Server: Apache
Last-Modified: Fri, 22 Dec 2023 02:13:23 GMT
ETag: "4-60d0fc2c864b7"
Accept-Ranges: bytes
Content-Length: 4
Content-Type: text/html
aaa #第一个资源请求完成,不会断开,可以继续请求第二个资源
GET /b.html HTTP/1.1
host: 1.2.3.4
HTTP/1.1 200 OK
Date: Fri, 22 Dec 2023 02:25:22 GMT
Server: Apache
Last-Modified: Fri, 22 Dec 2023 02:13:17 GMT
ETag: "4-60d0fc26b70d8"
Accept-Ranges: bytes
Content-Length: 4
Content-Type: text/html
bbb #第二个资源
Connection closed by foreign host.
#如果关闭KeepAlive 测试,获取到一个资源后立即断开
[root@ubuntu ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /a.html HTTP/1.1
host: 1.2.3.4
HTTP/1.1 200 OK
Date: Fri, 22 Dec 2023 02:31:54 GMT
Server: Apache
Last-Modified: Fri, 22 Dec 2023 02:13:23 GMT
ETag: "4-60d0fc2c864b7"
Accept-Ranges: bytes
Content-Length: 4
Connection: close
Content-Type: text/html
aaa
Connection closed by foreign host.
定义路径别名
Alias 指令用于在URL 和文件系统之间实现映射,使不在 DocumentRoot 目录下的内容也能成为项目的 一部份
bash
Alias [URL-path] file-path|directory-path
#以URL-path开头的路径在访问时将被映射到后面的文件系统路径,URL-path区分大小写
#作用域 server config, virtual host, directory
AliasPreservePath OFF|ON #此指令配合 Alias 不使用 URL-path 参数时使用,默认值 OFF,作用域同上
#ON 完整映射,每个资源都单独存在
#OFF 整体映射,被命中的资源都映射到同一个资源
#示例
[root@ubuntu ~]# ls /var/www/html/
index.html source
[root@ubuntu ~]# tree /var/www/html/source/
/var/www/html/source/
└── css
└── test.css
1 directory, 1 file
#直接访问
[root@ubuntu ~]# curl http://127.0.0.1/source/css/test.css
body{margin:0;padding:0}
#定义别名,并进行测试
[root@ubuntu ~]# cat /etc/apache2/apache2.conf
Alias "/css/" "/var/www/html/source/css/"
[root@ubuntu ~]# curl http://127.0.0.1/css/test.css
body{margin:0;padding:0}
#别名区分大小写
[root@ubuntu ~]# curl http://127.0.0.1/CSS/test.css
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<address>Apache/2.4.52 (Ubuntu) Server at 127.0.0.1 Port 80</address>
</body></html>
#如果 alias 定义的目录在 DocumentRoot 之外,则需要单独授权,否则不可用
#别名中定义的 URL-path 如果不是以 / 结尾,则后面的 file-path 也不能以 / 结尾
[root@ubuntu ~]# cat /etc/apache2/apache2.con
Alias "/test" "/alias/test"
[root@ubuntu ~]# systemctl restart apache2
#要确保apache2 运行用户对该目录有相应权限
[root@ubuntu ~]# mkdir -pv /alias/test
[root@ubuntu ~]# echo "alias test" > /alias/test/test.html
#提示403,没有权限
[root@ubuntu ~]# curl http://127.0.0.1/test/test.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
<hr>
<address>Apache/2.4.52 (Ubuntu) Server at 127.0.0.1 Port 80</address>
</body></html>
#加权限,再次测试
[root@ubuntu ~]# cat /etc/apache2/apache2.conf | tail
Alias "/test" "/alias/test"
<Directory "/alias/test">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
[root@ubuntu ~]# curl http://127.0.0.1/test/test.html
alias test
#如果在 <Location>, <LocationMatch>等指令中使用 Alias ,则可以省略掉 URL-path 参数
#这种写法仅在 Apache 2.4.19版本及后续版本中支持
<Location "/image">
Alias "/ftp/pub/image"
</Location>
<LocationMatch "/error/(?<NUMBER>[0-9]+)">
Alias "/usr/local/apache/errors/%{env:MATCH_NUMBER}.html"
</LocationMatch>
访问资源控制
bash
#创建文件夹和文件
[root@ubuntu24 ~]# mkdir -pv /data/www;echo "data-index" > /data/www/index.html
mkdir: created directory '/data'
mkdir: created directory '/data/www'
#修改apache2 配置,并重载
[root@ubuntu24 ~]# cat /etc/apache2/apache2.conf
DocumentRoot /data/www/ #指定默认内容目录
<Directory /data/www/> #资源控制
Options Indexes FollowSymLinks #目录选项
AllowOverride None #是否支持 .htaccess 配置规则
Require all granted #访问授权
</Directory>
#测试
[root@ubuntu24 ~]# curl 127.1
data-index
常用配置指令,要写在限定的路径或URL规则下
bash
Options [+|-]option [[+|-]option]
#指定目录选项,可以同时有多个值,作用域 server config, virtual host, directory, .htaccess
#Indexes 显示目录内容列表
#Includes 允许使用 `mod_include`模块提供的服务器端包含功能
#FollowSymLinks 可以跟随软链接,默认值
#SymLinksifOwnerMatch 服务器仅在符号连接与目标文件或目录的所有者具有相同的用户ID时才使用它
#ExecCGI 允许使用 `mod_cgi`模块执行CGI脚本
#Multiviews 允许使用 `mod_negotiation`模块提供内容协商的多重视图
#All 启用除了 MultiViews 之外的所有选项
#None 不支持任何特性
#apache2 允许一个目录被配置多次 Options,如果一个目录被设置了多条Options,则生效的是值后的那条,其它Options 中指定的值不会被合并,如果在值前面使用了 +,则一定被合并 ,- 一定被去除,但符号不要混搭使用,使用-IncludesNOEXEC或-Includes时,不论前面如何设置,都会完全禁用服务器端包含
#示例
<Directory /path/>
Options Includes FollowSymLinks #这条无效,被下面的覆盖
Options Indexes #这条生效
<Directory /path/>
<Directory /path/>
Options +Indexes
Options +Includes +FollowSymLinks #三个值都生效,并集
<Directory /path/>
AllowOverride All|None|directive-type [directive-type] ...
#作用域 directory
#允许在 .htaccess 文件中指定的指令类型,文件名不一定是 .htaccess,由AccessFileName 选项指定
#仅在不包含正则表达式的<Directory>配置段中才是有效的
#在<Location>, <DirectoryMatch>, <Files>配置段中都是无效的
#ALL 所有指令都可以在 .htaccess 文件中生效
#None 不使用 .htaccess 文件中的指令
#directive-type可以是下列各组指令之一,AuthConfig,FileInfo,Indexes,Limit,Options[=Option,...]
#AllowOverride AuthConfig 只能在 .htaccess 文件中配置 AuthConfig 相关指令
#AllowOverride Options=FollowSmlinks Indexes 可以在 .htaccess 文件中配置 FollowSmlinks Indexes
Require [not] entity-name [entity-name] ...
#作用域 directory, .htaccess
#用于指定哪些用户允许访问哪些资源
#某些情况下需要配合AuthName,AuthType,AuthUserFile,AuthGroupFile指令一起使用
#Require all granted 所有用户都可以访问
#Require all denied 所有用户都不可以访问
#Require method http-method [http-method] ... 特定请请求方法可以访问
#Require user userid [userid] ... 特定用户可以访问
#Require group group-name [group-name] ... 特定组中的用户可以访问
#Require valid-user 所有有效用户可以访问
#Require ip 10 172.20 192.168.2 指定IP可以访问
#Require forward-dns dynamic.example.org 指定主机名或域名可以访问
从语法上看,允许在 <Directory>段中使用的指令当然也可以在 <DirectoryMatch>,<Files>,<FilesMatch> ,<Location>,<LocationMatch>,<Proxy>,<ProxyMatch>段中使用,但也有例外:
-
AllowOverride 指令只能出现在 段中
-
Options指令不能用于 <Files>和 <FilesMatch> 段
-
Options 中的 FollowSymLinks 和 SymLinksIfOwnerMatch 只能出现在 段或者 .htaccess 文件中
基于文件系统路径的访问控制
bash
#基于目录-路径匹配
<Directory "/path">
#...
</Directory>
#基于目录-扩展正则匹配
<Directory ~ "regex">
#...
</Directory>
#基于目录-扩展正则匹配
<DirectoryMatch "regex">
#...
</DirectoryMatch>
#基于文件-文件路径匹配
<Files "/path/file">
#...
</Files>
#基于文件-通配符匹配
<Files "/path/*file*">
#...
</Files>
#基于文件-扩展正则匹配
<Files ~ "regex">
#...
</Files>
#基于正则表达式-扩展正则
<FilesMatch "regex">
#...
</FilesMatch>
基于URL路径的访问控
bash
#基于URL路径
<Location "/URL">
# ...
</Location>
#基于URL路径-扩展正则
<Location ~ "regex">
#...
</Location>
#基于URL路径-扩展正则
<LocationMatch "regex">
# ...
</LocationMatch>
示例
bash
#基于路径控制
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
#基于正则,文件后缀名控制
<FilesMatch "^\.ht"> #默认不给用户显示 .htaccess,该文件用来配置访问规则
Require all denied
</FilesMatch>
#基于正则,文件后缀名控制
<FilesMatch ".+\.(gif|jpe?g|png)$">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</FilesMatch>
#基于URL路径控制
<Location "/dira">
Require all granted
</Location>
#基于正则,URL路径控制
<LocationMatch "/dira/.+\.txt$">
Require all denied
</LocationMatch>
控制特定主机的访问
bash
#控制特定IP访问
RequireAll #允许所有客户端,拒绝指定主机,拒绝优先,作用域 directory, .htaccess
RequireAny #拒绝所有客户端,允许指定主机,允许优先,作用域 directory, .htaccess
#示例
<Directory "/data/www/dira/">
<RequireAll>
Require all granted #允许所有客户端
Require not ip 10.0.0.157 #拒绝 10.0.0.157,可以写成网段
</RequireAll>
</Directory>
<Directory "/data/www/dirb/">
<RequireAny>
Require all denied #拒绝所有客户端
Require ip 10.0.0.157 #允许10.0.0.157,可以写成网段
</RequireAny>
</Directory>
使用 .htaccess 设置配置
.htaccess 文件(或者"分布式配置文件")提供了针对每个目录改变配置的方法,即在一个特定的目录中 放置一个包含指令的文件,其中的指令作用于此目录及其所有子目录,.htaccess 中的内容发生了变化, 会直接生效,不需要重载或重启 Aapche2(这会导致性能问题),如果不想使用 .htaccess 作为配置 文件名,可以用 AccessFileName 指令来改变
如果不能确定某个指令是否可以用于 .htaccess 文件,可以在文档中查看该指令的作用域
bash
[root@ubuntu ~]# cat /etc/apache2/apache2.conf
....
<Location "/data/www/dirb/">
AllowOverride All #dirb 中的 .htaccess 并不生效,因为AllowOverride 指令只能出现在<Directory> 段中
Require all granted
</Location>
#修改为
<Directory "/data/www/dirb/">
AllowOverride All #允许所有规则都可以写在 .htaccess 文件中
Require all granted
</Directory>
虽然 .htaccess 文件可以分别为不同的目录配置规则,但在实践中尽量避免使用,原因如下:
-
首先是性能问题:如果 AllowOverride 启用了 .htaccess 文件,则 Apache2 需要在每个目录中查 找 .htaccess 文件,另外,每一次请求,都需要读取一次 .htaccess 文件
-
其次还是性能问题:在启用 .htaccess 文件后,如果客户端访问的资源路径较深,则 apache2 需要 读取上级目录中的 .htaccess 文件,因为要保证所有的指令生效
-
另外还有安全问题:如果使用 .htaccess 文件,则意味着允许apache2用户能自由的修改服务器配 置
日志配置
apache2中的日志主要包括错误日志和访问日志两类
bash
#主配置文件-错误日志路径,级别,定义可用的日志格式
[root@ubuntu apache2]# cat apache2.conf | grep -i log | grep -Ev '^#'
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn #定义错误日志级别
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\""
vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\""
combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
User-agent #用户代理,浏览器头
Referer #前一个页面,表示是从哪一个页面跳转过来的
man 3 strftime #时间格式相关帮助
#没有被虚拟主机配置命中的访问的访问日志
[root@ubuntu apache2]# cat conf-enabled/other-vhosts-access-log.conf | grep -Ev '^$|^#'
CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log vhost_combined
#默认虚拟主机日志配置
[root@ubuntu apache2]# cat sites-enabled/000-default.conf | grep -i log | grep -Ev '^.*#'
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#默认日志
[root@ubuntu ~]# ls /var/log/apache2/*log
/var/log/apache2/access.log
/var/log/apache2/error.log
/var/log/apache2/other_vhosts_access.log
自定义访问日志格式并使用
bash
#在/etc/apache2/apache2.conf 中增加日志格式定义
LogFormat "%h %l %u test-format %{User-agent}i" test-format
#修改 /etc/apache2/conf-enabled/other-vhosts-access-log.conf
CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log test-format
#重载,测试,查看日志
[root@ubuntu ~]# tail -1 /var/log/apache2/other_vhosts_access.log
127.0.0.1 - - test-format curl/7.81.0
状态页配置
bash
#状态页需要相关模块支持
[root@ubuntu ~]# apachectl -M | grep status
status_module (shared)
#默认己开启了状态页配置
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/status.load
LoadModule status_module /usr/lib/apache2/modules/mod_status.so
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/status.conf | grep -Ev "^.*#|^$"
<IfModule mod_status.c>
<Location /server-status> #可以自定义路径
SetHandler server-status #由此处决定上一行中定义的地址是查看状态
Require local #但默认只能本地访问,修改此处为 all granted,在浏览器中进行测试
</Location>
ExtendedStatus On #详细显示
<IfModule mod_proxy.c>
ProxyStatus On
</IfModule>
</IfModule>
虚拟主机配置
apache2 服务支持在一台物理服务器上配置多个网站,我们可以通过虚拟主机配置来实现该功能
在 apache2 服务中配置了虚拟主机,还需要在DNS解析中添加域名解析,将域名指向 apache2 服务器 所在的IP地址
DNS 解析负责将域名解析到 apache2 服务器上,虚拟主机配置负责区分不同的网站,将不同的域名与 内容分别对应起来
多虚拟主机的实现方式
-
基于端口实现:用不同的端口标识不同的虚拟主机
-
基于IP实现:用不同的IP地址标识不同的虚拟主机
-
基于域名实现:用不同的域名标识不同的虚拟主机
bash
#默认虚拟主机配置
[root@ubuntu24 www]# ls -lh /etc/apache2/sites-enabled/
total 0
lrwxrwxrwx 1 root root 35 Sep 7 19:05 000-default.conf -> ../sites-available/000-default.conf
[root@ubuntu24 www]# cat /etc/apache2/sites-enabled/000-default.conf | grep -Ev "^.*#|^$"
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
#确认主配置文件
[root@ubuntu24 www]# cat /etc/apache2/apache2.conf
ServerName ubuntu
DocumentRoot /data/www/
<Directory /data/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
[root@ubuntu24 apache2]# cd /data/www/
[root@ubuntu24 www]# mkdir web{1,2,3}
[root@ubuntu24 www]# ls
web1 web2 web3
[root@ubuntu24 www]# for i in {1..3};do echo "web-$i" > /data/www/web$i/index.html;done
#在浏览器中测试,还是走到默认的 /var/www/html 中了,因为请求被默认的虚拟主机配置命中
[root@ubuntu ~]# curl 127.1
配置基于端口区分的虚拟主机
bash
[root@ubuntu24 ~]# cat /etc/apache2/sites-enabled/vhost.conf
Listen 81
Listen 82
Listen 83
<virtualhost *:81>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost *:82>
DocumentRoot /data/www/web2/
ServerName www.b.com
CustomLog "${APACHE_LOG_DIR}/access_www.b.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost *:83>
DocumentRoot /data/www/web3/
ServerName www.c.com
CustomLog "${APACHE_LOG_DIR}/access_www.c.log" combined
<Directory /data/www/web3/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
#重启服务
[root@ubuntu24 sites-enabled]# systemctl restart apache2
#查看监听端口
[root@ubuntu24 sites-enabled]# ss -tnlp | grep apache2
LISTEN 0 511 *:81 *:* users:(("apache2",pid=4786,fd=6),("apache2",pid=4784,fd=6),("apache2",pid=4783,fd=6))
LISTEN 0 511 *:80 *:* users:(("apache2",pid=4786,fd=4),("apache2",pid=4784,fd=4),("apache2",pid=4783,fd=4))
LISTEN 0 511 *:83 *:* users:(("apache2",pid=4786,fd=10),("apache2",pid=4784,fd=10),("apache2",pid=4783,fd=10))
LISTEN 0 511 *:82 *:* users:(("apache2",pid=4786,fd=8),("apache2",pid=4784,fd=8),("apache2",pid=4783,fd=8))
#测试
[root@ubuntu24 sites-enabled]# curl 127.1 #默认就是80
Hello World
[root@ubuntu24 sites-enabled]# curl 127.1:81
web-1
[root@ubuntu24 sites-enabled]# curl 127.1:82
web-2
[root@ubuntu24 sites-enabled]# curl 127.1:83
web-3
[root@ubuntu24 sites-enabled]# curl 127.1:80
Hello World
配置基于IP区分的虚拟主机
bash
#添加IP地址
[root@ubuntu ~]# ip a a 10.0.0.80/24 dev ens33
[root@ubuntu ~]# ip a a 10.0.0.81/24 dev ens33
[root@ubuntu ~]# ip a a 10.0.0.82/24 dev ens33
[root@ubuntu ~]# ip a a 10.0.0.83/24 dev ens33
[root@ubuntu ~]# ip a s ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
group default qlen 1000
link/ether 00:0c:29:84:27:78 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.210/24 brd 10.0.0.255 scope global dynamic noprefixroute ens33
valid_lft 1599sec preferred_lft 1599sec
inet 10.0.0.80/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet 10.0.0.81/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet 10.0.0.82/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet 10.0.0.83/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe84:2778/64 scope link
valid_lft forever preferred_lft forever
#修改 hosts文件,绑定域名和IP
[root@ubuntu ~]# cat /etc/hosts
10.0.0.81 www.a.com
10.0.0.82 www.b.com
10.0.0.83 www.c.com
#修改配置文件,以IP地址来区分
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/vhost.conf
<virtualhost 10.0.0.81:80>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost 10.0.0.82:80>
DocumentRoot /data/www/web2/
ServerName www.b.com
CustomLog "${APACHE_LOG_DIR}/access_www.b.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost 10.0.0.83:80>
DocumentRoot /data/www/web3/
ServerName www.c.com
CustomLog "${APACHE_LOG_DIR}/access_www.c.log" combined
<Directory /data/www/web3/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/000-default.conf
<VirtualHost 10.0.0.80:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
[root@ubuntu ~]# apachectl -t
Syntax OK
[root@ubuntu ~]# systemctl reload apache2
#测试
[root@ubuntu ~]# curl 10.0.0.80
hello world
[root@ubuntu ~]# curl 10.0.0.81
web-1
[root@ubuntu ~]# curl 10.0.0.82
web-2
[root@ubuntu ~]# curl 10.0.0.83
web-3
配置基于域名区分的虚拟主机
bash
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/vhost.conf
<virtualhost *:80>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost *:80>
DocumentRoot /data/www/web2/
ServerName www.b.com
CustomLog "${APACHE_LOG_DIR}/access_www.b.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<virtualhost *:80>
DocumentRoot /data/www/web3/
ServerName www.c.com
CustomLog "${APACHE_LOG_DIR}/access_www.c.log" combined
<Directory /data/www/web3/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
[root@ubuntu24 sites-enabled]# systemctl reload apache2.service
[root@ubuntu24 sites-enabled]# vim /etc/hosts #添加一下域名和IP
10.0.0.161 www.a.com www.b.com www.c.com
#测试
[root@ubuntu ~]# curl 127.1
hello world
[root@ubuntu24 sites-enabled]# curl www.a.com
web-1
[root@ubuntu24 sites-enabled]# curl www.b.com
web-2
[root@ubuntu24 sites-enabled]# curl www.c.com
web-3
#如果没有默认配置,直接访问IP会锚定web-1,如果web-2在前,是web-2生效
[root@ubuntu ~]# mv /etc/apache2/sites-enabled/000-default.conf{,bak}
[root@ubuntu ~]# systemctl reload apache2
[root@ubuntu ~]# curl 127.1
web-1
[root@ubuntu24 sites-enabled]# curl -v www.a.com
* Host www.a.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.0.0.161
* Trying 10.0.0.161:80...
* Connected to www.a.com (10.0.0.161) port 80
> GET / HTTP/1.1
> Host: www.a.com #默认情况下,请求头中的host参数和请求域名一样
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 10 Sep 2024 06:46:53 GMT
< Server: Apache/2.4.58 (Ubuntu)
< Last-Modified: Tue, 10 Sep 2024 03:30:10 GMT
< ETag: "6-621bb7da277da"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html
<
web-1
* Connection #0 to host www.a.com left intact
[root@ubuntu24 sites-enabled]# curl -v -H "host:www.b.com" www.a.com
* Host www.a.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.0.0.161
* Trying 10.0.0.161:80...
* Connected to www.a.com (10.0.0.161) port 80
> GET / HTTP/1.1
> Host:www.b.com #apache2 中以 host参数值为区分不同虚拟主机
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 10 Sep 2024 06:49:02 GMT
< Server: Apache/2.4.58 (Ubuntu)
< Last-Modified: Tue, 10 Sep 2024 03:30:10 GMT
< ETag: "6-621bb7da277da"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html
<
web-2
* Connection #0 to host www.a.com left intact
可以使用多重因素将某域名绑定到特定IP的特定端口
bash
Listen 88
<virtualhost 10.0.0.123:88>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
错误页面配置
在 HTTP 协议中,响应报文都有相应的状态码,其中 200 表示正确返回,其它状态码都表示错误,可以 在Apache2 中设置根据不同的状态码设置不同的错误页面,也可以在虚拟主机的配置中为每个网站设置 不同的错误页面
bash
ErrorDocument error-code document #根据http状态码定义不同的错误输出
error-code #3位数错误状态码
document #错误码对应的输出,字符串|本地页面路径|外部URL|default
#如果使用外部URL,Apache2 服务器将向客户端返回302重定向状态码
#default 用来恢复默认设置
#作用域 server config, virtual host, directory, .htaccess
#设置全局错误页面-字符串
[root@ubuntu ~]# cd /etc/apache2/
[root@ubuntu apache2]# cat apache2.conf
ErrorDocument 403 "<h1>sorry!</h1> permission denied"
ErrorDocument 404 "sorry! your page not found"
#重启服务器,在浏览器中测试
[root@ubuntu apache2]# systemctl restart apache2
#设置全局错误页面-重定向
[root@ubuntu apache2]# cat apache2.conf
Alias "/error/" "/var/www/html/error/"
ErrorDocument 403 "/error/403.html"
ErrorDocument 404 https://www.bilibili.com/fniuohfi
[root@ubuntu apache2]# cat /var/www/html/error/403.html
<h1>sorry!</h1> permission denied
#重启服务器,在浏览器中测试
[root@ubuntu apache2]# systemctl restart apache2
#虚拟主机中单独配置
[root@ubuntu apache2]# cat sites-enabled/www.a.com.conf
<virtualhost *:80>
DocumentRoot /var/www/html/www.a.com/
ServerName www.a.com
ErrorDocument 403 "<h1>sorry!</h1> permission denied" #虚拟主机中不写,将使用全局配置
ErrorDocument 404 "sorry! your page not found" #如果值为 default 将恢复成 apache2 默认页面
ProxyErrorOverride On #保证PHP 的错误页面也能与设置中的保持一致
CustomLog "${APACHE_LOG_DIR}/access_www.a.com.log" combined
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"
</FilesMatch>
<Directory /var/www/html/www.a.com/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
#重启服务器,在浏览器中测试
#使用服务器IP访问将使用全局配置
#使用域名访问将使用虚拟主机中配置
[root@ubuntu apache2]# systemctl restart apache2
访问验证配置
bash
AuthType None|Basic|Digest|Form #用户认证类型,不同的值需要有不同的模块支持,作用域 directory, .htaccess
htpasswd [opt...] passwordfile username
htpasswd [opt...] passwordfile username password
#常用选项
c #创建新文件
n #不更新文件,在终端中显示
b #从命令行接受密码
i #从标准输入接受密码
m #密码使用MD5加密算法,默认
p #不加密密码,直接明文保存
D #删除指定用户
v #验证指定用户密码
#创建认证用户,新文件用 -c 选项
[root@ubuntu ~]# htpasswd -c /usr/share/apache2/apache2-pwd tom
New password:
Re-type new password:
Adding password for user tom
[root@ubuntu ~]# htpasswd /usr/share/apache2/apache2-pwd jerry
New password:
Re-type new password:
Adding password for user jerry
[root@ubuntu ~]# htpasswd /usr/share/apache2/apache2-pwd spike
New password:
Re-type new password:
Adding password for user spike
#默认己经加载了 auth_basic 认证模块
[root@ubuntu24 ~]# apachectl -M | grep auth_
auth_basic_module (shared)
[root@ubuntu24 ~]# cd /etc/apache2
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
AuthType Basic #基础认证
AuthName "Pls Input your name and pwd" #登录提示语,大部份浏览器不支持
AuthBasicProvider file #从文件中验证
AuthUserFile "/usr/share/apache2/apache2-pwd" #指定认证文件
Require user tom jerry #可以登录的用户
</Directory>
#重启服务,在浏览器中测试
[root@ubuntu24 apache2]# systemctl restart apache2.service
模块配置和工作模式配置
bash
#列出所有己加载的模块,包括核心模块和用配置文件加载的模块
[root@ubuntu24 apache2]# apachectl -M
Loaded Modules:
core_module (static)
so_module (static)
watchdog_module (static)
http_module (static)
log_config_module (static)
logio_module (static)
version_module (static)
unixd_module (static)
access_compat_module (shared)
alias_module (shared)
auth_basic_module (shared)
authn_core_module (shared)
authn_file_module (shared)
authz_core_module (shared)
authz_host_module (shared)
authz_user_module (shared)
autoindex_module (shared)
deflate_module (shared)
dir_module (shared)
env_module (shared)
filter_module (shared)
mime_module (shared)
mpm_event_module (shared)
negotiation_module (shared)
reqtimeout_module (shared)
setenvif_module (shared)
status_module (shared)
#列出所有核心模块,默认就有,不用配置文件加载的模块
[root@ubuntu24 apache2]# apachectl -l
Compiled in modules:
core.c
mod_so.c
mod_watchdog.c
http_core.c
mod_log_config.c
mod_logio.c
mod_version.c
mod_unixd.c
#先引用所有 load 文件,再引用所有 conf 文件
[root@ubuntu ~]# cat /etc/apache2/apache2.conf | grep "IncludeOptional mods-enabled"
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
#load 文件中定义要加载某个模块
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/status.load
LoadModule status_module /usr/lib/apache2/modules/mod_status.so
#与其同名的conf 文件定义如果加载了某个模块,则做哪些设置,load 文件与 conf 文件不是一对一
[root@ubuntu24 apache2]# cat /etc/apache2/mods-enabled/status.conf | grep -Ev "^.*#|^$"
<Location /server-status>
SetHandler server-status
Require all granted
</Location>
ExtendedStatus On
<IfModule mod_proxy.c>
ProxyStatus On
</IfModule>
#禁用模块
[root@ubuntu ~]# apache2ctl -M | grep "status"
#禁用模块,重载
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/status.load
#LoadModule status_module /usr/lib/apache2/modules/mod_status.so
[root@ubuntu ~]# systemctl reload apache2.service
#再次查看,己经没有该模块了
[root@ubuntu ~]# apache2ctl -M | grep "status"
#当前工作模式
[root@ubuntu ~]# ls /etc/apache2/mods-enabled/mpm*.load
/etc/apache2/mods-enabled/mpm_event.load
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/mpm_event.load
# Conflicts: mpm_worker mpm_prefork
LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so
当前工作模式
bash
[root@ubuntu ~]# ls /etc/apache2/mods-enabled/mpm*.load
/etc/apache2/mods-enabled/mpm_event.load
[root@ubuntu ~]# cat /etc/apache2/mods-enabled/mpm_event.load
# Conflicts: mpm_worker mpm_prefork
LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so
#当前是event模型
[root@ubuntu ~]# ps aux | grep apache2
root 91738 0.0 0.2 6776 5408 ? Ss 12:50 0:00
/usr/sbin/apache2 -k start
www-data 92386 0.0 0.2 1211736 4736 ? Sl 13:42 0:00
/usr/sbin/apache2 -k start
www-data 92387 0.0 0.2 1211736 4736 ? Sl 13:42 0:00
/usr/sbin/apache2 -k start
evnet 模型配置
bash
#event 模型默认配置
[root@ubuntu ~]# cat /etc/apache2/mods-available/mpm_event.conf | grep -Ev "#|^$"
<IfModule mpm_event_module>
StartServers 2 #服务启动时默认开启的工作进程数量
MinSpareThreads 25 #最小空闲线程数
MaxSpareThreads 75 #最大空闲线程数
ThreadLimit 64 #每个工作进程最大能开启的线程数量
ThreadsPerChild 25 #每个工作进程开启的工作线程数量
MaxRequestWorkers 150 #允许启动的最大工作线程数
MaxConnectionsPerChild 0 #工作进程最多能处理多少个请求,一个工作进程处理一定数量的请求后,该进程会被父进程终止
</IfModule>
prefork 模型配置
bash
#prefork 模型默认配置
[root@ubuntu ~]# cat /etc/apache2/mods-available/mpm_prefork.conf | grep -Ev "#|^$"
<IfModule mpm_prefork_module>
StartServers 5 #服务启动时默认开启的工作进程数量
MinSpareServers 5 #最小空闲进程数
MaxSpareServers 10 #最大空闲进程数
MaxRequestWorkers 150 #允许启动的最大工作进程数
MaxConnectionsPerChild 0 #工作进程最多能处理多少个请求,一个工作进程处理一定数量的请求后,该进程会被父进程终止
</IfModule>
work 模型配置
bash
#work 模型默认配置
[root@ubuntu ~]# cat /etc/apache2/mods-available/mpm_worker.conf | grep -Ev "#|^$"
<IfModule mpm_worker_module>
StartServers 2 #服务启动时默认开启的工作进程数量
MinSpareThreads 25 #最小空闲线程数
MaxSpareThreads 75 #最大空闲线程数
ThreadLimit 64 #每个工作进程最大能开启的线程数量
ThreadsPerChild 25 #每个工作进程开启的工作线程数量
MaxRequestWorkers 150 #允许启动的最大工作线程数
MaxConnectionsPerChild 0 #工作进程最多能处理多少个请求,一个工作进程处理一定数量的请求后,该进程会被父进程终止
</IfModule>
修改工作模式
bash
#当前工作模式是 evnet 模型
[root@ubuntu ~]# ls /etc/apache2/mods-enabled/mpm_*load
/etc/apache2/mods-enabled/mpm_event.load
#可用工作模式
[root@ubuntu ~]# ll /etc/apache2/mods-available/mpm_*load
-rw-r--r-- 1 root root 106 May 4 2023 /etc/apache2/mods-available/mpm_event.load
-rw-r--r-- 1 root root 108 May 4 2023 /etc/apache2/mods-available/mpm_prefork.load
-rw-r--r-- 1 root root 107 May 4 2023 /etc/apache2/mods-available/mpm_worker.load
#修改工作模式,删除旧的,创建新的
[root@ubuntu ~]# cd /etc/apache2/mods-enabled/
[root@ubuntu mods-enabled]# rm mpm_event.load
[root@ubuntu mods-enabled]# rm mpm_event.conf
[root@ubuntu mods-enabled]# ln -sv ../mods-available/mpm_prefork.load ./mpm_prefork.load
'./mpm_prefork.load' -> '../mods-available/mpm_prefork.load'
[root@ubuntu mods-enabled]# ln -sv ../mods-available/mpm_prefork.conf ./mpm_prefork.conf
'./mpm_prefork.conf' -> '../mods-available/mpm_prefork.conf'
#默认5个工作进程
[root@ubuntu ~]# ps aux | grep apache2
root 92720 0.0 0.2 6488 4396 ? Ss 15:16 0:00
/usr/sbin/apache2 -k start
www-data 92721 0.0 0.2 6820 4032 ? S 15:16 0:00
/usr/sbin/apache2 -k start
www-data 92722 0.0 0.2 6820 4032 ? S 15:16 0:00
/usr/sbin/apache2 -k start
www-data 92723 0.0 0.2 6820 4032 ? S 15:16 0:00
/usr/sbin/apache2 -k start
www-data 92724 0.0 0.2 6820 4032 ? S 15:16 0:00
/usr/sbin/apache2 -k start
www-data 92725 0.0 0.2 6820 4032 ? S 15:16 0:00
/usr/sbin/apache2 -k start
Apache2 实现 Https 访问
Apache2 中的默认 SSL 配置
bash
#ssl 功能需要相关模块支持,默认没有加载此模块
[root@ubuntu ~]# apachectl -M | grep ssl
[root@ubuntu24 apache2]# ll /etc/apache2/mods-available/ | grep ssl
-rw-r--r-- 1 root root 3129 Mar 18 20:35 ssl.conf
-rw-r--r-- 1 root root 88 Mar 18 20:35 ssl.load
#启用模块,两个模块,一个配置文件
[root@ubuntu24 mods-enabled]# ln -sv ../mods-available/ssl.conf ./ssl.conf
'./ssl.conf' -> '../mods-available/ssl.conf'
[root@ubuntu24 mods-enabled]# ln -sv ../mods-available/ssl.load ./ssl.load
'./ssl.load' -> '../mods-available/ssl.load'
[root@ubuntu24 mods-enabled]# ln -sv ../mods-available/socache_shmcb.load ./socache_shmcb.load
'./socache_shmcb.load' -> '../mods-available/socache_shmcb.load'
#添加虚拟主机配置
[root@ubuntu24 mods-enabled]# cd /etc/apache2/sites-enabled/
[root@ubuntu24 sites-enabled]# ln -sv ../sites-available/default-ssl.conf ./default-ssl.conf
'./default-ssl.conf' -> '../sites-available/default-ssl.conf'
[root@ubuntu24 sites-enabled]# systemctl restart apache2.service
#查看端口,可以看到 apache2监听了80和443
[root@ubuntu24 sites-enabled]# ss -tnlp | grep apache
LISTEN 0 511 *:443 *:* users:(("apache2",pid=6092,fd=6),("apache2",pid=6091,fd=6),("apache2",pid=6089,fd=6))
LISTEN 0 511 *:80 *:* users:(("apache2",pid=6092,fd=4),("apache2",pid=6091,fd=4),("apache2",pid=6089,fd=4)
#监听配置
[root@ubuntu24 sites-enabled]# cat /etc/apache2/ports.conf | grep -Ev "^.*#|^$"
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
#默认虚拟主机配置
[root@ubuntu24 sites-enabled]# cat /etc/apache2/sites-enabled/default-ssl.conf | grep -Ev "^.*#|^$"
<VirtualHost *:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem #SSL证书文件
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key #私钥文件
#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt SSL证书链文件,上级CA证书
#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt #顶级CA证书文件,与上面证链文件二选一
<FilesMatch "\.(?:cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
#ssl模块配置文件
[root@ubuntu24 apache2]# cat /etc/apache2/mods-enabled/ssl.conf | grep -Ev "^.*#|^$"
SSLRandomSeed startup builtin
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect builtin
SSLRandomSeed connect file:/dev/urandom 512
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
SSLSessionCacheTimeout 300
SSLCipherSuite HIGH:!aNULL
SSLProtocol all -SSLv3
SSLSessionTickets off
#相关证书文件己自动生成
[root@ubuntu24 apache2]# ll /etc/ssl/certs/ssl-cert-snakeoil.pem
-rw-r--r-- 1 root root 1086 Aug 27 09:34 /etc/ssl/certs/ssl-cert-snakeoil.pem
[root@ubuntu24 apache2]# ll /etc/ssl/private/ssl-cert-snakeoil.key
-rw-r----- 1 root ssl-cert 1704 Aug 27 09:34 /etc/ssl/private/ssl-cert-snakeoil.key
#查看,使用者和签发者都是当前主机,属于自签证书
[root@ubuntu24 ~]# openssl x509 -in /etc/ssl/certs/ssl-cert-snakeoil.pem -noout -text
#在浏览器中通过https访问,提示不安全
自签证书实现多域名 Https
bash
#安装软件
[root@ubuntu24 apache2]# apt install easy-rsa -y
[root@ubuntu24 apache2]# cd /usr/share/easy-rsa/
#初始化证书目录
[root@ubuntu24 easy-rsa]# ./easyrsa init-pki
[root@ubuntu24 easy-rsa]# tree pki
pki
├── inline
├── openssl-easyrsa.cnf
├── private
└── reqs
4 directories, 1 file
#生成CA机构证书,不使用密码
[root@ubuntu24 easy-rsa]# ./easyrsa build-ca nopass
No Easy-RSA 'vars' configuration file exists!
Using SSL:
* openssl OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
...+.....+.+...+......+.....+......+.............+...+.....+...+......+.+.....+.........+.+.........+..............+.+........+...+...+.+......+..+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+...+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..........+.....................+......+..+.+.....+....+..+...+...+...+..........+.....+.......+..................+.....+.+......+..+.+......+.........+.................+.........+.+..............+......+.........+...+............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..+.+......+.....+.+.........+......+............+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+.................+.+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..+..........+...+...........+......+....+..............+..........+.....+......+.+.....+.+..+.............+...+..+...+............+...+.+.....+......+.......+...+............+........+..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:a3
Notice
------
CA creation complete. Your new CA certificate is at:
* /usr/share/easy-rsa/pki/ca.crt
#生成 a.com 的私钥和证书申请文件
[root@ubuntu24 easy-rsa]# ./easyrsa gen-req a.com.server nopass
...
Your files are:
* req: /usr/share/easy-rsa/pki/reqs/a.com.server.req
* key: /usr/share/easy-rsa/pki/private/a.com.server.key
#签发证书
[root@ubuntu24 easy-rsa]# ./easyrsa sign-req server a.com.server
...
Certificate created at:
* /usr/share/easy-rsa/pki/issued/a.com.server.crt
配置虚拟主机
bash
[root@ubuntu24 ~]# cat /etc/apache2/sites-enabled/www.a.com.conf
<virtualhost *:80>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
<VirtualHost *:443>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
SSLEngine on
SSLCertificateFile /usr/share/easy-rsa/pki/issued/a.com.server.crt
SSLCertificateKeyFile /usr/share/easy-rsa/pki/private/a.com.server.key
SSLCACertificateFile /usr/share/easy-rsa/pki/ca.crt
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
#重启服务
[root@ubuntu24 sites-enabled]# systemctl reload apache2.service
#在客户端配置 hosts 文件,并在浏览器中分别测试不同域名的 http,https 协议
在公有云中配置 Https 域名
我们以阿里云为例
-
提交证书申请
-
设置域名解析记录,确保申请者有该域名的解析权限
-
等待签发证书
-
创建ECS实例,安装apache软件,配置web目录
-
绑定公网IP,并创建DNS解析
-
签发完成后在ECS实例中部署SSL证书(也可以部署到其它产品中)
-
在浏览器中测试
Apache2 中实现URL重定向
URL 重定向的两种方式
URL 重定向(URL redirection)
URL 重定向是指将客户端请求从一个 URL 地址转移到另外一个 URL 地址的 WEB 服务器技术,这两个 URL 地址可以是同一个域名下的不同资源,也可以是不同的域名
其具体实现原理是当客户端访问某个 URL 时,服务器会返回一个特定状态码及新的 URL地址,客户端根 据服务器的返回数据去请求新的URL地址
URL 重定向的分类
-
301(Moved Permanently):永久重定向,服务器向客户端发送指令,告诉客户端当前请求的 URL 被永久的重定向到其它的URL,客户端下次请求该资源应该使用新的 URL
-
302(Moved Temporarily):临时重定向,服务器向客户端发送指令,告诉客户端当前请求的 URL 被临时重定向到其它的URL,客户端下次请求该资源还可以继续使用原来的 RUL
生产环境中常见的URL重定向
bash
[root@ubuntu24 sites-enabled]# curl -v www.taobao.com
* Host www.taobao.com:80 was resolved.
* IPv6: 240e:928:201:1d00:3::7de, 240e:928:201:1d00:3::7df
* IPv4: 180.213.179.194, 180.213.179.193
* Trying 180.213.179.194:80...
* Connected to www.taobao.com (180.213.179.194) port 80
> GET / HTTP/1.1
> Host: www.taobao.com
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: Tengine
< Date: Tue, 10 Sep 2024 09:05:47 GMT
< Content-Type: text/html
< Content-Length: 262
< Connection: keep-alive
< Location: https://www.taobao.com/
< Via: ens-cache9.cn7307[,0]
< Timing-Allow-Origin: *
< EagleId: b4d5b39d17259591476744322e
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<h1>301 Moved Permanently</h1>
<p>The requested resource has been assigned a new permanent URI.</p>
<hr/>Powered by Tengine</body>
</html>
* Connection #0 to host www.taobao.com left intact
URL 重定向的实现
bash
#指令格式,作用域 server config, virtual host, directory, .htaccess
Redirect [status] URL-path URL
status #重定向状态码,默认temp
#permanent,状态码301,永久重定向
#temp,状态码302,临时重定向,默认值
#seeother,状态码303,表示资源己经被替代
#gone,状态码410,表示资源被删除
#示例
#www.a.com 临时重定向到 www.b.com
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/www.a.com.conf
<virtualhost *:80>
DocumentRoot /data/www/web1/
ServerName www.a.com
Redirect / "http://www.b.com" #重定向配置
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
#重载服务,并在浏览器中测试
##如果重定向配置不是写在特定虚拟主机中,则会造成循环重定向
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/www.a.com.conf
Redirect permanent "/" "https://www.a.com"
<virtualhost *:80>
DocumentRoot /data/www/web1/
ServerName www.a.com
CustomLog "${APACHE_LOG_DIR}/access_www.a.log" combined
<Directory /data/www/web1/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</virtualhost>
HSTS 安全重定向
HSTS:HTTP严格传输安全(HTTP Strict Transport Security)
HSTS 是一种网站用来声明他们只能使用安全连接(HTTPS)访问的方法,如果一个网站声明了 HSTS 策 略,浏览器必须拒绝所有的 HTTP 连接并阻止用户接受不安全的 SSL 证书。 目前大多数主流浏览器都支 持 HSTS
HSTS 工作原理
客户端在通过URL 请求某个资源的时候,如果服务端返回重定向状态码,则客户端需要重新发起 HTTPS 连接,如果服务端有配置 HSTS 功能,则服务端返回的内容中将明确声明,此网站的 HTTP 连接完全是 不被允许的,如果客户端接收到使用 HTTP 传输的资源,则必须使用HTTPS 请求替代,如果HTTPS不可 用,则终止该资源连接
另外,浏览器在遇到无效的 HTTPS 证书时(过期,自签名,由未知 CA 签名等),将阻止建立连接,并显示一个提示页面,但该页面可以手动确认后继续访问,但如果服务端配置了 HSTS功能,客户端将无 法手动绕过告警,若要访问该站点,必须从浏览器内部的 HSTS 列表中删除该站点
HSTS 与服务端HTTPS重定向的区别
服务端 HTTPS 重定向是指客户端每次访问 HTTP 协议的 URL 资源,然后服务端返回301或302,客户端 再去请求 HTTPS 资源
HSTS 是指客户端首次访问 HTTP 协议的 URL 资源,然后服务端返回带有 HSTS 的重定向头,在 HSTS 规定的有效期内,下次浏览器再次访问该网站的 HTTP 协议的资源时,浏览器将直接换成 HTTPS 协议再 去访问
HSTS 预加载列表(hsts preload list)
HSTS 预加载列表是 Chromium 项目维护一个使用 HSTS 的网站列表,该列表通过浏览器发布。 如果你 把你的网站添加到预加载列表中,浏览器会首先检查内部列表,这样你的网站就永远不会通过 HTTP 访 问,甚至在第一次连接尝试时也不会。 这个方法不是 HSTS 标准的一部分,但是它被所有主流浏览器 (Chrome,Firefox,Safari,Opera,IE11,Edge)所支持
为了提高安全性,浏览器不能访问或下载 预加载列表(preload list), 它作为硬编码资源(hardcoded resource)和新的浏览器版本一起分发。 这意味着结果出现在列表中需要相当长的时间,而域从 列表中删除也需要相当长的时间
生产环境中的HSTS
bash
[root@ubuntu ~]# curl -Ik http://www.jd.com
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Mon, 01 Jan 2024 13:56:41 GMT
Content-Type: text/html
Content-Length: 138
Connection: keep-alive
Location: https://www.jd.com/
Timing-Allow-Origin: *
X-Trace: 302-1704117401542-0-0-0-0-0
Strict-Transport-Security: max-age=3600
实现 HSTS 安全重定向
bash
[root@ubuntu ~]# cd /etc/apache2/mods-enabled/
[root@ubuntu mods-enabled]# ln -sv ../mods-available/headers.load ./headers.load
'./headers.load' -> '../mods-available/headers.load'
[root@ubuntu ~]# cat /etc/apache2/sites-enabled/www.a.com.conf
RewriteEngine on
Header always set Strict-Transport-Security "max-age=31536000" #添加此行,向客户端返回一个头,有效期一年
#重载,测试
[root@ubuntu ~]# curl -Ik www.a.com
HTTP/1.1 302 Found
Date: Mon, 01 Jan 2024 14:08:28 GMT
Server: Apache/2.4.52 (Ubuntu)
Strict-Transport-Security: max-age=31536000
Location: https://www.a.com/
Content-Type: text/html; charset=iso-8859-1
[root@ubuntu ~]# curl www.a.com
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://www.a.com/">here</a>.</p>
<hr>
<address>Apache/2.4.52 (Ubuntu) Server at www.a.com Port 80</address>
</body></html>
#L 跟踪跳转,k 不校验证书
[root@ubuntu ~]# curl -Lk www.a.com
web-1
#在浏览器中查看能看到307状态码,表示直接在客户端跳转https了