Last Updated: 2023-09-03 00:27:49 Sunday
-- TOC --
一直使用Apache的Httpd作为很多项目的Web Server,踩了很多坑,是时候总结一下了!
Httpd官方文档:http://httpd.apache.org/docs/2.4/,本文内容基于最新的2.4版本。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格式的内容,就是成功了!
$ 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
配置项。
$ 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
所谓优雅,就是不粗暴不强制,而是让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!
$ 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模块。
Apache服务器支持的.htaccess文件,使用起来是很方便的。优点是:修改Apache服务器的配置,不用重启httpd进程。不过,.htaccess文件的使用,还是存在一些问题:
1, 会导致服务器性能下降
只要Apache服务器启用了.htaccess文件,Apache就会在每个目录下查找.htaccess。不管是查找URL请求所在目录,还要查找请求所有的上级目录下的.htaccess文件。这些查询是针对每个请求的,会让服务器性能有所下降。(应该有缓存吧?)
2, 安全问题
.htaccess文件中的配置,会修改或覆盖服务器conf中的指令,使用不慎,可能会导致安全问题。
主配置文件的位置:bin/conf/httpd.conf
;辅助配置文件都在 bin/conf/extra
目录中。
这是Httpd的文档结构安装位置,编译安装完成后自动生成,一般不要去修改,它默认与编译安装时的 --prefix 路径一致。
Httpd的监听端口。
默认的http协议监听端口是80,可以根据自己的需求任意修改。如果开启了SSL,在extra/httpd-ssl.conf配置文件中,还有一个Listen 443。
httpd.conf文件中有一大堆这样的语句,有些注释掉了(#),有些没有。其实就是说明调用哪些模块,不调用哪些。不同的模块提供不同的功能,以及不同的配置指令。
<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模块默认是打开的。
配置一个Email地址,在Httpd服务器异常的时候,可能会出现在页面上,使得看到异常页面的人可以通过Email来联系。基本没用!
#
# 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应该是首先要查看的地方!
这条指令用来设置网站的根路径!注意:此处路径的最后不应该有 /
。除非匹配了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路径的访问权限和方式。
所谓的override,是指用路径下的.htaccess文件来覆盖httpd.conf中的配置。
比如有的用户没有权限登录服务器修改配置,但是又确实需要把一些路径的配置权限开放出来给他使用,这时就可以用AllowOverride指令,用户通过ftp上传.htaccess文件的方式,实现路径的配置。
AllowOverride none # not allowed
AllowOverride all # allowed
以上是常用的两条AllowOverride指令,一般都是选着其一,在 <Directory>...</Directory>
里面配置。
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是2.4版本开始出现的新的访问控制指令,它可以从多个维度设置访问控制。
简单来说,下面两条指令选择其一,配置在<Directory>...</Directory>
里面,这也是前面几处出现此指令的使用方式。
Require all granted # 无条件允许所有访问
Require all denied # 无条件拒绝所有访问
通过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>
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配置
请参考:Httpd如何配置gzip压缩
当有问题或错误出现时,Httpd可被配置做出以下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配置
请参考: MPM配置
请参考: KeepAlive配置
本文链接:https://cs.pynote.net/net/httpd/202109245/
-- EOF --
-- MORE --