打算写一篇关于httpd的文档,不由得就想到了TCP/IP协议、http协议、socket、域名解析、负载均衡......

那就从这开始写吧,但是我又想到了更多:IPC、端口、httpd的工作模式、httpd的连接模式、虚拟主机、反向代理......

想了这么多,我居然不知道该如何下笔了。于是心里最底层的懒散就开始作祟了,进而一拖再拖,一度有索性不写的想法。

这不是个好的想法,最后决定,就从最直接的实战演练开始吧。

本来我觉得介绍httpd,应该有大量的篇幅来说明前期的理论。但是水平有限,不能系统分类的来说明。

以下就从具体的操作步骤入手,然后在配置中夹杂相关理论。


说明一点:Apache和httpd的区别

Apache:Apache软件基金会(也就是Apache Software Foundation,简称为ASF),是专门为运作一个开源软件项目的Apache 的团体提供支持的非盈利性组织,这个开源软件的项目就是 Apache 项目。

httpd:httpd是超文本传输协议(HTTP)服务器的主程序。被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池。说白了,httpd是Apache组织下维护的一个开源软件。


本文大纲:

1、前期准备

    RHEL6.7、关闭ipables、selinux、yum源配置

2、安装

    yum安装

    安装包介绍

3、程序环境

    配置文件

    服务脚本

    主程序文件

    日志文件

    模块文件路径

    服务控制和启动

4、配置

    修改监听的IP和PORT

    持久连续

    MPM 

    虚拟主机

    ......

    


1、前期准备

Linux系统版本为RHEL6.7

IP为10.10.10.4

[root@wlm yum.repos.d]# cat /etc/issue
Red Hat Enterprise Linux Server release 6.7 (Santiago)
Kernel \r on an \m

关闭ipables、selinux

修改selinux的配置文件,关闭selinux后重启电脑

[root@wlm yum.repos.d]# /etc/init.d/iptables stop
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]
[root@wlm yum.repos.d]# setenforce=0 # 不重启关闭selinux,这个设置只对当前shell有效,从新登陆或是切换用户、打开子shell,在开启
[root@wlm yum.repos.d]# chkconfig iptables off # 永久关闭iptables
[root@wlm yum.repos.d]# sed -i s/=enforcing/=disabled/g /etc/selinux/config #从新启动电脑,selinux永久关闭

yum源配置

配置本地yum源

[root@wlm yum.repos.d]# rm -f /etc/yum.repos.d/*
[root@wlm yum.repos.d]# vim /etc/yum.repos.d/yum.repo
    [yum]
    name=RHEL6.7
    baseurl=file:///media/cdrom
    enabled=1
    gpgcheck=0
[root@wlm yum.repos.d]# mkdir /media/cdrom
[root@wlm yum.repos.d]# mount /dev/cdrom /media/cdrom/
mount: block device /dev/sr0 is write-protected, mounting read-only

2、安装

安装包介绍

安装版本httpd-2.2

yum安装

在安装前使用rpm -q httpd查看httpd-2.2是否被安装,若已经安装了其他版本的,

使用rpm -e httpd卸载

yum install httpd  # RHEL6.7默认安装的是httpd-2.2

3、程序环境

