Httpd(Apache)使用指南

Last Updated: 2023-09-03 00:27:49 Sunday

-- TOC --

一直使用Apache的Httpd作为很多项目的Web Server,踩了很多坑,是时候总结一下了!

apache_httpd

Httpd官方文档:http://httpd.apache.org/docs/2.4/,本文内容基于最新的2.4版本。Httpd的配置其实挺难的,弯弯绕有点多,我只能尽自己所理解来总结,难以做到全面准确。

编译安装Httpd

源码下载地址:

http://httpd.apache.org/download.cgi

https://apr.apache.org/download.cgi

编译安装操作顺序如下:

$ wget https://dlcdn.apache.org//httpd/httpd-2.4.49.tar.gz
$ wget https://dlcdn.apache.org//apr/apr-1.7.0.tar.gz
$ wget https://dlcdn.apache.org//apr/apr-util-1.6.1.tar.gz

$ tar zxf httpd-2.4.49.tar.gz
$ tar zxf apr-1.7.0.tar.gz
$ tar zxf apr-util-1.6.1.tar.gz
$ mv apr-1.7.0 httpd-2.4.49/srclib/apr
$ mv apr-util-1.6.1 httpd-2.4.49/srclib/apr-util

# why libpcre2-dev is not suitable?
$ sudo apt install libpcre3-dev  # mandatory
$ sudo apt install zlib1g-dev  # for --enable-deflat
$ sudo apt install libssl-dev  # for --enable-ssl

$ # ./configure --prefix=/usr/local/apache --with-pcre=/usr/local/pcre --enable-deflate --with-mpm=worker --with-included-apr
$ ./configure --prefix=/usr/local/apache-test1 --with-included-apr --enable-deflat --enable-ssl
$ make
# ...
$ sudo make install
# ...

这就装好了,测试OK:

$ sudo /usr/local/apache-test1/bin/apachectl start  # stop, restart
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
$ curl 127.0.1.1
<html><body><h1>It works!</h1></body></html>

由于此Linux环境没有图形界面,所以在命令行使用curl工具访问loopback地址,看到返回的html格式的内容,就是成功了!

查看上次make的configure配置

$ sudo cat config.nice
#! /bin/sh
#
# Created by configure

"./configure" \
"--prefix=/usr/local/apache-test1" \
"--with-included-apr" \
"--enable-deflat" \
"--enable-ssl" \
"$@"

config.nice是自动生成的。

重新安装

如果想要修改配置后重新安装,在重新make之前,先要运行 make clean,删除上一次make产生的目标文件,否则会报错。

除了重新configure,还可以直接使用上文提到的config.nice文件来重新配置安装:

$ ./config.nice --enable-allowmethods

这条命令表示,在config.nice的基础上,增加 --enable-allowmethods 配置项。

通过dnf安装并使用httpd

$ sudo dnf install httpd mod_ssl

然后就可以在/etc/httpd/conf下进行配置。

这个安装方案很OK,这样安装后,systemd相关命令也可以使用。但是我个人在配置的时候,通过systemd始终不能成功启动httpd(卡在ssl相关配置那部分),反而直接在命令行可以正常启动。命令行:

$ /usr/sbin/httpd -f <config>   # start
$ /usr/sbin/httpd -f <config> -k graceful  # graceful restart

[优雅地]启停Httpd

所谓优雅,就是不粗暴不强制,而是让Htppd及其创建的进程和线程先干完自己手上的活儿,再关闭或者重启。采用优雅地重启Httpd,父进程会重新读入配置文件,每当一个子进程干完活死掉,父进程立刻用新的配置文件产生一个新的子进程,并立刻开始等待新的请求。感觉挺优雅!

$ sudo apache/bin/apachectl -k graceful  # 优雅重启
$ sudo apache/bin/apachectl -k graceful-stop  # 优雅停止

bin/apachectl是个控制脚本,真正运行的是httpd程序。

非优雅的启停Httpd进程的方式:

$ sudo apache/bin/apachectl start  # 启动
$ sudo apache/bin/apachectl restart  # 重启
$ sudo apache/bin/apachectl stop  # 停止

检查配置文件语法

$ sudo apache/bin/httpd -t
Syntax OK

Syntax OK并不表示你的配置没有问题,仅仅只是语法上的OK!

查看Httpd版本和静态链接的模块

$ sudo /usr/local/apache-test1/bin/httpd -v
Server version: Apache/2.4.49 (Unix)
Server built:   Sep 24 2021 14:28:24
$ sudo /usr/local/apache-test1/bin/httpd -V
Server version: Apache/2.4.49 (Unix)
Server built:   Sep 24 2021 14:28:24
Server's Module Magic Number: 20120211:116
Server loaded:  APR 1.7.0, APR-UTIL 1.6.1
Compiled using: APR 1.7.0, APR-UTIL 1.6.1
Architecture:   32-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_PROC_PTHREAD_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/usr/local/apache-test1"
 -D SUEXEC_BIN="/usr/local/apache-test1/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"
