上次博文我们具体讨论了http协议(参见:http://sweetpotato.blog.51cto.com/533893/1656137),本次博文我们来具体配置一台Apache(httpd)服务器。
本次博文的主要内容:
httpd相关包信息
httpd的安装及主页面
httpd的配置文件
httpd的全局配置
httpd的主服务器配置
一、httpd的RPM包介绍及其相关信息:
RHEL5和RHEL6略有不同:
下图是RHEL5上httpd相关包的信息:
下图是RHEL6上httpd相关包的信息:
【httpd安装后各文件的内容及存放位置】:
服务脚本:/etc/rc.d/init.d/httpd
运行目录:/etc/httpd
配置文件:/etc/httpd/conf/
主配置文件:httpd.conf
扩展配置文件:/etc/httpd/conf.d/*.conf
socket:
http: 80/tcp,
https: 443/tcp
网页文件目录(DocumentRoot):
静态页面:/var/www/html
动态页面(CGI): /var/www/cgi-bin/
默认主页面:index.html index.php
【httpd的安装】:
注意:httpd的默认安装会试图通过反解当前主机的IP地址来为httpd服务器提供一个主机名称,如果反解失败会报错,会提示主机名称解析失败并使用127.0.0.1作为当前主机的主机名。所以没有配置DNS的情况下,建议首先配置/etc/hosts文件为其提供一个主机名。
1、编辑/etc/hosts文件,为当前主机配置相应的主机名:
2、通过yum来安装httpd,如果需要手册(httpd-manual:官方提供的httpd的配置手册),也可以一并安装;
3、安装完成后通过“chkconfig”命令来设置开机启动:
4、通过“netstat”或“ss”命令来查看80/tcp端口是否处于监听状态:
5、80/tcp端口被监听说明服务已经启动了,在客户机的浏览器中输入服务器地址验证安装:
看到上面的页面表示httpd已经能够正常工作了哈,上面的页面是一个测试页面,在我们提供默认主页面后该页面就会被替换。
6、为httpd提供默认主页(在"/var/www/html"目录下新建一个名为index.html的文件),内容如下:
7、再通过浏览器查看:
看到上面的页面说明我们提供的默认主页面工作正常了哈。
二、配置httpd的工作属性:
指令的说明:
1、指令不区分字符大小写,但约定俗成的习惯:单词的首字母大写;指令的值很有可能区分大小写;有些指令可以重复使用多次;
2、所有以“#”号开头的都为注释;
配置文件的构成:
整个配置文件由3段组成:
(1)全局配置:对主服务器或虚拟机都有效,且有些功能是服务器自身工作属性;
(2)主服务器:主站属性;
(3)虚拟主机:虚拟主机及属性定义
注:第二段和第三段(即主机和虚拟主机)不能同时使用;
配置文件语法测试:
#service httpd configtest #httpd -t
说明:大多数配置修改后,使用service httpd reload即能生效;而修改了监听的地址和端口通常需要重启服务;
第一段:全局配置:
1、配置监听的地址和端口:
Listen [IP:]PORT //Listen可重复使用多次
2、配置所选用的MPM的属性:
MPM:意为多路处理模块,也就是我们所说的apache的工作模式,共有3种工作模式:
prefork:一个主进程产生多个子进程,一个子进程响应一个请求;
worker:一个进程生成多个线程,一个线程响应一个请求;
event:基于事件驱动;
说明:
event在apache2.4版本之前是以测试状态提供,网上并没有太多的资料,在更新至2.4版本之后正式上线
先来说prefork:当httpd启动起来之后,会生成一个主进程,它负责监听用户的请求,一旦请求进来后,它不负责自己响应,而是让其生成的子进程来响应,而主进程继续监听请求。
需要考虑的是:刚启动服务的时候需要创建几个空闲进程,太多不好太少也不好。最少保证有几个空闲进程来响应请求进来,这是必须的。 最多设定多少个空闲进程,多余的空闲进程需要回收回来。
所以其有如下几个关键作用:
(1)启动服务时绑定特权端口:Linux系统中,只有管理员有权限使用小于1024的特权端口;但运行一些公共可用的服务,一定不能以管理员身份运行
(2)派发或回收子进程
(3)读取分析主配置文件
(4)监听每个用户请求并且派发子进程
补充:httpd命令的使用
httpd -l :用于查看核心模块
httpd -M:检查DSO模块加载情况(通过2种方式查询已加载的模块数量应该相等)
【配置prefork模型】:
apache服务默认就是以Prefork模式启动,无须更改启动模式,下面来演示如何更改其模型参数
编辑主配置文件:vim/etc/httpd/conf/httpd.conf找到与模块相关的参数:IfModule为指令,意为判断模块是否存在,如果存在那么参数则生效,反之如果不存在此模块,参数将不会生效
参数说明:
<IfModule prefork.c> #如果存在这个模块,那么提供以下属性 StartServers 8 #刚启动web服务时启动几个空闲子进程 MinSpareServers 5 #最少空闲进程数 MaxSpareServers 20 #最大空闲进程数 ServerLimit 256 #限定最多允许并发进来的活动用户连接个数
假如一个进程需要20M内存,那么256*20=5G内存,通常说此值是相当消耗内存,由此可以说明设置为256已经相当足够。
例:工作中,通过观察发现服务器每个请求进来并处理结束之间的过程大概需要50毫秒,在一秒钟之内一个进程可以处理20个请求,那么一共开启了256个那么即意味着256*20=每秒的并发数量,因此还需要再计算极端情况:对于一个站点来说一般都有高峰期,假如一次性进来的请求远远超于预想的阀值,该如何处理,之后会提到。
MaxClients 256 #服务器所允许同时所连接进来的链接数,一般来说与上面保持一致,或者大于上面的数。 MaxRequestsPerChild 4000 #一个服务器进程最多可以处理多少个进程,一旦超出请求后无论如何将进程结束并新启动新进程 </IfModule> #最后以IfModule结尾
如果发现服务器满负荷工作时,但服务器上仍然有空闲,可以将MaxClients、ServerLimit值调大。
【配置worker模型】
当第一个用户请求到达的时候线程发现需要复制文件,通过内核将文件复制给其进程,所以第二个用户请求同一个文件,对于第二个线程来说这个文件已存在,因为线程是共享同一个进程空间,所以速度得到提升;
缺点:共享意味着争用,共享资源被称作临界资源,线程共享进程空间就可能产生资源争用,并不是全状态并行。所以一个进程里不能启用太多线程;可启用多个进程然后由每个进程再启用多个线程,但无论如何每个线程也都是一个独立的执行实体(线程要能运行必须给其cpu资源)。
更改apache当前工作模式为worker模式:
编辑文件/etc/sysconfig/httpd,将以下参数的注释信息去掉:
HTTPD=/usr/sbin/httpd.worker
更改模式后必须重新启动服务
[root@Centos ~]# service httpd restart
启动完毕后,查看其进程状态:
[root@Centos ~]# ps -ef | grep http root 1667 1 0 23:43 ? 00:00:00 /usr/sbin/httpd.worker #以root用户身份生成的父进程(用于派发工作进程) apache 1671 1667 0 23:44 ? 00:00:00 /usr/sbin/httpd.worker #以apache用户身份运行的工作进程(该工作进程派发线程) apache 1672 1667 0 23:44 ? 00:00:00 /usr/sbin/httpd.worker apache 1673 1667 0 23:44 ? 00:00:00 /usr/sbin/httpd.worker apache 1676 1667 0 23:44 ? 00:00:00 /usr/sbin/httpd.worker
属性配置:
<IfModuleworker.c> StartServers 4 #配置启动多少个用于监听的服务,注意:这里并不是服务器进程,而是线程 MaxClients 300 #最大支持的用户连接数 MinSpareThreads 25 #最小的空闲线程数 MaxSpareThreads 75 #最大的空闲线程数 ThreadsPerChild 25 #允许每个进程最多生成多少个线程 MaxRequestsPerChild 0 #设置一个独立的子进程将能处理的请求数量 </IfModule>
3、配置服务器支持keep-alived:
KeepAlive {On|Off} :启用之后支持一次连接可以发多个请求(对于非常繁忙的服务器建议off KeepAliveTimeout 15 : 15秒之后断开长连接 MaxKeepAliveRequests 50:一次长连接之内最多允许50个请求
4、配置加载的模块:
#LoadModule指令 模块名称 模块所在的路径(相对于ServerRoot的路径) LoadModule foo_module modules/mod_foo.so
第二段:主服务器配置:
5、配置站点根目录(网页存放目录)
DocumentRoot "" #与之配对使用两个容器类指令:Directory指令限定的是文件系统上站点目录的路径(/var/www/html);Location指令限定的是URL路径 <Directory "FS_PATH"> </Directory> <Location "URL"> </Location> #两种路径定义方法 /var/www/html/images/logo.jpg => <Directory "/var/www/html" ></Directory> http://www.magedu.com/images/logo.jpg => <Location "/"></Location> #这里的“/”==/var/www/html
6、配置页面文件访问属性
<Directory "FS_PATH"> Options Indexes: 是否允许索引页面文件(不安全,建议关闭); FollowSynLinks: 是否跟随软链接文件(不安全,建议关闭); SymLinksifOwnerMatch:相对安全的跟随软链接指令(如果软链接文件的属主与网页访问用户匹配则允许) ExecCGI:是否允许执行CGI脚本; All None </Directory>
是否允许索引范例:
首先删除欢迎页面文件和默认主页面文件,或者将二者改名:
[root@Centos conf.d]# mv welcome.conf welcome.conf.bak [root@Centos conf.d]# cd /var/www/html/ [root@Centos html]# mv index.html index.html.bak [root@Centos html]# service httpd reload
关闭“index”功能后,显示没有权限访问站点根目录(如下图所示):
7、访问控制:
有两种访问控制:(1)基于客户端的访问控制;(2)基于用户的访问控制
7.1:基于客户端访问控制:
Order:定义allow和deny哪个为默认法则;写在后面的为默认法则:写在前面的指令没有显式定义的即受后面的指令控制; Order allow,deny Deny from 192.168.1.2 #拒绝所有的iP访问 allow from 192.168.1.0/24 #仅允许192.168.1.0网段的IP访问(但拒绝192.168.1.2:最小范围优先匹配原则) 说明:对于httpd 2.4及以后的版本,不再支持使用order, allow, deny这些机制,而是统一使用require指令进行访问控制(后面编译安装httpd 2.4版本时我们再说)
举例说明:
(1)修改网站根目录为"/website/htdocs":
此时ACL为如下形式:
Allow from all 表示允许所有人访问
(2)重新启动httpd服务:
(3)我用192.168.1.2的客户端能否访问index.php(由于我安装并配置好了PHP,所以我的实验虚拟机上可以访问动态站点):
可以看到能够访问哈,并且显示出了客户端的IP地址。
(4)现在我们把ACL写成如下形式并重新加载httpd配置文件:
现在表示什么意思?192.168.1.2还能访问网站吗?我们试试看哈
不能访问了哈,我们在另一台机器上访问试试看呢:
可以看到192.168.1.57能够访问网站。所以能够证明:ACL是最小范围匹配原则(先拒绝了192.168.1.2访问,然后允许了192.168.1.0网段能够访问,结果是拒绝了前者)。
7.2:基于用户的访问控制 :
在 Apache中,用户的认证可以采用数据来存储用户认证信息,不过我们这里先介绍使用文本来存储用户的信息。例如我们要使用户在访问" http://www.magedu.com/downloads/" 时需要认证才能访问,需要进行如下的配置:
(1)编辑/etc/http/conf/http.conf文件:
DocumentRoot "/var/www/html" <Directory "/PATH/TO/DocumentRoot_SUBDIR"> Options None|All|Indexes|FollowSymLinks|SymLinksIfOwnerMatch|ExecCGI AllowOverride All|None|directive-type [directive-type] ... AuthName "Realm" AuthType Basic AuthUserFile /path/to/passwords Require valid-user </Directory> 1、指令说明: DocumentRoot:是网站根目录(可以自定义); 在任何一对<Directory></Directory>标签对中定义用户访问控制,后面的路径指定所要控制的目标路径(例如对站点根目录下的downloads下载目录进行用户访问控制); Options:选项 AllowOverride:指确定允许存在于.htaccess文件中的指令类型 通常利用Apache的rewrite模块对 URL 进行重写的时候,rewrite规则会写在 .htaccess 文件里。但要使Apache 能够正常的读取.htaccess 文件的内容,就必须对.htaccess 所在目录进行配置;从安全性考虑,根目录的AllowOverride属性一般都配置成“None”不允许任何Override(优先级)。其语法格式为:AllowOverride All|None|directive-type [directive-type] ... directive-type可以是下列各组指令之一: AuthConfig:允许使用与认证授权相关的指令(AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, Require, 等)。 AuthName "Realm":认证名称是什么,描述信息,可以任意给,告诉客户端这里为什么要认证 AuthType:认证类型,一般有两种:Basic:基本认证;digest:摘要认证(不是所有浏览器都支持);通常都是基本认证; AuthUserFile:用户认证文件所存放的位置(可以是文本文件、数据库、ldap等,通过动态加载相应的模块实现,默认是保存在文本文件中) AuthGroupFile:组文件所存放的位置(基于组用户的认证与用户类似) Require:指明认证的用户是哪些,可以是多个用户,用户名之间用空格隔开;如果是所有合法用户,则为“valid-user”; 2、用户认证的密码是通过"htpasswd"命令创建的,用法如下: Usage: htpasswd [-cmdpsD] passwordfile username htpasswd -b[cmdpsD] passwordfile username password htpasswd -n[mdps] username htpasswd -nb[mdps] username password -c Create a new file. -m Force MD5 encryption of the password. On Windows, NetWare and TPF systems the '-m' flag is used by default. On all other systems, the '-p' flag will probably not work.
注意:创建第二个认证用户的时候不要加-c选项,否则会覆盖掉认证文件的内容
(2) 一个配置示例:
第一步:编辑http.conf文件,找到DocumentRoot,随便找个位置编写一个<Directory></Directory>指令,并检查语法错误,如下所示:
DocumentRoot "/website/htdocs" <Directory "/website/htdocs/downloads"> Options Indexes AllowOverride AuthConfig AuthName "Only for employees." AuthType Basic AuthUserFile /etc/httpd/conf/.htpass Require valid-user </Directory>
第二步:用htpass命令在/etc/httpd/conf/目录下创建一个隐藏文件(.htpass):
第三步:创建"/website/htdocs/downloads"目录,随便复制一些文件进去:
第四步:重新加载httpd.conf配置文件:
第五步:在客户端浏览器验证配置结果:
8、userdir:
让每个能够登录网站的用户都拥有个人站点:(可以在浏览器中输入“http://HOST/~username/”访问每个人的个人站点)
<IfModule mod_userdir.c> #UserDir disabled //注释此行 UserDir public_html //启用此行 </IfModule>
举例说明:
(1)找到<IfModule mod_userdir.c>开头的行;
(2)注释掉下面的行:
(3)启用下面的行:
上图的指令表示:每个用户可以在其家目录下建立名为“public_html”的目录以作为其个人站点目录(需要注意的是:这个目录必须让别人具有访问权限)
(4)保存并重新载入httpd的配置文件;
(5) 新建一个用户Tom,并切换到该用户身份:
(6)在Tom用户的家目录下创建“public_html”目录和相应的index.html文件:
(7)在客户端浏览器中输入http://192.168.1.59/~Tom,看是否能够访问我们刚刚创建的index.html网页:
不能访问哈,这是怎么回事呢?因为我们的网站是以apache身份访问的,而apache用户对用户的家目录有访问权限吗?
(8)修改用户家目录的权限以让apache用户有访问权限:
(9)再次访问网站:
9、定义默认主页面:
DirectoryIndex index.php index.jsp index.html #从左到右依次寻找,先找到的就作为默认主页
10、配置日志功能(Apache的日志是独立的,不记录进syslog):
对于任何一个web服务器来说,运行日志都是一个重要的环节,管理员除了使用一些状态显示模块来显示apache当前运行的状态外,只能通过日志来监控和管理Apache,Apache有十分完善的日志功能以及优先级,能够良好的记录各种服务相关的信息,这些都可以自定义的。
日志的分类:
日志分为2类,分别是访问日志和错误日志:
错误日志:由内核模块复制,专门记录apache服务运行错误信息。
访问日志:主要记录apache在运行中产生的日志,比如一个连接的详细信息,连接连接是否被拒等。
日志格式:
apache日志格式的定义在主配置文件中有体现,当然也可以手动自定义,前提是得搞懂每个参数是干啥用的:
日志参数解释(更详细的解释参考Apache官方手册,安装httpd-manual包): [root@Centos ~]# tail -1 /var/log/httpd/access_log %h #客户端主机 %l #用户登录名 %u #用户名 %t #接受到的请求到达的时间 \"%r\" #转义要使用引号本身,请求报文的起始行信息:(请求方法 请求的资源 协议版本) %>s #显示内部完成重定向的状态码 %b #响应报文的大小单位是字节,但不包含响应报文首部的大小(即响应报文主体大小) "%{Referer}i\" #从哪个网站页面跳过来的 举例说明: [root@Centos ~]# tail -1 /var/log/httpd/access_log 192.168.1.2 - - [29/May/2015:20:20:22 +0800] "GET /~Tom HTTP/1.1" 404 280 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36" #192.168.1.2客户端:在2015年5月29日的20:20:22,以GET方法访问http://ip/~Tom页面:返回状态码404:响应报文的大小为280字节(响应报文主体的大小,不包括响应头): 不是从其它页面跳转过来的:浏览器的版本和客户端操作系统信息
小结:
(1)日志分为2类,分别是访问日志和错误日志
(2)apache日志格式的定义在主配置文件中有体现,可以使用LogFormat模块来自定义日志规则
(3)一般在生产环境中要使用日志轮询的功能
11、设定默认字符集
AddDefaultCharset UTF-8
12、路径别名:
DocumentRoot "/web/htdocs" #定义网页存放的根目录在哪 范例:访问http://www.magedu.com/images/logo.gif => /web/htdocs/images/logo.gif Alias /html/ "/www/static/" #表示/www/static/是/web/htdocs/html/这个路径的别名,它们在浏览器中访问资源的情况参加下面的范例(特别注意:两个路径最后的/必须匹配,同有同无)
举例说明:
(1)没有定义路径的情况:
(2)定义路径别名并从新载入httpd.conf配置文件:
(3)创建/www/static/目录,并在其下创建一个index.html文件
(4)在浏览器中再次访问http://192.168.1.59/html/index.html:
13、脚本路径别名:
ScriptAlias /PATH/ /PATH/TO/SCRIPTS_DIR/
举例说明:
(1)编辑httpd.conf文件,找到LoadModule cgi_module,确保该模块被启用了:
(2)由于安全原因,CGI程序通常被限制在ScriptAlias指定的目录中,这样,管理员就可以严格控制谁可以使用CGI程序。
允许CGI在任意目录执行需要两个步骤:第一步,必须用AddHandler或SetHandler指令激活cgi-script处理器。第二步,必须在Options指令中启用ExecCGI选项;
因此,编辑主httpd.conf文件,找到添加AddHandler指令的地方,添加如下指令:
找到下面的指令并做相应更改:
保存用httpd -t检查语法错误并重新载入配置文件;
(3)在/website/htdocs/cgi-bin/目录下创建一个bash脚本(index.sh),内容如下:
#!/bin/bash #Description:CGI测试脚本 cat << EOF #特别注意:CGI语法规定:CGI文件第一句一定要先定义文档类型,然后跟着是一个新空行,后面才是主程序,否则会报“malformed header from script. Bad header”的错误 Content-Type: text/html #定义文档类型 <pre> #注意<pre>标签与文档类型定义之间要有个空格 The hostname is: `/bin/hostname`. The time is: `date`. </pre> EOF # end of cgi script file
(4)在浏览器中访问验证结果:
(5)通常,CGI脚本比较危险,我们不期望它们被放于网站根目录下,这就是脚本路径别名的意义,这是配置Apache以允许CGI的第二种方法。
将上例中所做的配置还原,然后找到ScriptAlias指令所在的位置,做如下更改:
(6)保存用httpd -t检查语法错误并重新载入配置文件;然后在浏览器中验证结果:
小结:
配置Apache以允许CGI的两种方法:
【ScriptAlias】
ScriptAlias指令使Apache允许执行一个特定目录中的CGI程序。当客户端请求此特定目录中的资源时,Apache假定其中所有的文件都是CGI程序并试图运行它。
ScriptAlias指令形如:
ScriptAlias /cgi-bin/ /usr/local/apache2/cgi-bin/
如果Apache被安装到默认位置,默认的配置文件httpd.conf中就会有上述配置。ScriptAlias与Alias指令非常相似,都是定义了映射到一个特定目录的URL前缀,两者一般都用于指定位于DocumentRoot以外的目录,其不同之处是ScriptAlias又多了一层含义,即URL前缀后面的任何文件都被视为CGI程序。所以,上述例子会指示Apache:任何以/cgi-bin/开头的资源都将映射到/usr/local/apache2/cgi-bin/目录中,且视之为CGI程序。
例如,如果有URL为http://www.example.com/cgi-bin/test.sh的请求,Apache会试图执行/usr/local/apache2/cgi-bin/test.sh文件并返回其输出。当然,这个文件必须存在而且可执行,并以特定的方法产生输出,否则Apache返回一个出错消息。
【ScriptAlias目录以外的CGI】
由于安全原因,CGI程序通常被限制在ScriptAlias指定的目录中,这样,管理员就可以严格控制谁可以使用CGI程序。但是,如果采取了恰当的安全措施,则没有理由不允许其他目录中的CGI程序运行。比如,你可能希望用户在UserDir指定的宿主目录中存放页面,而他们有自己的CGI程序,但无权访问cgi-bin目录,这样,就产生了运行其他目录中CGI程序的需求。
允许CGI在任意目录执行需要两个步骤:第一步,必须用AddHandler或SetHandler指令激活cgi-script处理器。第二步,必须在Options指令中启用ExecCGI选项。
(1)用Options显式地允许CGI的执行:
可以在主配置文件中,使用Options指令显式地允许特定目录中CGI的执行:
<Directory /website/htdocs/somedir>
Options +ExecCGI
</Directory>
上述指令使Apache允许CGI文件的执行。
(2)必须告诉服务器哪些文件是CGI文件。下面的AddHandler指令告诉服务器所有带有sh或py后缀的文件是CGI程序:
AddHandler cgi-script .sh .py
到此为止,一台完整的Apache服务器的基本配置就完成了,能够正常提供Web服务。下一次博文我们来看看如何编译安装httpd2.4以上版本及Apache的高级配置(包括虚拟主机、https、httpd status的配置等)。