http、httpd、https、浏览工具

来源:互联网 发布:2017计算机二c语言题库 编辑:程序博客网 时间:2024/06/11 21:35

0 目录

  • 目录
  • http
    • 1 http是什么
    • 2 工作机制
      • 21 服务器端与客户端
      • 22 web资源与MIME
      • 23 URL
      • 24 http事务的过程
    • 3 http报文格式
      • 31 请求报文格式
        • 311 常见请求方法
      • 32 响应报文格式
        • 321 常见状态码
      • 33 常见header
        • 331 通用首部
        • 332 请求首部
        • 333 响应首部
    • 4 cookie和session简要说明
  • httpd22
    • 1 主配置文件Section 1
      • 11 ServerRoot
      • 12 Listen
      • 13 LoadModule
      • 14 Include
      • 15 持久连接相关
        • 151 持久连接是什么
        • 152 KeepAlive
        • 153 KeepAliveTimeOut
        • 154 MaxKeepAliveRequests
      • 16 MPM
        • 161 prefork
        • 162 worker
        • 163 event
      • 17 User和Group
    • 2 主配置文件Section 2
      • 21 DocumentRoot
      • 22 DirectoryIndex
      • 23 对指定文件页面定义特性
        • 231 Options
        • 232 基于IP的访问控制
        • 233 基于用户认证的访问控制
        • 234 AllowOverride
      • 24 日志相关
        • 241 错误日志级别
        • 242 访问日志内容格式
      • 25 Alias
      • 26 status页面
    • 3 主配置文件Section3
      • 31 各虚拟主机监听不同IP
      • 32 各虚拟主机监听不同端口
      • 33 各虚拟主机使用不同的FQDN
  • 两个浏览器工具
    • 1 curl
    • 2 elinks
  • https
    • 1 自建CA签发证书
    • 2 https配置文件
    • 3 配置及测试
      • 31 配置
      • 32 测试
  • httpd24与22的部分不同之处

1 http

1.1 http是什么

http :(hyper text transfer protocol),超文本传输协议,一个基于TCP的应用层协议。

超文本指的是使用html(hyper text mark language,超文本标记语言)编程语言所开发的文本文件

1.2 工作机制

1.2.1 服务器端与客户端

服务器端即web服务器。运行了http服务端程序(如httpd、nginx等),存放了web资源的主机,可响应给客户端请求的资源,这些资源存放在web服务器上的某文件系统的某路径。服务器端监听在80端口(tcp)。

客户端就是各种浏览器。

1.2.2 web资源与MIME

一次请求和响应的内容,叫做web资源。分为静态、动态资源。

静态资源,jpg、html、mp3等等。就是无需服务端处理,直接发送给客户端的资源(httpd仅能处理静态资源)。为加快响应速度,静态资源可被浏览器缓存一段时间;
动态资源,php、jsp等。是需要服务端运行,将运行结果传给客户端的资源。

一个网页页面上通常有多个资源,一个图片、一个文本、一个链接都是各自独立的资源。不要误以为整个网页是一个资源。
所以,在打开一个页面时,客户端要对每个资源单独请求。显示一个完整网页,客户端其实是请求了多次的。

早期的http协议,仅能够用于文本文件(传输过程使用ASCII码)的传输。1.0之后引入MIME1,从而客户端可请求图片、音频等类型文件(传输过程中仍是文本)。

1.2.3 URL

客户端如何指定要请求哪些资源?
通过URL指定。只需在浏览器地址栏中输入指定URL即可。

URL(Uniform Resource Locator,统一资源定位符),用于唯一标识页面。

格式:Scheme://Server_IP:[port]/[PATH][;PARAMS][?QUERY][#FLAG]

各字段 意义 Scheme 指定协议,可以是http、ftp等 Server_IP:port 指定的服务器和端口号 PATH 页面在服务器上的路径映射 ;PARAMS 向服务器传递参数PARAMS。有的请求需要得到服务器的运行结果,运行中需要传递给服务器的参数PARAMS通过此字段指定 ?QUERY 查询语句。如果需要服务器端通过数据库查询时,可在此输入查询语句QUERY #FLAG 页面的锚点。当页面过长时(比如一个长文档),可在不同位置定义锚点,从而通过输入不同的FLAG跳转至页面不同位置方便浏览。当然一般是做成不同的链接供点击来跳转,而非让用户手动输入。

比如,http://www.sohu.com/
Scheme是http;
www.sohu.com是Server_IP:port,只是没有直接用IP而是域名,且http默认80端口,所以可省;
之后的PATH省略,表示访问的是默认主页面index.html。

再比如,https://baike.baidu.com/item/MIME/2900607?fr=aladdin等。

1.2.4 http事务的过程

http的工作机制很简单:客户端向服务器端发送请求资源报文;服务器端返回给客户端响应报文。而这也称为一次http事务。

从服务器端来看,具体过程:
1、对于来访的请求,建立或拒绝连接;
2、接收并处理请求。包括分析请求报文的首部(header)信息,从而得知客户端的请求方法(method)。由于http基于tcp,所以每个资源的请求都要3次握手、4次断开;
3、服务器根据请求报文指定的URL,访问存储设备上对应的资源;
4、服务器得到指定资源,构建响应报文(即加上各首部信息),发送给客户端;
5、服务器将此次访问相关的信息记录日志。

1.3 http报文格式

http的请求、响应报文包括http协议首部(其实行+各headers)和数据实体。
不过请求报文和响应报文的起始行格式、常使用的headers有所不同。

1.3.1 请求报文格式

请求报文格式:

<method> <URL> <version>                        # 起始行header1: value                                  # 各首部信息header2: value……headerN: value<request body>                                  # 与上述信息隔两行,是数据实体

method:请求方法。即客户端请求服务端对资源完成的动作。
URL:指定资源的URL
version:指明http协议版本
headers:各首部信息。用于描述报文的各种属性。
request body:请求报文的数据实体

起始行信息与各headers,就是http协议首部。隔两行之后是数据实体。

1.3.1.1 常见请求方法

方法 意义 GET 请求从服务器端获取一个资源。所以GET方法对应的数据实体常为空,无需向服务器传输什么数据 HEAD 请求从服务器获取响应报文的http首部。HEAD和GET方法不同就在于,不请求获取数据实体 POST 请求向服务器发送要被服务器处理的数据。比如一些表单、帐号密码的填写。该方法对应的数据实体,就是要发给服务器的数据 PUT 请求向服务器发送要存储在服务器上的数据(相比于POST,这些数据是无需处理的)。比如上传一个文件到服务器。显然该方法对应的数据实体就是要上传的数据 DELETE 请求删除服务器上的指定数据 OPTIONS 请求获取服务器对指定资源,开放支持了哪些请求方法。比如DELETE方法比较危险,未必所有服务器对所有资源都开放。通过此方法可知对指定服务器上的各资源能使用哪些请求方法 TRACE 追踪请求报文从客户端到服务器端,经过了哪些代理服务器2。

1.3.2 响应报文格式

响应报文与请求报文的格式,主要是起始行的不同:

<version> <status-code> <reason phrase>         # 起始行header1: value                                  # 各首部信息header2: value……headerN: value<entity body>                                   # 与上述信息隔两行,是数据实体

version,仍是http协议版本;
status-code,状态码,用于描述不同的响应状态(成功、失败等)
reaon phrase,原因短语,就是对状态码的解释
headers,响应报文用到的各首部
entity body,数据实体。比如客户端要GET某资源,则这时的数据实体就是该资源

1.3.2.1 常见状态码

状态码就是3位数字,其中按1、2、3、4、5开头的对应不同的状态类型:

开头数字 范围 意义 1 100、101 基本无意义 2 200至206 客户端请求成功 3 300至305 请求的资源被重定向等 4 400至415 因客户端原因导致请求失败 5 500至505 因服务端原因导致请求失败

常见状态码:

状态码 对应的原因短语 意义 200 OK 请求的资源内容已构建响应报文发给客户端 301 moved permanently 请求的URL指向的资源已被永久移动,放在了其他位置。响应报文会通过首部”Location”告知客户端资源的新URL 302 found 类似301,只是资源是被临时移动到了其他位置,过短时间或许还会恢复原样。服务端同样通过首部”Location”,告知客户端资源目前的临时URL 304 Not Modified 当客户端发出条件式请求请求指定资源时,服务端的对应资源正好也没有改变,则返回此状态,告知客户端继续使用缓存内容3 401 Unauthorized 需要输入帐号密码才能访问指定资源,比如http自带的basic认证等 403 Forbidden 请求被禁止。比如服务端对访问控制做了相关配置,拒绝某些IP的访问等 404 Not Found 客户端请求的URL对应的资源不存在 500 Internal Server Error 服务器内部错误 502 Bad Gateway 用户请求报文到达了代理服务器,而代理服务器从它的后端服务器(显然,这可能是真正的web服务器也可能还是个代理服务器)收到了错误响应,导致它无法正确响应用户请求

1.3.3 常见header

如上所述,请求报文、响应报文的起始行之后,都有任意个首部(header)信息,以描述当前报文的属性等信息。

格式为:header_name: value
如有多个header,则每行一个。

比如,打开浏览器的调试界面(F12),地址栏输入www.sohu.com。随便找一个资源对应的首部信息,可看到该资源对应的请求、响应报文各首部,大致如下:

这里写图片描述

各常见首部:

1.3.3.1 通用首部

通用首部就是在请求、响应报文都可能用到的首部。

名称 意义 Date 报文创建的时间 Connection 连接状态。比如keepalive(长连接)、close(连接关闭)等 Via 显示报文经过的中间结点(如代理服务器等) Cache-control 缓存控制

1.3.3.2 请求首部

仅用于请求报文中的常见首部:

名称 意义 Accept 告知服务端,客户端能够识别的媒体类型(即MIME类型) Accept-Charset 告知服务端,客户端所能接收的字符集 Accept-Encoding 告知服务端,客户端所能接收的编码格式(比如gzip等压缩格式) Accept-Language 告知服务端,客户端所能接收的语言 Client-IP 指明客户端IP Host 请求的服务器IP和端口号(包括FQDN) Referer 当前所请求资源的上一级资源。即当前请求的资源是由哪个页面跳转而来,如果是直接从浏览器地址栏键入而非从其他页面跳转来的,则为空 User-agent 客户端代理类型。就是浏览器类型 If-Modified-Since 自从指定的时间后,请求的资源是否发生过修改(条件式请求,以此决定是否使用缓存内容) Authorization 客户端向服务端发送认证信息 Cookie 客户端发送Cookie以使服务器识别客户端来源(http是无状态的,服务端无法识别客户端来源,看待任何请求都是一样的,所以使用Cookie来标记客户端)

1.3.3.3 响应首部

仅用于响应报文中的常见首部:

名称 意义 Age 响应持续时长 Server 服务器端运行的程序名称和版本(如apache、nginx等),这个信息一般是不发的 Accept-Ranges 服务端可接收的请求范围 Set-Cookie 为服务端设置并发送一cookie WWW-Authenticate 来自服务端对客户端的质询认证表单(如帐号密码) Allow 列出对当前数据实体可使用的请求方法。响应客户端Options方法时,要用此首部 Location 用于资源重定向时,告知客户端资源的新位置在哪 Cotent-Encoding 数据实体内容的编码格式 Cotent-Language 数据实体内容的语言 Cotent-Length 数据实体内容的长度 Cotent-Type 数据实体的类型(即MIME类型) Expires 响应资源的缓存过期时间 Last-Modified 响应资源的最后依次修改时间

1.4 cookie和session简要说明

http协议是无状态的,就是服务器端无法识别访问者来源。即便是同一用户访问同一资源,在服务端看来也是两次不同的、独立的请求。

这在需要输入帐号密码、或是电商站点的情形是有问题的:只要一刷新页面就要重新输入验证信息,并且重新选购物品等。

使用cookie就是为了追踪访问者,以保持访问页面的状态。它会记录用户信息和操作记录。在客户端第一次向服务端发请求时,服务端发cookie给客户端。cookie存储在客户端本地,只要再访问服务端,就发送cookie以标明身份。
这样,在安全上又有较大风险,cookie可能泄露隐私信息。

于是引入session,session可看作服务端为用户建立的一种数据结构,用于存储用户操作记录。把cookie的部分信息用session来存储,cookie与session对应起来。
这样,根据指定cookie可在服务器上找到对应用户session,session中记录了用户的操作、行为记录等。

2 httpd2.2

应用层协议的实现,都是通过具体的软件。
httpd就是http协议中,服务器端的安装程序。以下说明httpd2.2的常用配置。笔者使用的是CentOS 6(6的光盘上的rpm包就是httpd2.2,如需在6上安装2.4,需编译安装),IP为192.168.0.105。

安装后只需在浏览器键入地址,即可看到测试页:

这里写图片描述