$ sudo /usr/local/apache-test1/bin/httpd -l
Compiled in modules:
  core.c
  mod_so.c
  http_core.c
  event.c

可以查到此Httpd的版本号,编译时间等信息,注意默认安装的event模块。

.htaccess的优缺点

Apache服务器支持的.htaccess文件,使用起来是很方便的。优点是:修改Apache服务器的配置,不用重启httpd进程。不过,.htaccess文件的使用,还是存在一些问题:

1, 会导致服务器性能下降

只要Apache服务器启用了.htaccess文件,Apache就会在每个目录下查找.htaccess。不管是查找URL请求所在目录,还要查找请求所有的上级目录下的.htaccess文件。这些查询是针对每个请求的,会让服务器性能有所下降。(应该有缓存吧?)

2, 安全问题

.htaccess文件中的配置,会修改或覆盖服务器conf中的指令,使用不慎,可能会导致安全问题。

配置Httpd

主配置文件的位置:bin/conf/httpd.conf;辅助配置文件都在 bin/conf/extra目录中。

ServerRoot

这是Httpd的文档结构安装位置,编译安装完成后自动生成,一般不要去修改,它默认与编译安装时的 --prefix 路径一致。

Listen

Httpd的监听端口。

默认的http协议监听端口是80,可以根据自己的需求任意修改。如果开启了SSL,在extra/httpd-ssl.conf配置文件中,还有一个Listen 443。

LoadModule