配置文件:

     /etc/httpd/conf/httpd.conf

     /etc/httpd/conf.d/*.conf

服务脚本:

    /etc/rc.d/init.d/httpd

脚本配置文件:/etc/sysconfig/httpd

主程序文件:

     /usr/sbin/httpd

     /usr/sbin/httpd.event

     /usr/sbin/httpd.worker

日志文件:

    /var/log/httpd:

    access_log:访问日志

    error_log:错误日志

站点文档:

    /var/www/html

模块文件路径:

    /usr/lib64/httpd/modules


服务控制和启动:

     chkconfig  httpd  on|off

     service  {start|stop|restart|status|configtest|reload}  httpd

4、配置

1)修改监听的IP和PORT

套接字通信(Socket):IPC(进程间通信)的一种实现,允许位于不同主机(也可以是同一主机)上的进程之间进行通信;
Socket API(封装了内核中的socket通信相关的系统调用)
Web服务器就是C/S架构,基于套接字通信的机制。
配置说明:
Listen  [IP:]PORT
(1) 省略IP表示为0.0.0.0,代表本机所有IP;
(2) Listen指令可重复出现多次;
Listen  80
Listen  8080
(3) 修改监听socket,重启服务进程方可生效;

实际操作:

[root@wlm yum.repos.d]# vim /etc/httpd/conf/httpd.conf
    # Listen 12.34.56.78:80
    Listen 80    # 监听本机所有IP的80和8080端口
    Listen 8080
[root@wlm ~]# httpd -t     # 语法检测
httpd: apr_sockaddr_info_get() failed for wlm # #此错误忽略,是因为没有设置ServerName,后面会讲
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
Syntax OK
[root@wlm yum.repos.d]# /etc/init.d/httpd restart    # 重启进程
Stopping httpd:                                            [FAILED]
Starting httpd: httpd: apr_sockaddr_info_get() failed for wlm    #此错误忽略,是因为没有设置ServerName,后面会讲
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

测试:从浏览器访问,默认是访问80端口,出现的是默认测试页面

linux上的apache/httpd2.2安装配置详解_第1张图片


2)持久连续

保持连接(长连接):keep-alive通过特定的时间和请求资源数量来限制
非保持连接(短连接):一次资源请求一次连接(三次握手四次挥手)

tcp的短连接是每请求一次资源,就进行三次握手和四次挥手,这样太繁琐,所以httpd可以在服务器端设置持久连接。
持久连续(Persistent Connection):tcp连续建立后,每个资源获取完成后不全断开连接,而是继续等待其它资源请求的进行; 
如何断开?
     数量限制
     时间限制
副作用:对并发访问量较大的服务器,长连接机制会使得后续某些请求无法得到正常 响应;
折衷:使用较短的持久连接时长,以及较少的请求数量;
配置说明:
    KeepAlive  On|Off #是否打开长连接
    KeepAliveTimeout  15    #长连接时间,默认是S
    MaxKeepAliveRequests  100    #数量限制,100个请求以内
测试方式:
    telnet  WEB_SERVER_IP  PORT
    GET  /URL  HTTP/1.1
    Host: WEB_SERVER_IP

实际操作:

[root@wlm yum.repos.d]# vim /etc/httpd/conf/httpd.conf
KeepAlive On    # 开启
KeepAliveTimeout 15 # 15s的长连接
# 重新载入配置:
[root@wlm yum.repos.d]# /etc/init.d/httpd reload
Reloading httpd: 
# 测试:
[root@ns1 named]# telnet 10.10.10.4 80
Trying 10.10.10.4...
Connected to 10.10.10.4.
Escape character is '^]'.
GET /index.html HTTP/1.1    # 输入
Host:10.10.10.4    # 输入,然后两次回车,会连接15s后断开

3)MPM 模块

MPM:Multipath processing Modules (多路处理模块)
(1)prefork:多进程模型,每个进程响应一个请求;
一个主进程:负责生成子进程及回收子进程;负责创建套接字;负责接收请求,并将其派发给某子进程进行处理;
      n个子进程:每个子进程处理一个请求;
     工作模型:会预先生成几个空闲进程,随时等待用于响应用户请求;最大空闲和最小空闲;
    (2)worker:多进程多线程模型,每线程处理一个用户请求;
     一个主进程:负责生成子进程;负责创建套接字;负责接收请求,并将其派发给某子进程进行处理;
    多个子进程:每个子进程负责生成多个线程;
    每个线程:负责响应用户请求;
    并发响应数量:m*n
m:子进程数量
n:每个子进程所能创建的最大线程数量;
   (3)event:事件驱动模型,多进程模型,每个进程响应多个请求;
   一个主进程 :负责生成子进程;负责创建套接字;负责接收请求,并将其派发给某子进程进行处理;
   子进程:基于事件驱动机制直接响应多个请求;
httpd-2.2: 仍为测试使用模型;
httpd-2.4:event可生产环境中使用;

httpd-2.2不支持同时编译多个MPM模块,所以只能编译选定要使用的那个;CentOS 6的rpm包为此专门提供了三个应用程序文件,httpd(prefork), httpd.worker, httpd.event,分别用于实现对不同的MPM机制的支持;确认现在使用的是哪下程序文件的方法:
ps  aux  | grep httpd
默认使用的为/usr/sbin/httpd,其为prefork的MPM模块 ;
查看httpd程序的模块列表:
查看静态编译的模块:
# httpd  -l
查看静态编译及动态编译的模块:
# httpd  -M

更换使用httpd程序,以支持其它MPM机制;
vim /etc/sysconfig/httpd
HTTPD=/usr/sbin/httpd.{worker,event}

注意:重启服务进程方可生效

MPM配置:/etc/httpd/conf/httpd.conf
prefork的配置

StartServers       8 # 服务器刚启动是就启动多少个空闲进程
MinSpareServers    5 # 最小空闲进程数
MaxSpareServers   20 # 最大空闲进程数
ServerLimit      256 # 最大启动多少个进程
MaxClients       256 # 最大启动多少个进程响应客户端请求。最大并发数
MaxRequestsPerChild  4000 # 每个进程最多可以处理多少个请求,达到4000个就销毁一个进程


worker的配置:

StartServers         4 # 服务器刚启动是就启动多少个空闲进程
MaxClients         300 # 最大启动多少个进程响应客户端请求。最大并发数
MinSpareThreads     25 # 最小空闲进程数
MaxSpareThreads     75 # 最大空闲进程数
ThreadsPerChild     25 # 每个进程最大可生成多少个线程
MaxRequestsPerChild  0 # 进程处理的请求数量不受限制


PV:Page View:日点击量,有多少个页面被点击

实际操作:

[root@wlm yum.repos.d]# ps aux | grep httpd    #默认为prefork模式
root      6236  0.0  0.4 186024  4340 ?        Ss   17:04   0:01 /usr/sbin/httpd
apache    6326  0.0  0.3 186024  2940 ?        S    17:35   0:00 /usr/sbin/httpd
apache    6327  0.0  0.2 186024  2584 ?        S    17:35   0:00 /usr/sbin/httpd

[root@wlm ~]# httpd -l
Compiled in modules:
  core.c
  prefork.c   
  http_core.c
  mod_so.c
[root@wlm ~]# httpd -M
httpd: apr_sockaddr_info_get() failed for wlm
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
Loaded Modules:
 core_module (static)
 mpm_prefork_module (static)
 http_module (static)
 so_module (static)
 auth_basic_module (shared)
 ...
 
[root@wlm ~]# vim /etc/sysconfig/httpd
    HTTPD=/usr/sbin/httpd.worker # 默认是prefork模式,启用为worker模式
# 保存退出

[root@wlm ~]# vim /etc/httpd/conf/httpd.conf # 可以在这里优化,具体的介绍看上面的理论说明
    
    StartServers         4
    MaxClients         300
    MinSpareThreads     25
    MaxSpareThreads     75
    ThreadsPerChild     25
    MaxRequestsPerChild  0
    
# 保存退出,重启生效,切记,从起前要进行语法检测

4)DSO(dynamic shared object):动态共享对象

配置指定实现模块加载/etc/httpd/conf/httpd.conf
LoadModule    
模块文件路径可使用相对路径:
相对于ServerRoot(默认/etc/httpd)
[root@wlm ~]# vim /etc/httpd/conf/httpd.conf
    # LoadModule foo_module modules/mod_foo.so    #可以直接指定要加载的模块
    #
    LoadModule auth_basic_module modules/mod_auth_basic.so
    LoadModule auth_digest_module modules/mod_auth_digest.so
    LoadModule authn_file_module modules/mod_authn_file.so
    LoadModule authn_alias_module modules/mod_authn_alias.so
    LoadModule authn_anon_module modules/mod_authn_anon.so
    LoadModule authn_dbm_module modules/mod_authn_dbm.so
    LoadModule authn_default_module modules/mod_authn_default.so
    LoadModule authz_host_module modules/mod_authz_host.so
    LoadModule authz_user_module modules/mod_authz_user.so

5)定义'Main' server的文档页面路径

在/etc/httpd/conf/http.conf
DocumentRoot  ""
例如:
DocumentRoot "/web/host1"

文档路径映射:
DoucmentRoot指向的路径为URL路径的起始位置
其相当于站点URL的根路径;
(FileSystem) /web/host1/index.html  -->  (URL)  /index.html
/web/host1/相当于是httpd服务的跟了,例如我们访问的是系统目录/web/host1/下的index.html,
在使用http协议访问时,直接写在:http://10.10.10.4/index.html

实际操作:

[root@wlm ~]# vim /etc/httpd/conf/httpd.conf
    DocumentRoot "/var/www/html" # 默认为/var/www/html目录
    # 改为/web/目录下,首先得创建web目录,然后书写一个index.html文件
    DocumentRoot "/web"
    ...
    #
    # Note that from this point forward you must specifically allow
    # particular features to be enabled - so if something's not working as
    # you might expect, make sure that you have specifically enabled it
    # below.
    #
    
    #
    # This should be changed to whatever you set DocumentRoot to.
    #
        # 这里一并改掉
# 保存退出
# 重新加载httpd服务器
[root@wlm ~]# httpd -t 
httpd: apr_sockaddr_info_get() failed for wlm
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
Syntax OK
[root@wlm ~]# /etc/init.d/httpd reload
Reloading httpd:

# 测试(确保selinux和iptables是关闭的,且/web目录下有index.html文件)

linux上的apache/httpd2.2安装配置详解_第2张图片


6)站点访问控制常见机制

中“基于源地址”实现访问控制:
(1) Options
     后跟1个或多个以空白字符分隔的“选项”列表;
     Indexes:指明的URL路径下不存在与定义的主页面资源相符的资源文件时,返回索引列表给用户;
       Options Indexes FollowSymLinks
       Options  FollowSymLinks
     FollowSymLinks:允许跟踪符号链接文件所指向的源文件;
     None:
     All:
     Options #不要index,也不要符号链接文件
(2)  AllowOverride
     与访问控制相关的哪些指令可以放在.htaccess文件(每个目录下都可以有一个)中;
     All: 所有的都放进去
     None:都不放进去
(3) order和allow、deny:对源IP地址的访问控制
    order:定义生效次序;写在后面的表示默认法则;
     Allow from, Deny from
     来源地址:
     可以直接填写IP
     也可以填写网段NetAddr:例如:
     172.16
     172.16.0.0
     172.16.0.0/16
     172.16.0.0/255.255.0.0

使用说明:这里我们一般不做更改,使用默认设置


    
        Options Indexes FollowSymLinks
    
        AllowOverride None
    
        Order allow,deny
        Allow from all
    
    

7)定义站点主页面

DirectoryIndex  index.html  index.html.var

8)定义路径别名

格式:
Alias  /URL/  "/PATH/TO/SOMEDIR/"

使用说明:

Alias /down/ "/var/www/html/" #定义down的别名路径是/var/www/html,当在浏览器访问http://10.10.10.4/down,实则是访问/var/www/html目录下

9)设定默认字符集和ServerName

AddDefaultCharset  UTF-8
中文字符集:GBK, GB2312, GB18030
ServerName为要访问的域名,通过请求报文的头文件里包含的信息识别
ServerName www.wlm.com:80

10)日志设定

日志类型:访问日志 和 错误日志

错误日志:
ErrorLog  logs/error_log # 错误日志,默认配置,在/etc/httpd/logs
LogLevel  warn    # 默认级别
访问日志    
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog  logs/access_log  combined

LogFormat format strings:
http://httpd.apache.org/docs/2.2/mod/mod_log_config.html#formats

     %h:客户端IP地址;
     %l:Remote User, 通常为一个减号(“-”);
     %u:Remote user (from auth; may be bogus if return status (%s) is 401);非为登录访问时,其为一个减号;
     %t:服务器收到请求时的时间;
     %r:First line of request,即表示请求报文的首行;记录了此次请求的“方法”,“URL”以及协议版本;
     %>s:响应状态码;
     %b:响应报文的大小,单位是字节;不包括响应报文的http首部;
     %{Referer}i:请求报文中首部“referer”的值;即从哪个页面中的超链接跳转至当前页面的;
     %{User-Agent}i:请求报文中首部“User-Agent”的值;即发出请求的应用程序;

11)基于用户的访问控制

basic认证配置示例:
基于用户:
(1) 定义安全域
   
        Options None
        AllowOverride None
        AuthType Basic
        AuthName "String“
        AuthUserFile  "/PATH/TO/HTTPD_USER_PASSWD_FILE"
        Require  user  username1  username2 ...
   

允许账号文件中的所有用户登录访问:
   Require  valid-user
(2) 提供账号和密码存储(文本文件)
使用专用命令完成此类文件的创建及用户管理
htpasswd  [options]   /PATH/TO/HTTPD_PASSWD_FILE  username
    -c:自动创建此处指定的文件,因此,仅应该在此文件不存在时使用;
    -m:md5格式加密
    -s: sha格式加密
    -D:删除指定用户
基于组(非用户主,自定义组和组用户)账号进行认证;
(1)定义安全域
   
        Options None
        AllowOverride None
        AuthType Basic
        AuthName "String“
        AuthUserFile  "/PATH/TO/HTTPD_USER_PASSWD_FILE"
        AuthGroupFile "/PATH/TO/HTTPD_GROUP_FILE"
        Require  group  grpname1  grpname2 ...
   

(2)创建用户账号和组账号文件;
组文件:每一行定义一个组
GRP_NAME: username1  username2  ...

12)虚拟主机

有三种实现方案:
基于ip:
为每个虚拟主机准备至少一个ip地址;
基于port:
为每个虚拟主机使用至少一个独立的port;
基于FQDN(域名):通过请求报文中首部含有域名信息来识别请求
为每个虚拟主机使用至少一个FQDN(域名);

注意:一般虚拟机不要与中心主机混用;因此,要使用虚拟主机,得先禁用'main'主机;
禁用方法:注释中心主机的DocumentRoot指令即可;

虚拟主机的配置方法:
    
         ServerName FQDN
         DocumentRoot  ""
    
其它可用指令:
     ServerAlias:虚拟主机的别名;可多次使用;
     ErrorLog:
     CustomLog:
    
          ...
    
     Alias
     ...

配置演示:

基于IP的虚拟主机示例:

(1)添加多个IP

[root@wlm web]# ifconfig eth0:0 10.10.10.101 up
[root@wlm web]# ifconfig eth0:1 10.10.10.102 up    # 在一块网卡上再添加两个IP

(2)要使用虚拟主机,得先禁用'main'主机;
禁用方法:注释中心主机的DocumentRoot指令即可;

#DocumentRoot "/web"    # 加#禁用

(3)配置


        ServerName www.a.com
        DocumentRoot "/web/a.com"


        ServerName www.b.net
        DocumentRoot "/web/b.net"


        ServerName www.c.org
        DocumentRoot "/web/c.org"

(4)创建/www/下的文件

[root@wlm web]# mkdir /web/
[root@wlm web]# echo "www.a.com" > /web/www.a.com/index.html
[root@wlm web]# echo "www.b.net" > /web/
[root@wlm web]# echo "www.c.org" > /web/www.c.org/index.html

(5)语法检测,重新转载

[root@wlm web]# httpd -t
Syntax OK
[root@wlm web]# /etc/init.d/httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:

(6)测试

通过不通地址从浏览器访问

linux上的apache/httpd2.2安装配置详解_第3张图片


基于端口的虚拟主机:

(1)修改配置如下

Listen 80    # 监听多个端口
Listen 808
Listen 8080
# 不通的端口对应不通的主页

        ServerName www.a.com
        DocumentRoot "/web/www.a.com"


        ServerName www.b.net
        DocumentRoot "/web/www.b.net"


        ServerName www.c.org
        DocumentRoot "/web/www.c.org"

(2)语法检测,重新装载

[root@wlm web]# httpd -t
Syntax OK
[root@wlm web]# /etc/init.d/httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:

(3)测试


基于FQDN(域名)的虚拟主机:

(1)配置一个DNS服务器正在向区域文件里添加3个域名解析到该web主机(关于DNS配置见我另一篇文档http://afterdawn.blog.51cto.com/7503144/1420116)或是在hosts文件里面直接添加域名和映射的IP

如果没有现成的DNS服务器,这里建议直接写hosts文件

# DNS服务器里在向区域文件里的配置
$TTL 3600
$ORIGIN wlm.com.
@       IN      SOA     ns1.wlm.com.   dnsadmin.wlm.com. (
        2014100101
        1H
        10M
        3D
        1D )
        IN      NS      ns1
        IN      NS      ns2
        IN      MX   10 mx1
        IN      MX   20 mx2
ns2     IN      A       10.10.10.10
ns1     IN      A       10.10.10.3
a       IN      A       10.10.10.4
b       IN      A       10.10.10.4
c       IN      A       10.10.10.4


# 如果是hosts文件
直接写域名和对应的IP即可

(2)配置

NameVirtualHost 10.10.10.4:80    #声明10.10.10.4:80为该虚拟主机的IP端口

        ServerName a.wlm.com
        DocumentRoot "/web/www.a.com"


        ServerName b.wlm.com
        DocumentRoot "/web/www.b.net"


        ServerName c.wlm.com
        DocumentRoot "/web/www.c.org"

(3)语法检测,重载

[root@wlm web]# httpd -t
Syntax OK
[root@wlm web]# /etc/init.d/httpd reload
Reloading httpd:

(4)测试,用不通域名访问

linux上的apache/httpd2.2安装配置详解_第4张图片

13)使用mod_deflate模块压缩页面优化传输速度

适用场景:
(1) 节约带宽,额外消耗CPU;同时,可能有些较老浏览器不支持;
(2) 压缩适于压缩的资源,例如文件文件;

实际配置

打开配置文件,添加以下内容:

[root@wlm ~]# vim /etc/httpd/conf/httpd.conf
SetOutputFilter DEFLATE

# mod_deflate configuration

# Restrict compression to these MIME types
AddOutputFilterByType DEFLATE text/plain 
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css
 
# Level of compression (Highest 9 - Lowest 1)
DeflateCompressionLevel 9
 
# Netscape 4.x has some problems.
BrowserMatch ^Mozilla/4  gzip-only-text/html
 
# Netscape 4.06-4.08 have some more problems
BrowserMatch  ^Mozilla/4\.0[678]  no-gzip
 
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSI[E]  !no-gzip !gzip-only-text/html

[root@wlm ~]# /etc/init.d/httpd restart    # 从新加载服务


关于https的访问方式见:http://afterdawn.blog.51cto.com/7503144/1875173



好了,整个基于http协议访问的httpd程序站点就部署完了,下面再说说http访问的过程:

一次完整的http请求处理过程:

    (1) 建立或处理连接:接收请求或拒绝请求;

     (2) 接收请求:接收来自于网络上的主机请求报文中对某特定资源的一次请求的过程;

     (3) 处理请求:对请求报文进行解析,获取客户端请求的资源及请求方法等相关信息;

     (4) 访问资源:获取请求报文中请求的资源;

     (5) 构建响应报文:

     (6) 发送响应报文:

     (7) 记录日志: