httpd
httpd介绍
-
20世纪90年代初,国家超级计算机应用中心NCSA开发
-
1995年开源社区发布apache(a patchy server)
- ASF: apache software foundation
官网:www.apahce.org - FSF:Free Software Foundation
- ASF: apache software foundation
-
httpd的特性:
- 高度模块化:core + modules
- DSO:Dynamic Shared Object 动态加/卸载
- MPM:multi-processing module多路处理模块
MPM工作模式
IO模型:多个用户同时发请求至web服务器,web服务器怎么处理?在Apache中有三种工作模式,称为MPM的工作模式。
prefork:
- 多进程IO模型,每个进程响应一个请求,默认模型
- 一个主进程:生成和回收n个子进程,创建套接字,不响应请求
- 多个子进程:工作的work进程,每个进程处理一个请求,系统初始化时,预先生成多个空闲进程,等待请求,最大不超过1024个。
worker:
- 复用的多进程IO模型,多进程多线程,IIS使用此模型
- 一个主进程:生成m个子进程,每个子进程负责生成n个线程,每个线程响应一个请求,并发响应请求:m*n
event:
-
事件驱动模型(worker模型的变种)
- 一个主进程:生成m个子进程,每个子进程负责生成n个线程,每个线程响应一个请求,并发响应请求:m*n,有专门的监控线程来管理这些keep-alive类型的线程,当有真实请求时,将请求传递给服务线程,执行完毕后,又允许释放。这样增强了高并发场景下的处理请求能力。
httpd-2.2:event 测试版,centos6默认
httpd-2.4:event 稳定版,centos7默认
prefork MPM
- prefork MPM:预派生模式,有一个主控进程,然后生成多个子进程,每个子进程有一个独立的线程响应用户请求,相对比较占用内存,但是比较稳定,可以设置最大和最小进程数,是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景。
- 优点:稳定
- 缺点:慢,占用资源,不适合高并发场景
worker MPM
- worker MPM:是一种多进程和多线程混合模型,有一个控制进程,启动多个子进程,每个子进程里面包含固定的线程,使用线程来处理请求,当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,因此可以承受高并发。
- 优点:相比prefork占用的内存较少,可以同时处理更多的请求
- 缺点:使用keep-alive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被占用占据,也会导致在高并发场景下没有服务线程可用。(该问题在prefork模式下,同样会发生)
event MPM
- event MPM:Apache中最新的模式,属于事件驱动模型(epoll),每个进程响应多个请求,在现在版本里的已经是稳定可用的模式。它和worker模式很像,最大的区别在于,它解决了keep-alive场景下,长期被占用的线程的资源浪费问题(某些线程因为被keep-alive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)。event MPM中,会有一个专门的线程来管理这些keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力
- event只在有数据发送的时候才开始建立连接,连接请求才会触发工作线程,即使用了TCP的一个选项,叫做延迟接受连接TCP_DEFER_ACCEPT,加了这个选项后,若客户端只进行TCP连接,不发送请求,则不会触发Accept操作,也就不会触发工作线程去干活,进行了简单的防攻击(TCP连接)
- 优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
- 缺点:没有线程安全控制
httpd2.4
httpd功能特性
- 虚拟主机
- IP、Port、FQDN
- CGI:Common Gateway Interface,通用网关接口
- 反向代理
- 负载均衡
- 路径别名
- 丰富的用户认证机制
basic
digest - 支持第三方模块
httpd-2.4新特性
- MPM支持运行为DSO机制;以模块形式按需加载
- event MPM生产环境可用
- 异步读写机制
- 支持每模块及每目录的单独日志级别定义
- 每请求相关的专用配置
- 增强版的表达式分析式
- 毫秒级持久连接时长定义
- 基于FQDN的虚拟主机不需要NameVirutalHost指令
- 新指令,AllowOverrideList
- 支持用户自定义变量
- 更低的内存消耗
Httpd 安装
- 版本:
CentOS 7: 2.4
CentOS 6: 2.2 - 安装方式:
rpm:centos发行版,稳定,建议使用
编译:定制或特殊需求 - CentOS 7程序环境:httpd-2.4
配置文件:
/etc/httpd/conf/httpd.conf
/etc/httpd/conf.d/*.conf
检查配置语法:
httpd –t
Httpd 程序环境
- 服务单元文件: /usr/lib/systemd/system/httpd.service
配置文件:/etc/sysconfig/httpd - 服务控制和启动:
systemctl enable|disable httpd.service
systemctl {start|stop|restart|status|reload} httpd.service - 站点网页文档根目录:
/var/www/html - 模块文件路径:
/etc/httpd/modules
/usr/lib64/httpd/modules - 主程序文件:
/usr/sbin/httpd - 主进程文件:
/etc/httpd/run/httpd.pid - 日志文件目录:
/var/log/httpd
access_log: 访问日志
error_log:错误日志 - 帮助文档包:
httpd-manual
Httpd 常见配置
- httpd配置文件的组成:
- 主要组成
Global Environment
Main server configuration
virtual host - 配置格式:directive value
directive 不区分字符大小写
value 为路径时,是否区分大小写,取决于文件系统 - 官方帮助
http://httpd.apache.org/docs/2.4/
httpd的常见配置
【实验规划】
- centos 7.6
- httpd:2.4.6
- 安装方式:yum install httpd
- #systemctl start --now httpd 设为开机启动并立即启动
- 修改httpd的各种常见配置:
配置文件:
/etc/httpd/conf/httpd.conf
/etc/httpd/conf.d/*.conf
【服务器版本信息】
- yum安装默认的server信息:Server: Apache/2.4.6 (CentOS)
这样web server的版本就暴露了存在安全隐患 - ServerTokens
Description: Configures the Server HTTP response header
Syntax: ServerTokens Major|Minor|Min[imal]|Prod[uctOnly]|OS|Full
Default: ServerTokens Full
Context: server config
Status: Core
Module: core
ServerTokens Full (or not specified)
Server sends (e.g.): Server: Apache/2.4.2 (Unix) PHP/4.2.2 MyMod/1.2
ServerTokens Prod[uctOnly]
Server sends (e.g.): Server: Apache
ServerTokens Major
Server sends (e.g.): Server: Apache/2
ServerTokens Minor
Server sends (e.g.): Server: Apache/2.4
ServerTokens Min[imal]
Server sends (e.g.): Server: Apache/2.4.2
ServerTokens OS
Server sends (e.g.): Server: Apache/2.4.2 (Unix)
- 建议使用:ServerTokens Prod
- #curl -I 192.168.38.17 只查看响应报文头部
【监听的IP和Port】
- Listen [IP:]PORT
(1) 省略IP表示为本机所有IP
(2) Listen指令至少一个,可重复出现多次
Description: IP addresses and ports that the server listens to
Syntax: Listen [IP-address:]portnumber [protocol]
Context: server config
Status: MPM
Module: event, worker, prefork, mpm_winnt, mpm_netware, mpmt_os2
Compatibility: The protocol argument was added in 2.1.5
For example, to make the server accept connections on both port 80 and port 8000, use:
Listen 80
Listen 8000
To make the server accept connections on two specified interfaces and port numbers, use
Listen 192.170.2.1:80
Listen 192.170.2.5:8000
IPv6 addresses must be surrounded in square brackets, as in the following example:
Listen [2001:db8::a00:20ff:fea7:ccea]:80
【持久连接】
-
Persistent Connection:连接建立,每个资源获取完成后不会断开连接,而是继续等待其它的请求完成,默认关闭持久连接
- 断开条件:时间限制:以秒为单位, 默认5s,httpd-2.4 支持毫秒级
- 副作用:对并发访问量大的服务器,持久连接会使有些请求得不到响应
- 折衷:使用较短的持久连接时间
- 设置:KeepAlive On|Off
KeepAliveTimeout 15
MaxKeepAliveRequests 500 持久连接最大接收的请求数 - 测试:telnet WEB_SERVER_IP PORT
GET /URL HTTP/1.1
Host: WEB_SERVER_IP
Description: Enables HTTP persistent connections
Syntax: KeepAlive On|Off
Default: KeepAlive On
Context: server config, virtual host
Status: Core
Module: core
【动态的共享对象】
-
DSO: Dynamic Shared Object
加载动态模块配置,不需重启即生效
/etc/httpd/conf/httpd.conf
Include conf.modules.d/*.conf
配置指定实现模块加载格式:
LoadModule <mod_name> <mod_path>
模块文件路径可使用相对路径:相对于ServerRoot(默认/etc/httpd) -
动态模块路径: /usr/lib64/httpd/modules/
-
查看静态编译的模块
httpd -l -
查看静态编译及动态装载的模块
httpd –M -
MPM( Multi-Processing Module)多路处理模块
prefork, worker, event -
切换使用的MPM
/etc/httpd/conf.modules.d/00-mpm.conf
启用要启用的MPM相关的LoadModule指令即可
prefork的配置:
StartServers 2000
MinSpareServers 2000
MaxSpareServers 2000
ServerLimit 2560 最多进程数,最大值 20000
MaxRequestWorkers 2560 最大的并发连接数,默认256
MaxRequestsPerChild 4000 子进程最多能处理的请求数量。在处理MaxRequestsPerChild 个请求之后,子进程将会被父进程终止,这时候子进程占用的内存就会释放(为0时永远不释放)
MaxConnectionsPerChild 4000 子进程最多能处理的连接数量,代替上面MaxRequestsPerChild ,httpd.2.4.9开始支持
worker的配置:
ServerLimit 16
StartServers 2
MaxRequestWorkers 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
【存放主页的修改】
- 定义’Main’ server的文档页面路径
DocumentRoot “/path”
文档路径映射:
DocumentRoot指向的路径为URL路径的起始位置
示例:
DocumentRoot "/app/data“
http://HOST:PORT/test/index.html --> /app/data/test/index.html
注意:SELinux和iptables的状态 - 在httpd2.4中一个目录想要被用户访问,必须明确授权!
- 定义站点主页面
DirectoryIndex index.html
【站点访问控制常见机制】
- 可基于两种机制指明对哪些资源进行何种访问控制
- 访问控制机制有两种:客户端来源地址,用户账号
文件系统路径:
<Directory “/path">
...
</Directory>
<File “/path/file”>
...
</File>
<FileMatch "PATTERN">
...
</FileMatch>
URL路径:
<Location "">
...
</Location>
<LocationMatch "">
...
</LocationMatch>
<Directory>中“基于源地址”实现访问控制
Options Indexes FollowSymLinks 允许查看软链接允许查看索引
(1) Options:后跟1个或多个以空白字符分隔的选项列表
在选项前的+,- 表示增加或删除指定选项
常见选项:
Indexes:指明的URL路径下不存在与定义的主页面资源相符的资源文件时,返回索引列表给用户
FollowSymLinks:允许访问符号链接文件所指向的源文件
None:全部禁用
All: 全部允许
(2) AllowOverride
与访问控制相关的哪些指令可以放在指定目录下的.htaccess(由AccessFileName指定)文件中,覆盖之前的配置指令
只对<directory>语句有效
AllowOverride All: .htaccess中所有指令都有效
AllowOverride None: .htaccess 文件无效
AllowOverride AuthConfig .htaccess 文件中,除了AuthConfig 其它指令都无法生效
主配置文件中有拒绝所有用户访问的.ht文件的相关配置
<Files ".ht*">
Require all denied
</Files>
基于IP的访问控制:
无明确授权的目录,默认拒绝
允许所有主机访问:Require all granted
拒绝所有主机访问:Require all denied
控制特定的IP访问:
Require ip IPADDR:授权指定来源的IP访问
Require not ip IPADDR:拒绝特定的IP访问
控制特定的主机访问:
Require host HOSTNAME:授权特定主机访问
Require not host HOSTNAME:拒绝
HOSTNAME:
FQDN:特定主机
domin.tld:指定域名下的所有主机
示例:
不能有失败,至少有一个成功匹配才成功,即失败优先
<RequireAll>
Require all granted
Require not ip 172.16.1.1 拒绝特定IP
</RequireAll>
多个语句有一个成功,则成功,即成功优先
<RequireAny>
Require all denied
require ip 172.16.1.1 允许特定IP
</RequireAny>
【日志设定】
-
日志类型
- 访问日志
- 错误日志
-
错误日志:
- ErrorLog logs/error_log
- LogLevel warn
- LogLevel 可选值: debug, info, notice, warn,error, crit, alert, emerg
-
访问日志:
- 定义日志格式:LogFormat format strings
LogFormat “%h %l %u %{%F %T}t “%r” %>s %b “%{Referer}i” “%{User-Agent}i”” testlog - 使用日志格式:
CustomLog logs/access_log testlog
- 定义日志格式:LogFormat format strings
-
参考帮助:
-
http://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats
-
%h 客户端IP地址
-
%l 远程用户,启用mod_ident才有效,通常为减号“-”
-
%u 验证(basic,digest)远程用户,非登录访问时,为一个减号“-”
-
%t 服务器收到请求时的时间
-
%r First line of request,即表示请求报文的首行;记录了此次请求的“方法”,“URL”以及协议版本
-
%>s 响应状态码
-
%b 响应报文的大小,单位是字节;不包括响应报文http首部
-
%{Referer}i 请求报文中首部“referer”的值;即从哪个页面中的超链接跳转至当前页面的
-
%{User-Agent}i 请求报文中首部“User-Agent”的值;即发出请求的应用程序
-
【默认字符集】
- 设定默认字符集
- AddDefaultCharset UTF-8 此为默认值
- 中文字符集:GBK, GB2312, GB18030
【路径别名】
- 格式:Alias /URL/ “/PATH/”
- DocumentRoot “/www/htdocs”
- http://www.xxx.com/download/bash.rpm
==>/www/htdocs/download/bash.rpm
- http://www.xxx.com/download/bash.rpm
- Alias /download/ “/rpms/pub/”
- http://www.xxx.com/download/bash.rpm
==>/rpms/pub/bash.rpm - http://www.xxx.com/images/logo.png
==>/www/htdocs/images/logo.png
- http://www.xxx.com/download/bash.rpm
示例:
alias /news /opt/news
<directory /opt/news>
require all granted
</directory>
注意:目录需要授权
【基于用户的访问控制】
- 认证质询:WWW-Authenticate:响应码为401,拒绝客户端请求,并说明要求客户端提供账号和密码
- 认证:Authorization:客户端用户填入账号和密码后再次发送请求报文;认证通过时,则服务器发送响应的资源
- 认证方式两种:
- basic:明文
- digest:消息摘要认证,兼容性差
- 安全域:需要用户认证后方能访问的路径;应该通过名称对其进行标识,以便于告知用户认证的原因
- 用户的账号和密码
- 虚拟账号:仅用于访问某服务时用到的认证标识
- 存储:文本文件,SQL数据库,ldap目录存储,nis等
basic认证配置示例:
(1) 定义安全域
<Directory “/path">
Options None
AllowOverride None
AuthType Basic
AuthName "String“
AuthUserFile "/PATH/HTTPD_USER_PASSWD_FILE"
Require user username1 username2 ...
</Directory>
允许账号文件中的所有用户登录访问:
Require valid-user
(2) 提供账号和密码存储(文本文件)
使用专用命令完成此类文件的创建及用户管理
htpasswd [options] /PATH/HTTPD_PASSWD_FILE username
-c 自动创建文件,仅应该在文件不存在时使用
-p 明文密码
-d CRYPT格式加密,默认
-m md5格式加密
-s sha格式加密
-D 删除指定用户
基于组账号进行认证
(1) 定义安全域
<Directory “/path">
AuthType Basic
AuthName "String“
AuthUserFile "/PATH/HTTPD_USER_PASSWD_FILE"
AuthGroupFile "/PATH/HTTPD_GROUP_FILE"
Require group grpname1 grpname2 ...
</Directory>
(2) 创建用户账号和组账号文件
组文件:每一行定义一个组
GRP_NAME: username1 username2 ...
- 远程客户端和用户验证的控制
- Satisfy ALL|Any
- ALL 客户机IP和用户验证都需要通过才可以
- Any客户机IP和用户验证,有一个满足即可
【实现家目录的共享】
- 实现用户家目录的http共享
- 基于模块mod_userdir.so实现
- 相关设置:
vim /etc/httpd/conf.d/userdir.conf
<IfModule mod_userdir.c> #UserDir disabled
UserDir public_html #指定共享目录的名称
</IfModule>
准备目录,允许Apache用户具有访问权限
su – wang;mkdir ~/public_html
setfacl –m u:apache:x ~wang
授权对应的家目录可以进行访问
共享的目录只是~/public_html对应家目录中的这个目录
实现步骤:
① vim /etc/httpd/conf.d/userdir.conf
# UserDir disabled 指定共享目录的名称
UserDir public_html
② 创建共享目录
mkdir /home/wang/public_html
③授权Apache用户可以访问wang用户的家目录
setfacl -m apache:x /home/wang/
④对/home/wang/public_html进行授权
<directory /home/wang/public_html>
require all granted
</directory>
- 访问
http://localhost/~wang/index.html
【ServerSignature】
- ServerSignature On | Off | EMail
默认值Off,当客户请求的网页并不存在时,服务器将产生错误文档,如果打开 了 ServerSignature选项,错误文档的最后一行将包含服务器的名字、Apache的版本等信息,如果不对外显示这些信息,就可以将这个参数设置为Off设置为Email,将显示ServerAdmin 的Email提示
【TraceEnable】
- TraceEnable [on|off|extended]
- 是否支持trace方法,默认on,基于安全风险,建议关闭
- TraceEnable 有安全风险,一般关闭
【status页面】
LoadModule status_module modules/mod_status.so
<Location "/status">
SetHandler server-status
</Location>
ExtendedStatus On 显示扩展信息
- 可以利用status对Apache进行监控,实现健康性检查,基于安全可以利用基于ip访问
【虚拟主机】
- 站点标识: socket
- IP相同,但端口不同
- IP不同,但端口均为默认端口
- FQDN不同:请求报文中首部 Host: www.xxx.com
- 有三种实现方案:
- 基于ip:为每个虚拟主机准备至少一个ip地址
- 基于port:为每个虚拟主机使用至少一个独立的port
- 基于FQDN:为每个虚拟主机使用至少一个FQDN
基于主机头:自动从访问的URL中取出来的。例如:访问http://www.xxx.com
主机头就是:www.xxx.com
apache可以根据访问的主机头返回对应主机头对应的网站页面
基于端口号:
# vim conf.d/test.conf
listen 8001
listen 8002
listen 8003
<virtualhost *:8001>
documentroot /data/www1
<directory /data/www1>
require all granted
</directory>
customlog "logs/access_www1_log" combined
</virtualhost>
<virtualhost *:8002>
documentroot /data/www2
<directory /data/www2>
require all granted
</directory>
customlog "logs/access_www2_log" combined
</virtualhost>
<virtualhost *:8003>
documentroot /data/www3
<directory /data/www3>
require all granted
</directory>
customlog "logs/access_www3_log" combined
</virtualhost>
测试:192.168.38.27
curl 192.168.38.17:8001
curl 192.168.38.17:8002
curl 192.168.38.17:8003
总结:
此类做法用户访问主页需要输入端口号,不宜采用
基于ip实现:
首先准备三个ip:(临时添加)
# ip a a 192.168.38.101/24 dev eth0
# ip a a 192.168.38.102/24 dev eth0
# ip a a 192.168.38.103/24 dev eth0
# vim conf.d/test.conf
<virtualhost 192.168.38.101:80>
documentroot /data/www1
<directory /data/www1>
require all granted
</directory>
customlog "logs/access_www1_log" combined
</virtualhost>
<virtualhost 192.168.38.102:80>
documentroot /data/www2
<directory /data/www2>
require all granted
</directory>
customlog "logs/access_www2_log" combined
</virtualhost>
<virtualhost 192.168.38.103:80>
documentroot /data/www3
<directory /data/www3>
require all granted
</directory>
测试:192.168.38.27主机
# curl 192.168.38.101
/data/www1/
# curl 192.168.38.102
/data/www2/
# curl 192.168.38.103
总结:
基于ip实现虚拟主机需要申请多个共有ip,花费成本和共有ip,不宜采用
基于主机头:推荐使用
# vim conf.d/test.conf
<virtualhost *:80>
documentroot /data/www1
servername www.a.com
<directory /data/www1>
require all granted
</directory>
customlog "logs/access_www1_log" combined
</virtualhost>
<virtualhost *:80>
documentroot /data/www2
servername www.b.com
<directory /data/www2>
require all granted
</directory>
customlog "logs/access_www2_log" combined
</virtualhost>
<virtualhost *:80>
documentroot /data/www3
servername www.c.com
<directory /data/www3>
require all granted
</directory>
customlog "logs/access_www3_log" combined
</virtualhost>
测试主机ip:192.168.38.27 由于没有搭建DNS服务,不能采用DNS解析,直接使用/etc/hosts文件进行解析
# vim /etc/hosts
192.168.38.17 www.a.com www.b.com www.c.com
~]# curl www.a.com
/data/www1/
~]# curl www.b.com
/data/www2/
~]# curl www.c.com
/data/www3/
总结:
基于主机头实现虚拟主机是比较理想和常用的实现方式