httpd.conf文件中有一大堆这样的语句,有些注释掉了(#),有些没有。其实就是说明调用哪些模块,不调用哪些。不同的模块提供不同的功能,以及不同的配置指令。

User & Group

<IfModule unixd_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User daemon
Group daemon
</IfModule>

指定Httpd程序运行的用户和用户组。注意文件访问权限方面的问题,以及不同的用户其$PATH值可能不一样带来的差异。

这两条配置包含在 unixd_module 里面,用 <IfModule>...</IfModule> 括起来,表示如果加载了XX模块,就是用YY配置。unixd_module模块默认是打开的。

ServerAdmin

配置一个Email地址,在Httpd服务器异常的时候,可能会出现在页面上,使得看到异常页面的人可以通过Email来联系。基本没用!

ErrorLog & LogLevel

#
# 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"

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

ErrorLog可以配置全局的,也可以按VirtualHost配置,后者优先级更高。VirtualHost就是虚拟主机,用一台物理服务器承载多个网站的运行。LogLevel也可以按VirtualHost配置。

有问题查原因,error log应该是首先要查看的地方!

DocumentRoot

这条指令用来设置网站的根路径!注意:此处路径的最后不应该有 /。除非匹配了Alias指令,Httpd服务器会将客户端请求的URL与此root拼接起来使用。

比如,当配置如下是:

DocumentRoot "/home/xinlin/web"

此时有一个请求是 http://cs.pynote.net/abc.jpg,Httpd服务器就会去访问 home/xinlin/web/abc.jpg 文件,将其返回给客户端。

DocumentRoot可以是一个全局配置,也可以配置在VirtualHost里面!

目录访问权限

#
# Deny access to the entirety of your server's filesystem. You must
# explicitly permit access to web content directories in other
# <Directory> blocks below.
#
<Directory />
    AllowOverride none
    Require all denied
</Directory>

这一段配置的含义是:对于系统的根目录 /,不允许用.htaccess文件覆盖配置(AllOverride none),也不允许任何人访问(Require all denied)。

这里的不允许访问,是指通过URL访问。比如静态资源的URL,它一定对应了服务器文件系统的某个文件,这个文件一定存在一个从根/起始的路径,<Directory>...</Directory> 范围内的指令,就是用来规定这些路径的访问权限。如果不允许访问,Httpd会向客户端返回一个AH01630错误,即Forbidden,此错误在error log中会显示:client denied by server configuration...

针对DocumentRoot,默认的访问权限配置如下:

<Directory "/usr/local/apache2.4.46/htdocs">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   AllowOverride FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # Controls who can get stuff from this server.
    #
    Require all granted
</Directory>

虚拟主机定义DocumentRoot路径后,都需要在对应的 <Directory>...</Directory> 中定义此root路径的访问权限和方式。

AllowOverride

所谓的override,是指用路径下的.htaccess文件来覆盖httpd.conf中的配置。

比如有的用户没有权限登录服务器修改配置,但是又确实需要把一些路径的配置权限开放出来给他使用,这时就可以用AllowOverride指令,用户通过ftp上传.htaccess文件的方式,实现路径的配置。

AllowOverride none  # not allowed
AllowOverride all   # allowed

以上是常用的两条AllowOverride指令,一般都是选着其一,在 <Directory>...</Directory> 里面配置。

Options

Options指令用在 <Directory> 里面,给这个路径的访问特性,提供一些选项,如上面的配置:

    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

如果有Indexes这个option,Httpd服务器在没有可显示页面的情况下,会将这个路径下所有文件显示出来。一般要去掉Indexes选项,因为可能泄露路径文件内容。

有些企业内部使用的Httpd服务器,确正好是需要Indexes选项,当做下载服务器,但是默认情况下,中文会显示乱码。解决Indexes中文乱码的问题,增加一行配置:

IndexOptions Charset=UTF-8

Httpd服务器默认使用ISO-8859-1,切换到UTF-8,就能够正常显示中文了。

顾名思义,就是允许follow符号链接。

文件访问权限

#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<Files ".ht*">
    Require all denied
</Files>

使用 <Files>...</Files> 指令控制具体某些文件的访问权限,以上配置静止了对.ht开头的文件的访问。再比如对于WordPress用户(曾经的我)来说,xmlrpc.php这个文件恐怕是要禁止访问的:

# protect xmlrpc.php
<Files "xmlrpc.php">
    Require all denied
</Files>

Require

Require是2.4版本开始出现的新的访问控制指令,它可以从多个维度设置访问控制。

简单来说,下面两条指令选择其一,配置在<Directory>...</Directory> 里面,这也是前面几处出现此指令的使用方式。

Require all granted  # 无条件允许所有访问
Require all denied   # 无条件拒绝所有访问

Alias

通过Alias指令,可以将一个不在DocumentRoot所覆盖范围内的路径,加入进来。如果不使用Alias,通过URL能够访问的都在DocumentRoot覆盖范围之内,使用Alias,就是将其他目录也加入URL可以访问的范围。但要注意,Alias指令指向的路径,要通过在<Directory>...</Directory> 里面,用Require指令配置访问权限。

    #
    # Alias: Maps web paths into filesystem paths and is used to
    # access content that does not live under the DocumentRoot.
    # Example:
    # Alias /webpath /full/filesystem/path
    #
    # If you include a trailing / on /webpath then the server will
    # require it to be present in the URL.  You will also likely
    # need to provide a <Directory> section to allow access to
    # the filesystem path.

以上至httpd.conf中关于Alias部分默认的注释说明。

如下是我个人服务器的Alias配置:

Alias "/.well-known/acme-challenge" "/home/xinlin/acme-challenge"
# for acme challenge
<Directory "/home/xinlin/acme-challenge">
    Require all granted
</Directory>

ServerAlias

Apache的ServerAlias指令,顾名思义,就是ServerName的别名。我没想清楚它的具体含义,于是做了个简单的测试。

我已经有一个test.maixj.net网站,什么内容都没有,不过已经可以正常访问。我先在DNS设置的地方,增加tt.maixj.net的DNS解析;然后在服务器的Apache配置里面,在test.maixj.net的VirualHost配置里面,增加:

ServerName  test.maixj.net
ServerAlias tt.maixj.net

然后重启Apache。

这时,访问tt.maixj.net,打开的就是test.maixj.net的页面,浏览器地址栏还是tt.maixj.net这个地址,表示并没有发生跳转。

这就是ServerAlias所起的作用,通过别名访问ServerName对应的网站,但是没有跳转。通过HTTP状态工具检查tt.maixj.net,看到的是200返回码。

HTTP请求中有Host字段!

CGI配置

请参考:详解CGI配置

gzip配置

请参考:Httpd如何配置gzip压缩

ErrorDocument

当有问题或错误出现时,Httpd可被配置做出以下4件事件之一:

  1. 输出hardcoded error message(default)
  2. 输出自定义的message
  3. 内部重定向到另一个地址
  4. 重定向到外部
ErrorDocument 500 http://example.com/cgi-bin/server-error.cgi
ErrorDocument 404 /errors/bad_urls.php
ErrorDocument 401 /subscription_info.html
ErrorDocument 403 "Sorry, can't allow you access today"
ErrorDocument 403 Forbidden!
ErrorDocument 403 /errors/forbidden.py?referrer=%{escape:%{HTTP_REFERER}}

/ 接在 DocumentRoot 指向的地址后面。

Httpd默认没有ErrorDocument的配置,其实什么都可以不做。但如果你想自定义404页面(这可能是需求最大的),就可以通过ErrorDocument指令来实现。

ErrorDocument 404 /404.html

可能一般静态网站会这样配置,动态网站有自己处理404 的方式,比如WordPress,就有一个404.php文件,用来动态生成404页面,而且也没有用到Httpd的ErrorDocument指令。

缓存配置

请参考: Httpd缓存配置

防盗链配置

请参考: 防盗链配置

HTTPS配置

请参考:网站HTTPS配置

MPM模块配置

请参考: MPM配置

KeepAlive配置

请参考: KeepAlive配置

本文链接:https://cs.pynote.net/net/httpd/202109245/

-- EOF --

-- MORE --