httpd2.2的配置文件为:主配置文件/etc/httpd/conf/httpd.conf和其他配置文件/etc/httpd/conf.d/*.conf
上面的测试页面就是/etc/httpd/conf/httpd.conf/welcome.conf定义配置的。

主配置文件分3段:

### Section 1: Global Environment                       # 全局环境配置……### Section 2: 'Main' server configuration              # 中心主机配置……### Section 3: Virtual Hosts                            # 虚拟主机配置……

配置格式为:”Command Value”各Command不严格区分大小写,但一般是把每个单词首字母大写。
修改其中的参数后可使用“httpd -t”检查配置文件语法

下面列出主配置文件中的常用配置:

2.1 主配置文件Section 1

此段中的配置对全局有效。

2.1.1 ServerRoot

ServerRoot,用于定义服务端httpd程序的配置、日志等文件所在的目录(可看作是httpd的工作目录)。
注意,不要在最后加“/”:

……# Do NOT add a slash at the end of the directory path.#ServerRoot "/etc/httpd"

2.1.2 Listen

Listen,用于定义服务端监听的IP和端口。IP可省略,表示监听在所有IP;端口不可省。
可多次使用,表示同时监听在多个IP和端口。
修改监听的IP或端口,只有重启服务才能生效。

比如,修改为监听在80和8000端口:

Listen 80Listen 8000

重启服务后,查看监听端口验证:

[root@localhost ~]% netstat -tnlpActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1592/sshd           tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1671/master         tcp        0      0 127.0.0.1:6010              0.0.0.0:*                   LISTEN      1757/sshd           tcp        0      0 127.0.0.1:6011              0.0.0.0:*                   LISTEN      2243/sshd           tcp        0      0 :::8000                     :::*                        LISTEN      2347/httpd          tcp        0      0 :::80                       :::*                        LISTEN      2347/httpd……

2.1.3 LoadModule

httpd是高度模块化的,支持动态装载、卸载各功能模块(就像内核一样)。
httpd的各模块文件放在/usr/lib64/httpd/modules

LoadModule,用于指定装载的模块。
格式:LoadModule Module_Name Module_Path
其中模块所在的文件路径可以是相对路径,相对于ServerRoot定义的路径。

可看到httpd默认已经装载了诸多模块:

LoadModule auth_basic_module modules/mod_auth_basic.soLoadModule auth_digest_module modules/mod_auth_digest.soLoadModule authn_file_module modules/mod_authn_file.soLoadModule authn_alias_module modules/mod_authn_alias.so……

httpd命令的”-M”选项,可列出当前装载的所有模块。

2.1.4 Include

包含指定文件到配置文件。

主配置文件中使用了此指令,/etc/httpd/conf.d/*.conf才会作为配置文件生效,因为默认定义的就是此路径:

# Load config files from the config directory "/etc/httpd/conf.d".#Include conf.d/*.conf

2.1.5 持久连接相关

2.1.5.1 持久连接是什么

http基于tcp(连接需3次握手、4次断开)。

默认情况下是非持久连接:客户端每请求一个资源都要与服务端3次握手、获取到资源、4次断开。

当用户数较多时,应采取默认方式,以保证所有用户都能轮流得到响应;
当用户数较少时(比如只有1个用户,请求多个资源),频繁地3次握手、4次断开增加了不必要的开销。

对于后者应采取持久连接(也叫长连接):客户端与服务端一直保持连接状态,直到获取到一定数量的资源或连接达到一定时长才断开(注意,是满足二者中任一条件就断开)。

显然,长连接的情况下,当达到断开条件时,由服务端向客户端发出断开要求,因为只有服务端知道是否达到了资源数或指定时长;
默认情况断开请求是由客户端发出的。

2.1.5.2 KeepAlive

KeepAlive,用于指定是否启用长连接。

# KeepAlive: Whether or not to allow persistent connections (more than# one request per connection). Set to "Off" to deactivate.#KeepAlive Off                                               # 默认是关闭的,如需开启改为on

2.1.5.3 KeepAliveTimeOut

KeepAliveTimeOut,用于指定长连接的时长。

# KeepAliveTimeout: Number of seconds to wait for the next request from the# same client on the same connection.#KeepAliveTimeout 15                                     # 默认15秒

2.1.5.4 MaxKeepAliveRequests

MaxKeepAliveRequests,用于指定客户端在长连接中最多请求的资源数。

# MaxKeepAliveRequests: The maximum number of requests to allow# during a persistent connection. Set to 0 to allow an unlimited amount.# We recommend you leave this number high, for maximum performance.#MaxKeepAliveRequests 100                                # 默认100个

2.1.6 MPM

MPM(Multipath Processing Module,多路处理模块),是指httpd在同时响应多个请求时的工作模型

分为3种:prefork、worker、event只能启用其中一种。并且在需要切换模型时,最好是在关闭服务的情况下修改配置文件,修改完成后再开启。

虽然叫做模块,但httpd2.2不支持MPM的动态装载、卸载2.4开始支持
所以只要编译时采用了哪种模型,则使用的就是哪种模型。CentOS 6为了方便,3中模型都编译了,对应的应用程序分别为/usr/sbin/httpd、/usr/sbin/httpd.worker、/usr/sbin/httpd.event
不过2.2上,event模型处于测试阶段;2.4可正常使用。

服务脚本启用httpd时,用的是哪种模型,在服务脚本配置文件/etc/sysconfig/httpd中进行了定义:

# The default processing model (MPM) is the process-based# 'prefork' model.  A thread-based model, 'worker', is also# available, but does not work with some modules (such as PHP).# The service must be stopped before changing this variable.##HTTPD=/usr/sbin/httpd.worker                               如需启用则把该行注释掉

2.1.6.1 prefork

默认情况下,服务脚本启动的是prefork模型对应的应用程序/usr/sbin/httpd:

[root@localhost ~]# ps aux | grep httpdroot      2000  0.0  0.3 175332  3688 ?        Ss   16:07   0:00 /usr/sbin/httpdapache    2002  0.0  0.2 175332  2464 ?        S    16:07   0:00 /usr/sbin/httpdapache    2003  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2004  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2005  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2006  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2007  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2008  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdapache    2009  0.0  0.2 175332  2444 ?        S    16:07   0:00 /usr/sbin/httpdroot      2012  0.0  0.0 103312   880 pts/2    S+   16:11   0:00 grep httpd

prefork模型:一个主进程用于创建套接字,由该主进程生成若干个子进程(称为服务进程)。处理请求时,由主进程接收并把请求派发给各子进程处理,每个子进程逐个处理资源请求4。处理一定数量的请求后,被主进程销毁、回收
由于收到请求后再创建进程会影响响应效率,所以主进程会预先创建m个子进程等待用户请求。所以叫做prefork5。

httpd主配置文件中关于prefork的配置:

# prefork MPM# StartServers: number of server processes to start# MinSpareServers: minimum number of server processes which are kept spare# MaxSpareServers: maximum number of server processes which are kept spare# ServerLimit: maximum value for MaxClients for the lifetime of the server# MaxClients: maximum number of server processes allowed to start# MaxRequestsPerChild: maximum number of requests a server process serves<IfModule prefork.c>StartServers       8                                # 服务启动时,启动多少服务进程MinSpareServers    5                                # 最小空闲进程数MaxSpareServers   20                                # 最大空闲进程数ServerLimit      256                                # httpd运行期间,所能够启动的服务进程总数MaxClients       256                                # 任一时刻,允许启动的服务进程最大数(即最多同时响应的用户数)MaxRequestsPerChild  4000                           # 每个服务进程最多处理的请求数</IfModule>

注意:
1、MaxClients,限制了任一时刻,服务端最多并发响应多少用户的请求
prefork模式中,同一时间,一个进程响应一个请求。即便每个服务进程响应的都是来自不同用户的请求(这正是服务端能允许并发用户数最多的情况),用户数量也就是恰好等于MaxClients定义的值;其他情况只会小于MaxClients。
2、ServerLimit大于等于MaxClients
因为整个服务运行期间,服务进程数一共最多有ServerLimit个。所以在某一时刻,启动的服务进程最多就是ServerLimit个(再启动就超过ServerLimit了),而这正是MaxClients等于ServerLimit的情况。否则MaxClients会小于ServerLimit,因为某一时刻启动的最大服务进程数,不一定就是要把服务运行期间所能启动的服务进程都启动起来,可能是一个进程达到响应数量,销毁、回收后再继续启动新服务进程。

2.1.6.2 worker

在/etc/sysconfig/httpd中,修改为启用worker模型,再启动httpd,则会看到运行的程序变为/usr/sbin/httpd.worker:

[root@localhost ~]# ps aux | grep httpdroot      2151  0.0  0.3 175540  3888 ?        Ss   19:55   0:00 /usr/sbin/httpd.workerapache    2153  0.0  0.5 519800  5300 ?        Sl   19:55   0:00 /usr/sbin/httpd.workerapache    2154  0.0  0.5 519800  5304 ?        Sl   19:55   0:00 /usr/sbin/httpd.workerapache    2156  0.0  0.5 519800  5308 ?        Sl   19:55   0:00 /usr/sbin/httpd.workerroot      2266  0.0  0.0 103312   876 pts/1    S+   19:55   0:00 grep httpd

worker模型:一个主进程用于创建套接字,由该主进程生成若干个子进程,各子进程再创建若干线程。处理请求时,由主进程接收并把派发请求,由每个线程逐个响应请求
最多同时响应”m乘以n”个请求(m为子进程数,n为每个子进程创建的线程数)

httpd主配置文件中,关于worker模型的配置:

# worker MPM# StartServers: initial number of server processes to start# MaxClients: maximum number of simultaneous client connections# MinSpareThreads: minimum number of worker threads which are kept spare# MaxSpareThreads: maximum number of worker threads which are kept spare# ThreadsPerChild: constant number of worker threads in each server process# MaxRequestsPerChild: maximum number of requests a server process serves<IfModule worker.c>StartServers         4                                  # 服务启动时,启动的子进程数MaxClients         300                                  # 最多同时连接服务端的用户数MinSpareThreads     25                                  # 最小空闲线程数MaxSpareThreads     75                                  # 最大空闲线程数ThreadsPerChild     25                                  # 每个进程有多少线程MaxRequestsPerChild  0                                  # 默认为0,表示不限制每个子进程响应请求的数量</IfModule>

注意:
1、默认定义的服务启动时的进程数是4,每个进程创建的线程是25。所以服务启动时会有100个空闲线程。但默认定义的最大空闲线程是75,所以服务又会销毁一个进程,变为3个子进程6。

[root@localhost ~]% service httpd restart                                  # 重启服务Stopping httpd:                                            [  OK  ]Starting httpd:                                            [  OK  ][root@localhost ~]% ps aux | grep httpd                                        # 立即查看可看到4个子进程root      2310  0.0  0.3 175540  3892 ?        Ss   20:36   0:00 /usr/sbin/httpd.workerapache    2312  0.0  0.5 519800  5304 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerapache    2313  0.0  0.5 519800  5320 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerapache    2314  0.0  0.5 519800  5304 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerapache    2315  0.0  0.5 519800  5312 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerroot      2425  0.0  0.0 103312   880 pts/0    S+   20:36   0:00 grep httpd[root@localhost ~]% ps aux | grep httpd                                        # 稍等几秒查看,变为3子进程。这就是由于默认的定义导致的root      2310  0.0  0.3 175540  3892 ?        Ss   20:36   0:00 /usr/sbin/httpd.workerapache    2313  0.0  0.5 519800  5324 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerapache    2314  0.0  0.5 519800  5304 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerapache    2315  0.1  0.5 519800  5312 ?        Sl   20:36   0:00 /usr/sbin/httpd.workerroot      2427  0.0  0.0 103312   880 pts/0    S+   20:36   0:00 grep httpd

2、worker配置中的MaxClients和prefork中的意义貌似不同:
prefork模型中的MaxClients定义的是最多同时启动的子进程数,即最多同时响应的用户数;
worker模型中的MaxClients定义的是最多同时连接(注释中使用的是”连接”而非”响应”)的用户数。默认定义的是300,而默认的线程数是75。所以有的用户连接了但是或许要等待(这点不大确定)。

3、ps命令无法查看线程的情况,只能查看进程的情况。

2.1.6.3 event

httpd2.2的event模型处于测试(2.4可正常使用),不能正常使用,httpd2.2的主配置文件中也没有event的配置,关于其配置此处不述。

event:一个主进程用于创建套接字、接收请求,并由它生成若干子进程,并把请求派发给各子进程处理。每个子进程可响应多个请求(这是和prefork的不同之处)
所以最多可同时响应”m乘以n”个请求,其中m为子进程数,n为每个子进程能响应的请求数。

2.1.7 User和Group

完成创建套接字、监听端口这些功能,需要以root身份运行(小于1023端口的监听,均需要root运行);为了安全起见,服务进程则要由非root用户身份运行。

从上述的prefork、worker的进程的情况可看出,服务进程都是由apache用户运行:

[root@localhost ~]% ps aux | grep httpdroot      2515  0.0  0.3 175332  3680 ?        Ss   21:03   0:00 /usr/sbin/httpd        # 主进程由root运行apache    2517  0.0  0.2 175332  2456 ?        S    21:03   0:00 /usr/sbin/httpd        # 子进程由apache用户运行apache    2518  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2519  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2520  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2521  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2522  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2523  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdapache    2524  0.0  0.2 175332  2436 ?        S    21:03   0:00 /usr/sbin/httpdroot      2526  0.0  0.0 103312   880 pts/0    S+   21:03   0:00 grep httpd

User和Group,就是用于指定以哪个用户、哪个组的身份,来运行服务进程。

在主配置文件中的默认定义:

# User/Group: The name (or #number) of the user/group to run httpd as.#  . On SCO (ODT 3) use "User nouser" and "Group nogroup".#  . On HPUX you may not be able to use shared memory as nobody, and the#    suggested workaround is to create a user www and use that user.#  NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)#  when the value of (unsigned)Group is above 60000; #  don't use Group #-1 on these systems!#User apacheGroup apache

注意:
由于服务进程是以apache用户身份运行,所以某些请求的资源如无法获取,应排查是否是apache用户没有该资源的文件权限

2.2 主配置文件Section 2

此段配置的是中心主机各属性。

中心主机:一台物理服务器仅作为一个站点的服务端。
如果用中心主机,则不能用虚拟主机。

2.2.1 DocumentRoot

DocumentRoot,用于定义服务端的网页内容放置在哪个目录。相当于各URL的根。

# DocumentRoot: The directory out of which you will serve your# documents. By default, all requests are taken from this directory, but# symbolic links and aliases may be used to point to other locations.#DocumentRoot "/var/www/html"                    # 默认放置在目录/var/www/html

所以,URL如”http://192.168.0.105/test.html“,访问的资源在服务器文件系统的路径就是”/var/www/html/test.html”。

在不使用路径别名alias定义,或允许在DocumentRoot定义的目录下创建符号链接的情况下,页面文件都是在DocumentRoot定义的目录下的。

2.2.2 DirectoryIndex

DirectoryIndex,用于定义主页面。
当用户键入的URL没有指明请求的具体页面时,则返回DirectoryIndex定义的页面给用户。

# DirectoryIndex: sets the file that Apache will serve if a directory# is requested.## The index.html.var file (a type-map) is used to deliver content-# negotiated documents.  The MultiViews Option can be used for the # same purpose, but it is much slower.#DirectoryIndex index.html index.html.var                    # 默认定义的主页面是index.html

2.2.3 对指定文件(页面)定义特性

httpd支持对不同文件单独定义各种特性。
可使用容器Directory、Files、Location、LocationMatch等封装。Directory和Files作用对象是服务端的文件系统路径,Location作用对象是URL,LocationMatch作用对象是正则表达式匹配到的URL。

它们的用法差不多,以Direvtory为例,格式:

<Directory "/PATH">                     # 对指定文件定义……                                      # 封装在此Directory的内容就是对指定文件的配置内容</Directory>

注意:
可多次使用Directory对多个PATH进行配置,但生效的是PATH范围小的那个
如果对更小范围的路径没有定义配置,则它的配置就继承它上一级目录的

比如,主配置文件中对默认路径的配置:

# First, we configure the "default" to be a very restrictive set of # features.  #<Directory />                               # 这里的路径是根,所以只要不被其他Directory显式配置的,生效的都是这个Directory定义的配置,所以是默认配置    Options FollowSymLinks    AllowOverride None</Directory>

再比如对页面默认放置路径/var/www/html的设定:

# This should be changed to whatever you set DocumentRoot to.#<Directory "/var/www/html">    Options Indexes FollowSymLinks    AllowOverride None    Order allow,deny    Allow from all</Directory>

由于/var/www/html范围更小,所以对/var/www/html来说就是这个Directory定义的配置生效,而不是上面对根路径配置的Directory。

如果/var/www/html的Directory对某些设置没有定义(比如Options),则它继承比它更大范围的文件路径对应的Directory中对相关配置的定义。比如Options没定义或是仅定义了参数FollowSymLinks,则会继承根路径Directory定义的Indexes;如果需禁用,则要显式定义Options的参数为”None”或”-Indexes”。

容器中常用的配置为:

2.2.3.1 Options

定义访问特性。
常用参数:

参数 意义 indexes 当指令DirectoryIndex指定的主页面不存在时,启用该选项表示列出服务端的所有页面文件 followsymlink URL指向的如果是一个链接文件,该选项表示显示链接文件所指向的文件内容 none 不启用Options的任何功能(这反而是很常用的)

由于indexes、followsymlinks不安全,none反而比较常用。不过indexes、followsymlinks默认是被开启的。其他参数不述,可根据配置文件注释查询。

1、indexes效果:

在/var/www/html目录下创建一个test.html作为测试文件,内容是test page:

[root@localhost ~]% echo "<h1>test page</h1>" > /var/www/html/test.html

注销配置文件/etc/httpd/conf.d/welcome.conf中的内容(该配置文件定义了CentOS自带的测试页作为主页),此时就没有主页内容了,于是直接访问服务器IP,页面为:

这里写图片描述

结果是把test.html文件名列出,用户直接点击就打开该页面。
如果主页面不存在,且为设置Indexes,则会返回403或404错误页面。

2、followsymlinks效果:

比如,在/var/www/html目录下创建/etc/issue的链接文件issue.html,由于默认是开启的,所以URL指定为issue.html,显示的内容是/etc/issue的:

[root@localhost ~]% ln -sv /etc/issue /var/www/html/issue.html`/var/www/html/issue.html' -> `/etc/issue'

这里写图片描述

如果把/var/www/html的Options参数改为None,则无法访问:

这里写图片描述

2.2.3.2 基于IP的访问控制

可对Directory指定的路径做基于IP的访问控制。

首先使用指令Order,指定是做白名单还是黑名单。
白名单:

Order allow,deny                        # 除了显式定义允许的,其他都拒绝

黑名单:

Order deny,allow                        # 除了显式定义拒绝的,其他都允许

而后通过指令”Allow from”或”Deny from”,定义允许、拒绝的IP和网段。
比如/var/www/html的Directory默认定义的:

    Order allow,deny    Allow from all

表示允许所有主机访问。

再比如/var/www/html/test.html对应的Directory,如果定义为:

    Order allow,deny    Allow from 192.168.0.0    Deny from 192.168.0.100

表示仅允许192.168.0.0网段7的主机访问,但禁止192.168.0.100的IP访问。虽然这个IP属于192.168.0.0,但以更小范围的为准。

2.2.3.3 基于用户认证的访问控制

基于IP的访问控制显得比较简陋,可使用httpd自带的用户认证机制8。

有两种方式:基于明文的basic;基于特征码的digest。认证信息通过明文传输是有风险的,但由于有的浏览器不支持digest,所以默认使用basic。

服务端返回认证质询页面的状态码是401

相关指令:

指令 意义 AuthType [ basic | digest ] 指定使用basic还是digest AuthName STRING 使用字符串,向用户说明访问哪些URL是需要认证的。就是提示信息 AuthUserFile 指定用户名、密码存放在哪个文件 Require User 定义哪些帐号可登录,帐号必须是AuthUserFile指定的文件中定义的。如果定义为只要有帐号密码都可登录,则参数指定为”valid-user” AuthGroupFile 指定把用户划分为组的文件9 Require Group 定义哪些组可登录,组必须是AuthGroupFile指定的文件中定义的

如果使用文本文件存储帐号密码,使用专用于管理basic认证的命令htpasswd创建,这是httpd自带的一个组件。
格式:htpasswd PASSWD_FILE USER,表示在文件PASSWD_FILE中创建用户USER。

选项 意义 -m 使用md5算法加密存放 -s 使用sha算法加密存放 -c 文件不存在时创建,但已存在时使用该选项会把文件内容清空(就是重新创建了) -D 删除指定用户

下面令笔者的192.168.0.105虚拟机上的test页面需认证才可登录,过程、效果:

1、创建帐号、密码文件,在其中创建3帐号(密码就设置为帐号名):

[root@localhost ~]% htpasswd -c -m /etc/httpd/my_passwd user1      # 只有创建第一个用户时使用“-c”选项New password: Re-type new password: Adding password for user user1[root@localhost ~]% htpasswd -m /etc/httpd/my_passwd user2New password: Re-type new password: Adding password for user user2[root@localhost ~]% htpasswd -m /etc/httpd/my_passwd user3New password: Re-type new password: Adding password for user user3

可看到文件内容中包含了帐号和密文存放的密码:

[root@localhost ~]% cat /etc/httpd/my_passwd user1:$apr1$lW68PjQ8$NF9HNaN4xplRcMdyl80tJ1user2:$apr1$2t3DiJUz$a7WLgFq.4QCKFxWq4n3v8/user3:$apr1$RFTMn8.I$0yG8nbmYO8M3Um66iJ6aV/

2、把user2、user3两帐号划分为1组(这个步骤不是必要的,只是为了后续验证对组的权限指派),组名为User_Group:

[root@localhost ~]% echo "User_Group: user2 user3" > /etc/httpd/my_group

3、把各指令定义在主配置文件的/var/www/html/test.html的Directory中:

<Directory "/var/www/html/test.html">        Options None        AllowOverride None        Order allow,deny        Allow from all        Authtype basic        AuthName "/var/www/html/test.html"        AuthUserFile /etc/httpd/my_passwd        Require User user1 user2 user3#       AuthGroupFile /etc/httpd/my_group#       Require Group User_Group</Directory>

注意,基于IP和基于用户做访问控制并不冲突,都有效。只是这里对客户端IP没有做限制。

4、效果:

出现提示框要求帐号、密码认证:

这里写图片描述

提示信息中的”/var/www/html/test.html”,正是由AuthName定义的字符串;
有警告信息,是因为采用的AuthType是basic这种不安全的发送方式(明文)。

如点击“取消”,或多次输入错误密码,则返回如下页面:

这里写图片描述

经测试,正确输入user1、user2、user3的帐号密码可显示正确页面内容。

5、为验证组的效果,把第3步的内容改为:

<Directory "/var/www/html/test.html">        Options None        AllowOverride None        Order allow,deny        Allow from all        Authtype basic        AuthName "/var/www/html/test.html"        AuthUserFile /etc/httpd/my_passwd                  #       Require User user1 user2 user3        AuthGroupFile /etc/httpd/my_group        Require Group User_Group</Directory>

注意,虽然是验证组的效果,把”Require User”这项注释掉了。但AuthUserFile还是要指定的,因为组文件只是把指定的用户帐号划分为了一组,密码还是存储在AuthUserFile指定的文件中的。如不指定这项,还是会要求认证,但不论输入什么认证都不会通过。

经测试,只有user2、user3才能通过认证。因为User_Group组中仅包含了user2、user3。

2.2.3.4 AllowOverride

AllowOverride,指定哪些访问控制指令可放在.htaccess中。这个文件中定义的指令有效,而配置文件中Directory定义的就无效了。

网站的每个目录下都可以有.htaccess文件,使每个目录都按被分别控制。不常用,降低性能。所以默认参数是none,不起作用。

不常用。

2.2.4 日志相关

httpd的日志分为:访问日志、错误日志。顾名思义。

日志存放位置由配置文件定义(默认使用的是相对路径,相对于ServerRoot):

# ErrorLog: The location of the error log file.# If you do not specify an ErrorLog directive within a <VirtualHost># container, error messages relating to that virtual host will be# logged here.  If you *do* define an error logfile for a <VirtualHost># container, that host's errors will be logged there and not here.#ErrorLog logs/error_log
# For a single logfile with access, agent, and referer information# (Combined Logfile Format), use the following directive:#CustomLog logs/access_log combined              # 不仅定义了放置路径,还定义了日志格式使用combined格式

不过除了定义的路径,还可看到/var/logs/httpd目录下各文件,做了硬链接:

[root@localhost ~]# ls -li /etc/httpd/logs/total 1441184103 -rw-r--r--. 1 root root 46985 Oct 29 15:59 access_log1184086 -rw-r--r--. 1 root root 25970 Oct 29 11:21 access_log-201710291184104 -rw-r--r--. 1 root root 25789 Oct 29 15:59 error_log1184085 -rw-r--r--. 1 root root 24090 Oct 29 11:22 error_log-20171029[root@localhost ~]# ls -li /var/log/httpd/total 1441184103 -rw-r--r--. 1 root root 46985 Oct 29 15:59 access_log1184086 -rw-r--r--. 1 root root 25970 Oct 29 11:21 access_log-201710291184104 -rw-r--r--. 1 root root 25789 Oct 29 15:59 error_log1184085 -rw-r--r--. 1 root root 24090 Oct 29 11:22 error_log-20171029

2.2.4.1 错误日志级别

对于错误日志,可定义不同级别。
作用是定义,当错误达到哪种级别才记录日志。所以,级别定义得越低,日志文件就会越大。

默认是警告级别就记录日志。

# LogLevel: Control the number of messages logged to the error_log.# Possible values include: debug, info, notice, warn, error, crit,# alert, emerg.#LogLevel warn

2.2.4.2 访问日志内容格式

指令CustomLog定义了访问日志的存放位置和日志内容的格式。各种格式具体为何,则由指令LogFormat定义:

# The following directives define some format nicknames for use with# a CustomLog directive (see below).#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedLogFormat "%h %l %u %t \"%r\" %>s %b" commonLogFormat "%{Referer}i -> %U" refererLogFormat "%{User-agent}i" agent

格式都写在双引号中了,所以双引号中再使用双引号,使用了“\”进行转义。
访问日志默认使用的格式是combined,相对于其他的比较全,各字段意义:

字段 意义 %h 客户端IP %l 客户端主机名。如没有启用对应模块则不会识别,则为“-” %u 客户端用户名。可用于基于用户名的认证。如没有(如非登录访问),则为“-” %t 服务器收到请求的时间 %r 请求报文的起始行(如上所述,起始行包含请求方法、URL、协议版本) %>s 响应的状态码 %b 响应报文的内容大小(即entity body的大小,不含http首部) %{referer}i 请求报文中首部referer的值。如果是直接键入浏览器地址栏访问的,则为“-” %{user-agent}i 请求报文中首部user-agent的值。就是发出请求的应用程序(各浏览器、命令行工具等)

还有其他许多字段,只是combined格式没有使用。参考官方文档:http://httpd.apache.org/docs/2.2/mod/mod_log_config.html

以笔者的192.168.0.105服务器刚产生的一条访问日志为例:

[root@localhost ~]# tail -1 /var/log/httpd/access_log192.168.0.104 - - [29/Oct/2017:17:18:30 +0800] "GET /favicon.ico HTTP/1.1" 403 292 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"

1、客户端IP192.168.0.104;
2、未识别主机名;
3、未识别用户名;
4、收到请求的时间[29/Oct/2017:17:18:30 +0800],使用的是英文标准时间格式;
5、起始行”GET /favicon.ico HTTP/1.1”;
6、状态码403;
7、报文内容大小292字节(因为返回了403对应的页面);
8、笔者是直接从浏览器输入的地址,所以首部referer无值;
9、浏览器类型”Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36”。

2.2.5 Alias

Alias,用于定义路径别名。
格式:Alias fakename realname

fakename为相对于DocumentRoot的URL路径,realname为把前者URL映射为指定的文件系统路径。

所以虽说叫做别名,实际上应该算是改名。

效果:

1、两个不同的页面文件,一个在DocumentRoot定义的路径下,一个在其他路径下:

[root@localhost ~]% cat /var/www/html/test.html                # 本机上已定义过的test.html页面,在DocumentRoot指定的路径下<h1>test page</h1>[root@localhost ~]% echo "<h1>another test page</h1>" > /var/www/test.html     # 定义另一个不同的页面,在另一路径下

2、在不使用别名的情况下,URL”http://192.168.0.105/test.html“,对应的页面文件是/var/www/html/test.html:

这里写图片描述

3、在配置文件中定义别名,使URL”http://192.168.0.105/test.html“对应页面文件变为/var/www/test.html:

配置文件中定义:

Alias /test.html "/var/www/test.html"               # 注意也可对目录做别名,最后可加斜杠。但前后的斜杠要一致,有斜杠前后都要有

此时同样的URL,页面变为了另一个:

这里写图片描述

2.2.6 status页面

status页面显示的是站点的运行状态信息。
最好做下认证(基于IP或用户)。

查看status页面,需要加载status模块,默认是加载的:

LoadModule status_module modules/mod_status.so

默认的对于status页面的访问控制定义(默认都是注释着的):

# Allow server status reports generated by mod_status,# with the URL of http://servername/server-status# Change the ".example.com" to match your domain to enable.##<Location /server-status>#    SetHandler server-status#    Order deny,allow#    Deny from all#    Allow from .example.com                # 默认仅允许域.example.com的主机访问#</Location>

这里为查看效果,改为允许笔者的windows主机登录(IP192.168.0.104):

# Allow server status reports generated by mod_status,# with the URL of http://servername/server-status# Change the ".example.com" to match your domain to enable.#<Location /server-status>    SetHandler server-status    Order deny,allow    Deny from all    Allow from 192.168.0.104</Location>

使用浏览器查看status页面,效果:

这里写图片描述

笔者用红框圈住的部分,就是httpd启动的进程的状态。下方有对应的说明,其中几个说明下:
1、“_”表示空闲服务进程,横杠都连在一起了(这里有8个,因为配置文件中StartServer默认是8;最多不超过MaxClients指定的值);
2、“w”表示正在正在响应的服务进程;
3、“.”表示目前还没启动,但服务运行过程中允许启动的进程,所占的位置(所以它的数量是被ServerLimit指定的)。

2.3 主配置文件Section3

此段用于配置虚拟主机。

1物理服务器默认仅作为1个站点的服务端(就是中心主机配置)。但对于访问量不多的站点,可在1主机上配置多个虚拟主机分别作为它们的服务端。

每个虚拟主机使用容器VirtualHost封装定义。大部分可在中心主机定义的指令,也可在虚拟主机中使用:

<VirtualHost IP:PORT>    ServerName XXX                          # ServerName和DocumentRoot显然是必要的,其他可按需定义    DocumentRoot XXX    ……</VirtualHost>

重点在于,服务端收到一个请求,如何得知访问的是哪个虚拟主机?
可令不同虚拟主机监听于不同的IP、端口区分,也可使用主机名区分。它们可混合使用。

下面分别使用这3种方式:

2.3.1 各虚拟主机监听不同IP

下面令同一主机有192.168.0.105和108两地址,为它们创建两虚拟主机,它们提供的主页面不一样。访问105地址的服务端返回的是105的页面,访问108返回的是108的页面:

1、配置105、108两IP地址:

[root@localhost ~]% ip addr show eth02: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000    link/ether 00:0c:29:05:75:b2 brd ff:ff:ff:ff:ff:ff    inet 192.168.0.105/24 brd 192.168.0.255 scope global eth0    inet 192.168.0.108/32 scope global eth0    inet6 fe80::20c:29ff:fe05:75b2/64 scope link        valid_lft forever preferred_lft forever

2、配置文件中定义两虚拟主机,以IP区分,对应不同的DocumentRoot:

<VirtualHost 192.168.0.105:80>        DocumentRoot "/var/www/html/192.168.0.105"        ServerName test1</VirtualHost><VirtualHost 192.168.0.108:80>        DocumentRoot "/var/www/html/192.168.0.108"        ServerName test2</VirtualHost>

3、在两DocumentRoot定义的目录下均创建test.html,内容就是它们的IP:

[root@localhost ~]% cat /var/www/html/192.168.0.105/test.html 192.168.0.105[root@localhost ~]% cat /var/www/html/192.168.0.108/test.html 192.168.0.108

4、查看不同IP的test.html页面,得到不同页面:

这里写图片描述

这里写图片描述

注意,这种方法是为每个站点都提供了一个IP。不实用,不可能对每个站点都申请一个公网IP。

2.3.2 各虚拟主机监听不同端口

令两虚拟主机监听于不同端口。客户端访问同一IP的不同端口,得到不同页面:

1、配置文件中,定义两虚拟主机,监听105的80和8000端口,对应不同的DocumentRoot:

<VirtualHost 192.168.0.105:80>        DocumentRoot "/var/www/html/192.168.0.105"        ServerName test1</VirtualHost><VirtualHost 192.168.0.105:8000>        DocumentRoot "/var/www/html/192.168.0.105:8000"        ServerName test2</VirtualHost>

2、不同的DocumentRoot下对应的test.html页面内容不同:

[root@localhost ~]% cat /var/www/html/192.168.0.105/test.html 192.168.0.105[root@localhost ~]% cat /var/www/html/192.168.0.105:8000/test.html 192.168.0.105:8000

3、注意,因为使用了多个端口,所以配置文件的全局段,要设置监听每个端口:

Listen 80Listen 8000

4、访问同一IP的不同端口,得到不同的页面:

这里写图片描述

这里写图片描述

注意,一般用户在键入网址时并不知道服务端使用的别的端口,仍会使用默认的80端口。所以这种也不实用。

2.3.3 各虚拟主机使用不同的FQDN

两虚拟主机使用同样的IP和端口,使用不同的FQDN来区分。
虽然请求报文送达服务器时是先通过FQDN解析出IP地址,再发送(FQDN貌似无法起到作用)。但请求报文中包含首部Host,它记录了客户端键入的是哪个FQDN。服务端据此得知FQDN,从而根据FQDN返回对应页面。

1、在配置文件中,设置两虚拟主机监听的IP、端口相同,FQDN不同:

NameVirtualHost 192.168.0.105:80                # 注意,httpd2.2中配置基于FQDN区分的虚拟主机,要使用此命令说明虚拟主机监听的IP和端口,否则语法检查时会被提示使用该指令。httpd2.4中无需这样做<VirtualHost 192.168.0.105:80>        DocumentRoot "/var/www/html/test1"        ServerName www.test1.com</VirtualHost><VirtualHost 192.168.0.105:80>        DocumentRoot "/var/www/html/test2"        ServerName www.test2.com</VirtualHost>

2、不同的DocumentRoot下对应的test.html页面内容不同:

[root@localhost ~]% cat /var/www/html/test1/test.html www.test1.com[root@localhost ~]% cat /var/www/html/test2/test.html www.test2.com

3、由于笔者是用windows的浏览器测试,为避免再创建一个DNS服务器用来解析FQDN的麻烦,所以在windows的hosts文件10中添加这两FQDN的解析记录:

这里写图片描述

4、在浏览器键入不同的FQDN,可看到返回不同的页面:

这里写图片描述

这里写图片描述

3 两个浏览器工具

3.1 curl

curl严格来看并不是浏览器,而是一个文件传输工具。可基于URL模拟http、https、ftp等协议的客户端。
作为传输工具,无法解析html文档,所以输出的是html文档的源码。

使用格式:curl [options] [URL...]

常用选项:

选项 意义 -A 模拟不同的用户代理(即浏览器)访问 -u 访问的页面需用户认证时,此选项输入帐号密码。也可仅输入用户,但会被提示输入密码 -e 伪装referer。即伪装成是从哪个页面跳转而来 -I 仅返回响应报文的http首部,不显示实体数据。相当于请求method是HEAD –cacert 使用https协议访问时,该选项用于指明CA证书位置

仍以192.168.0.105主机作为服务端,验证各选项效果:

选项-A(这里只是验证-A效果,ie6所属的浏览器类型不知道是否就叫ie6):

[root@localhost ~]% curl 192.168.0.105/test.html                   # 不使用任何选项<h1>test page</h1>[root@localhost ~]% tail -n 1 /etc/httpd/logs/access_log           # 日志记录浏览器类型crul……192.168.0.105 - - [31/Oct/2017:21:30:28 +0800] "GET /test.html HTTP/1.1" 200 19 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"[root@localhost ~]% curl -A ie6 192.168.0.105/test.html                # -A指定ie6<h1>test page</h1>[root@localhost ~]% tail -n 1 /etc/httpd/logs/access_log           # 日志记录浏览器类型ie6192.168.0.105 - - [31/Oct/2017:21:31:21 +0800] "GET /test.html HTTP/1.1" 200 19 "-" "ie6"

选项-I:

[root@localhost ~]% curl -I 192.168.0.105/test.html                    # 仅显示响应报文首部信息HTTP/1.1 200 OKDate: Tue, 31 Oct 2017 13:34:31 GMTServer: Apache/2.2.15 (CentOS)Last-Modified: Sun, 29 Oct 2017 04:04:49 GMTETag: "121169-13-55ca79f8d26f6"Accept-Ranges: bytesContent-Length: 19Connection: closeContent-Type: text/html; charset=UTF-8

选项-e:

[root@localhost ~]% curl 192.168.0.105/test.html<h1>test page</h1>[root@localhost ~]% tail -n 1 /etc/httpd/logs/access_log           # 默认访问,日志的referer字段为“-”192.168.0.105 - - [31/Oct/2017:21:36:04 +0800] "GET /test.html HTTP/1.1" 200 19 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"[root@localhost ~]% curl -e www.haha.com 192.168.0.105/test.html   # 使用-e可伪装是从指定的页面跳转而来<h1>test page</h1>[root@localhost ~]% tail -n 1 /etc/httpd/logs/access_log192.168.0.105 - - [31/Oct/2017:21:36:21 +0800] "GET /test.html HTTP/1.1" 200 19 "www.haha.com" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

选项-u:

仍使用标题2.2.3.3中,对/var/www/html/test.html做用户认证的定义。

<Directory "/var/www/html/test.html">        Options None        AllowOverride None        Order allow,deny        Allow from all        Authtype basic        AuthName "/var/www/html/test.html"        AuthUserFile /etc/httpd/my_passwd        Require User user1 user2 user3        AuthGroupFile /etc/httpd/my_group        Require Group User_Group</Directory>
[root@localhost ~]% curl -u user1 192.168.0.105/test.html          # 使用用户user1登录Enter host password for user 'user1':                               # 要求输入密码,笔者在这里仍输入了“user1”<h1>test page</h1>[root@localhost ~]% curl -u user1:user1 192.168.0.105/test.html        # 或是直接输入用户和密码,冒号隔开<h1>test page</h1>

elinks是一个文本浏览器,可解析html文档。默认是在交互模式,按q键退出。

仍以192.168.0.5的test.html为例:

[root@localhost ~]% elinks 192.168.0.105/test.html

这里写图片描述

注意,由于不像windows下的浏览器有各种用于打开不同MIME类型资源的插件,所以它只能打开文本资源(http协议默认就是文本传输),如果页面上有其他类型资源(如图片),会自动过滤掉。

如果不使用交互模式,而是令页面内容一次性输出,使用选项-dump(只是格式会有点不一样):

[root@localhost ~]% elinks -dump 192.168.0.105/test.html                                   test page

3 https

https的服务端监听在tcp的443端口。用于实现加密传输网页。
httpd调用ssl层(介于应用层和传输层之间,可看作应用层的子层),就可作为https的服务端。

SSL会话基于IP,如果把1物理主机上的虚拟主机配置为https的服务端,只能有一个虚拟主机作为https服务端,且不能基于端口、FQDN创建。

下面配置192.168.0.105主机作为https的服务端;192.168.0.102为自建CA。配置、验证https服务端效果:

3.1 自建CA签发证书

1、192.168.0.102主机作为CA,105主机申请证书:

在102主机自建CA:

[root@node2 ~]% openssl genrsa -out /etc/pki/CA/private/cakey.pem      # CA的私钥Generating RSA private key, 1024 bit long modulus.......................++++++.....................................++++++e is 65537 (0x10001)[root@node2 ~]% openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -out /etc/pki/CA/cacert.pem                                                  # CA的自签证书You are about to be asked to enter information that will be incorporatedinto 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 blankFor some fields there will be a default value,If you enter '.', the field will be left blank.-----Country Name (2 letter code) [XX]:CNState or Province Name (full name) []:TaiWan    Locality Name (eg, city) [Default City]:TaipeiOrganization Name (eg, company) [Default Company Ltd]:WCOrganizational Unit Name (eg, section) []:WCCommon Name (eg, your name or your server's hostname) []:node2Email Address []:123456@qq.com[root@node2 ~]% echo 01 > /etc/pki/CA/serial                       # 在证书的序列号文件中添加一个初始序列号[root@node2 ~]% touch /etc/pki/CA/index.txt                            # 创建index.txt作为证书的索引文件,没有此文件会报错提示

在105主机,创建私钥、创建证书申请,把申请传给102主机:

[root@localhost ssl]% openssl genrsa -out node1.private             # 创建私钥Generating RSA private key, 1024 bit long modulus..................++++++.++++++e is 65537 (0x10001)[root@localhost ssl]% openssl req -new -key node1.private -out node1.csr        # 创建证书申请You are about to be asked to enter information that will be incorporatedinto 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 blankFor some fields there will be a default value,If you enter '.', the field will be left blank.-----Country Name (2 letter code) [XX]:CNState or Province Name (full name) []:TaiWanLocality Name (eg, city) [Default City]:TaipeiOrganization Name (eg, company) [Default Company Ltd]:WCOrganizational Unit Name (eg, section) []:WCCommon Name (eg, your name or your server's hostname) []:node1   Email Address []:654321@qq.comPlease enter the following 'extra' attributesto be sent with your certificate requestA challenge password []:An optional company name []:[root@localhost ssl]% scp node1.csr root@192.168.0.102:/etc/httpd/ssl/node1.csr     # 把证书申请复制至102主机root@192.168.0.102's password: node1.csr                                                                                   100%  672     0.7KB/s   00:00

在102主机,签发105主机的证书申请,并传给105主机:

[root@node2 ~]% openssl ca -in /tmp/node1.csr -out /etc/pki/CA/certs/node1.crt     # 签发证书Using configuration from /etc/pki/tls/openssl.cnfCheck that the request matches the signatureSignature ok……[root@node2 ~]% scp /etc/pki/CA/certs/node1.crt root@192.168.0.105:/tmp/node1.crt  # 把签发的证书复制给主机105主机root@192.168.0.105's password: node1.crt                                                                                   100% 3139     3.1KB/s   00:00

openssl自建CA详细过程见http://blog.csdn.net/wangzhenyu177/article/details/78122812

3.2 https配置文件

httpd默认没有加载ssl模块,需使用yum单独安装mod_ssl模块。
安装完成后,可看到多了一个https的配置文件/etc/httpd/conf.d/ssl.conf。该配置文件直接加载了mod_ssl模块,并监听443端口:

LoadModule ssl_module modules/mod_ssl.soListen 443

配置文件中定义一个叫做”_default_”的虚拟主机,指的是如果解析到的IP地址和其他虚拟主机不匹配,则由该虚拟主机来响应。
该虚拟主机中除了定义ServerRoot、DocumentRoot等必须的参数,还定义了https相关的,常用的有

指令 意义 SSL Engine [ on | off ] 如启用ssl,值为on SSLCertificateFile 指定服务器的证书的文件路径 SSLCertificateKeyFile 指定服务器的私钥的文件路径

其他指令如无需要可不修改。

3.3 配置及测试

3.3.1 配置

这里因为是要把192.168.0.105作为https的服务器,所以把虚拟主机_default_改成192.168.0.105:

<VirtualHost 192.168.0.105:443>

根据标题3.1中获得的私钥和自建CA颁发的证书,指定证书路径和私钥路径:

SSLCertificateFile /etc/httpd/ssl/node1.crtSSLCertificateKeyFile /etc/httpd/ssl/node1.private

定义DocumentRoot和ServerName:

DocumentRoot "/var/www/html"ServerName www.node2.com                        # 注意,主机名要和证书上的名字一致,否则会被认为没有通过证书验证

而后注释掉监听80端口的语句”Listen 80”,虽然http和https互不影响,但这里测试https,多一事不如少一事。
注意,https的实现算是httpd的一个模块,所以语法检查、重启服务等都还是httpd的操作命令,”httpd -t”、”service httpd restart”等。

3.3.2 测试

仍访问之前定义过的/var/www/html/test.html:

这里写图片描述

这里提示安全证书有问题,因为地址栏键入的是地址,而证书上的主机名是node1。
因为笔者使用windows上的浏览器测试,所以在windows主机上的hosts文件中,还要加入node1:

这里写图片描述

而后键入地址”https://node1/test.html“:

这里写图片描述

仍有问题,提示无法证明是访问的就是node1主机11,因为windows上的浏览器并没有添加信任笔者自建的CA(就是192.168.0.102主机)。

于是添加自建CA的自签证书(/etc/pki/CA/cacert.pem文件)到该浏览器。由于添加的目的是让客户端主机信任自建CA所颁发的证书,所以会被系统特别提示:

这里写图片描述

这里使用了一个向导程序添加,实际对各浏览器添加信任的颁发机构可能略有不同,但差不多,这里不赘述添加证书过程了。

主机node2作为信任CA添加至windows主机的浏览器上了,于是再访问https://node1.test.html就正常显示内容了:

这里写图片描述

使用IE还可查看加密情况:

这里写图片描述

至此就实现了https加密通信。

4 httpd2.4与2.2的部分不同之处

2.4比2.2改进的地方很多,这里列出和上述提到的各特性与httpd2.2的不同:

  • MPM在2.4中也变成一个可装载、卸载的模块了。启动时仅需主程序/usr/sbin/httpd即可。prefork、worker、event模式可切换;
  • 配置文件多了/etc/httpd/conf.modules.d/*.modules用于各模块的配置(包括MPM等),而2.2是写在主配置文件中;
  • event在2.4不是测试,可正常使用了;
  • 长连接时长可定义至毫秒级(使用ms作单位);
  • 基于FQDN的虚拟主机,不再需要NameVirtualHost指令;
  • 增加了新指令AllowOverrideList,以增强AllowOverride;
  • mod_remoteip,用于基于IP的访问控制。且2.4默认所有目录都是禁止访问的,需显式定义访问权限。不再使用allow、deny指令,使用新机制:

    • Require all granted,允许所有用户访问
    • Require all denied,拒绝所有用户访问
    • Require [not] IP,允许、拒绝指定IP访问。也可以是IP段
    • Require [not] HOST,允许、拒绝指定主机名访问。可以是具体主机名也可以是域名
    • 如果有多条限制,则需写在容器(容器名不限制)中。比如允许所有主机访问,但拒绝192.168.0.1:

      <Require>Require all grantedRequire not 192.168.0.1</Require>

(完)


  1. MIME:Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型。
    MIME规定了用符号表示各类型数据的方法,即各媒体类型如何表示。服务端只要把MIME类型放在响应报文的首部信息中,浏览器可识别服务器返回的资源是哪种媒体类型,从而自动用对应的应用程序(就是浏览器插件),打开对应类型的资源。这样就实现了让http这种文本传输的协议,能够传输图片、音频等多种媒体类型。 ↩
  2. 虽然http协议工作机制简单,但实际使用中,客户端的请求往往不是直接到达服务器,而是先到达代理服务器(可能要经过多个)。
    这样的目的是在代理服务器使用缓存、负载均衡等,可有效提高访问效率,也减小服务器压力。 ↩
  3. 为加快服务端响应速度、降低服务器压力、降低带宽占用等,本地浏览器会把一些静态资源(如图片等)缓存下来。再获取同样资源时,只需发出条件式请求:如果指定资源未发生改变,则继续使用缓存内容;如果改变,则重新从服务器获取。 ↩
  4. 每个子进程逐个处理请求。比如5个子进程共处理50个,那么每个就处理10个。但同一时间仅能处理1个,这样逐个处理完10个。 ↩
  5. fork正是linux中用于创建进程的函数。 ↩
  6. 默认定义为何这样不得而知,看上去没什么用。 ↩
  7. 这里网段的写法很灵活,可以有掩码,掩码可以写全也可用长度表示;也可以不要掩码。也可直接写成192.0.0,即仅写明网络号,后面的主机号省略也可以。 ↩
  8. 注意这和很多盈利性网站要求用户登录不同,那些网站使用的是专门开发的用于认证身份的程序。httpd自带的这个认证是比较简单的。不常用 ↩
  9. 当记录的用户较多时,设置各用户的访问权限(比如允许哪些用户登录)比较繁琐,可把用户划分为不同的组,以组来指派用户权限就方便多了 ↩
  10. windows的hosts文件在C盘windows/system32/drivers/etc/hosts ↩
  11. 虽然此时选择继续通信,通信过程是加密的。如使用IE浏览器更可清楚看到,点击地址栏的”https”,会显示通信过程是加密的,只是身份无法验证。因为https服务端是启动的,所以保证了通信过程是加密的。而身份验证需要客户端信任颁发证书的CA,而且服务端的CA要和服务器的主机名一致。
    通信内容加密了,无法验证身份,就无法防止中间人攻击。 ↩
原创粉丝点击