loading...
Featured image of post Apache入门

Apache入门

还是nginx好用

时隔一个月,又来学服务器了

其实是因为美亚杯做到了apache相关内容啦

猜你喜欢:Nginx入门

何为Apache

Apache HTTP Server(简称Apache,或httpd,使用时为Apache2)是Apache软件基金会的一个开源网页服务器项目

自1995年发布以来,它凭借其稳定性、强大的功能、丰富的模块和跨平台特性,一度成为全球使用最广泛的Web服务器

它的核心优势在于其高度模块化的设计,几乎所有功能,从SSL加密(mod_ssl)、URL重写(mod_rewrite)到与各种后端语言(如PHP的mod_php)的集成,都是通过模块实现的,这使得Apache具有极高的灵活性和可扩展性

Nginx vs Apache

在之前,我们介绍了如何使用nginx:Nginx入门

那么它和apache之间究竟有什么区别?

核心架构

这是两者最根本的区别

Apache

采用基于进程或线程的模型,它有多种工作模式(MPM),如prefork(每个请求一个进程)和worker/event(每个请求一个线程)

这种模型对于每个连接都会消耗一定的系统资源,在高并发下内存占用较高

Nginx

采用事件驱动的异步非阻塞架构

它用极少数的工作进程就能处理成千上万的并发连接,资源消耗极低,特别擅长应对高并发和处理静态资源

功能与生态

Apache

历史悠久,功能模块极其丰富,生态系统成熟

对于动态内容(如PHP),其mod_php模块直接在Apache进程内执行,处理流程简单直接

它的.htaccess文件提供了强大的目录级配置能力,让开发者无需修改主配置就能调整行为

Nginx

核心功能是高性能的HTTP服务和反向代理

它的模块化设计虽然也很强大,但通常更侧重于性能和网络层面

它不支持.htaccess,所有配置集中管理,性能更高,也更符合现代运维理念


总的来说:

Apache稳定、功能全面,对动态内容支持极佳

Nginx轻量、高效,在高并发、静态资源和反向代理场景下更好用

在现代架构中两者常常协同工作,用Nginx处理静态资源和代理,后端再由Apache处理复杂的动态业务逻辑


Apache的主要用法

Web服务器

直接向客户端提供静态(HTML, CSS, 图片)和动态(PHP, Perl, Python)内容的服务

Apache对动态内容的原生支持非常出色,是许多传统Web应用(如WordPress, Joomla)的首选平台

反向代理服务器

通过mod_proxy模块,Apache可以作为客户端和后端应用服务器之间的中间人,实现请求转发、负载均衡,并隐藏后端服务细节

负载均衡器

配合mod_proxy_balancer模块,Apache可以将接收到的请求分发到后端的多台服务器上,从而提高网站的可用性和处理能力

访问控制与URL重写

强大的.htaccessmod_rewrite功能,使其在URL美化(伪静态)、访问权限控制等方面表现非常灵活

目录结构

和nginx一样,不同发行版和安装方式的apache的目录结构有差异,只不过apache的差异更为显著

与nginx不同,apache官方一般只提供二进制编译安装的文件,.deb文件更多是交给第三方打包

源码编译安装

名称为apache2

自定义程度最高,所有文件通常都集中在指定的前缀下(默认为/usr/local/apache2

/                                                  # 根目录
└── usr/
    └── local/
        └── apache2/
            ├── bin/                         # 可执行文件 (httpd, apachectl, ab等)
            ├── build/                      # 编译时使用的脚本和工具
            ├── cgi-bin/                   # CGI脚本示例目录
            ├── conf/                       # 配置文件目录
            │   ├── httpd.conf         # 主配置文件
            │   ├── extra/                 # 额外的配置文件 (vhosts.conf, ssl.conf等)
            │   └── mime.types
            ├── htdocs/                    # 默认 Web 根目录
            │   └── index.html
            ├── icons/                       # Apache默认图标目录
            ├── include/                    # C/C++头文件,用于开发模块
            ├── logs/                         # 日志文件目录 (access_log, error_log)
            └── modules/                  # 动态加载的模块 (.so 文件)

Debian/Ubuntu官方仓库 (通过apt安装)

名称为apache2

目录结构遵循Debian的策略,将配置文件、模块和站点配置分拆到不同目录,便于管理

/                                                       # 根目录
├── etc/
│   └── apache2/
│       ├── apache2.conf                  # 主配置文件,主要包含全局设置
│       ├── conf-available/                # 可用的配置片段目录
│       ├── conf-enabled/                 # 已启用的配置片段 (符号链接)
│       ├── mods-available/              # 可用的模块配置文件 (.load, .conf)
│       ├── mods-enabled/               # 已启用的模块 (符号链接)
│       ├── sites-available/                # 可用的虚拟主机配置文件
│       │   └── 000-default.conf
│       └── sites-enabled/                 # 已启用的虚拟主机配置 (符号链接)
│           └── 000-default.conf -> ../sites-available/000-default.conf
├── usr/
│   ├── sbin/
│   │   └── apache2ctl                     # Apache 控制脚本
│   └── lib/
│       └── apache2/
│           └── modules/                    # 模块二进制文件 (.so)
├── var/
│   ├── www/
│   │   └── html/                             # 默认 Web 根目录
│   │       └── index.html
│   └── log/
│       └── apache2/                         # 日志文件目录
│           ├── access.log
│           └── error.log
└── lib/
    └── systemd/
        └── system/
            └── apache2.service # Systemd 服务单元

CentOS/RHEL官方仓库 (通过yum/dnf安装)

名称为httpd

目录结构与Debian系有所不同,但同样遵循系统规范

关于systemd位置的问题,可以查看nginx入门 — systemd

/                                                                     # 根目录
├── etc/
│   └── httpd/
│       ├── conf/
│       │   └── httpd.conf                              # 主配置文件
│       ├── conf.d/                                         # 子配置目录,所有 .conf 文件会被自动加载
│       │   └── welcome.conf
│       └── conf.modules.d/                           # 模块加载配置目录
├── usr/
│   ├── sbin/
│   │   └── httpd                                           # 主程序二进制文件
│   └── lib64/
│       └── httpd/
│           └── modules/                                  # 模块二进制文件 (.so)
├── var/
│   ├── www/
│   │   ├── html/                                            # 默认 Web 根目录
│   │   └── cgi-bin/
│   └── log/
│       └── httpd/                                            # 日志文件目录
│           ├── access_log
│           └── error_log
└── usr/
    └── lib/
        └── systemd/
            └── system/
                └── httpd.service                            # Systemd 服务单元

Docker镜像(官方 httpd)

docker镜像目录结构取决于镜像的制作者,没有自己的专属结构

以官方的httpd镜像为例,它是基于Debian或Alpine Linux构建的,其内部结构通常类似于源码编译安装

/                                           # 根目录
└── usr/
    └── local/
        └── apache2/
            ├── bin/
            ├── cgi-bin/
            ├── conf/                # 配置文件目录 (可挂载)
            ├── htdocs/            # 默认 Web 根目录 (可挂载)
            ├── icons/
            ├── include/
            ├── logs/                 # 日志文件目录 (符号链接)
            └── modules/

唯一要注意的是日志文件:

Docker容器的httpd的日志输出到标准输出(stdout)和标准错误(stderr),而不是写入文件

执行如下命令:

grep -E "ErrorLog|CustomLog" /usr/local/apache2/conf/httpd.conf

输出中会有这样两行:

ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 common

也就是说,访问日志和错误日志不会被写入文件,而是重定向到标准输入和标准错误

我们可以通过docker的命令来查看它们:

docker logs <容器ID>

宝塔面板

宝塔面板中Apache名称仍为apachehttpd(取决于系统)

为了方便管理,宝塔有下面的这些特点:

  1. 每个站点有独立的根目录
  2. 每个站点日志独立
  3. 主程序和配置统一管理在 /www/server/httpd/
/                                                               # 根目录
├── www/
│   ├── wwwroot/                                   # 网站根目录,每个站点一个文件夹
│   │   ├── example1.com/
│   │   │   ├── index.html
│   │   │   └── ...其他文件
│   │   └── example2.com/
│   │       ├── index.html
│   │       └── ...
│   ├── wwwlogs/                                   # 站点日志目录
│   │   ├── example1.com.log
│   │   └── example1.com.error.log
│   │   ├── example2.com.log
│   │   └── example2.com.error.log
│   │   ├── ...
│   └── server/
│       └── httpd/
│           ├── conf/                                  # 主配置文件
│           │   └── httpd.conf
│           ├── conf/vhost/                        # 虚拟主机配置,每个站点一个.conf
│           │   ├── example.com.conf
│           │   └── test.com.conf
│           ├── logs/                                   # Apache全局日志
│           │   ├── access.log
│           │   └── error.log
│           ├── modules/                            # Apache模块 (.so)
│           └── sbin/                                   # 可执行文件 httpd, apachectl 等
└── etc/
    └── init.d/
        └── bt                                             # 宝塔面板统一管理脚本(启动/停止Apache)

有以下几个需要注意的:

  • /www/server/httpd/sbin/httpd为主程序,宝塔一般会在/usr/bin/httpd做软连接,方便命令行直接运行

  • /etc/init.d/bt面板也可以控制Apache启动、停止、重载

  • /www/wwwlogs/<domain>.log为每个站点单独日志 ,/www/server/httpd/logs/为Apache全局日志,记录全局错误(和nginx不同,不强制记录站点严重错误)及未单独指定站点的请求

常用命令

使用systemctl管理Apache

适用于通过系统包管理器安装的Apache服务,比如apache2httpd

下文以apache2为例

启动

systemctl start apache2

停止

systemctl stop apache2

重启

systemctl restart apache2

重新加载配置

不会中断现有连接

systemctl reload apache2

查看状态

systemctl status apache2  # 或 httpd

使用apachectl(或 apache2ctl)

这是Apache自带的控制工具,适合调试、配置检查

它其实就是对httpd可执行程序的一个封装,方便管理Apache

启动

apachectl start

停止

apachectl start

重新加载配置

不会中断现有连接

apachectl graceful

查看版本

apachectl -v

检查配置文件语法

apachectl -t

Debian/Ubuntu专属工具:a2en* / a2dis*

这些工具主要管理站点配置和模块,对/etc/apache2/下的文件进行操作

  • 启用:在*-available*-enabled创建符号链接
  • 禁用:删除对应链接

操作之后要记得重启(reload / graceful

管理站点(虚拟主机) —— site

/etc/apache2/sites-enabled/site.conf -> /etc/apache2/sites-available/site.conf

启用站点

a2ensite site.conf 

site.conf是要启用的虚拟主机配置文件,它定义了一个网站在Apache上的访问方式,包括域名、网站目录、日志路径等

禁用站点

a2dissite site.conf

管理模块 —— mod

/etc/apache2/mods-enabled/module_name.load -> /etc/apache2/mods-available/module_name.load

/etc/apache2/mods-enabled/module_name.os -> /etc/apache2/mods-available/module_name.os

部分模块会有配置文件:

/etc/apache2/mods-enabled/module_name.conf -> /etc/apache2/mods-available/module_name.conf

启用模块

a2enmod module_name

module_name是要启动的模块名称,不用带后缀名

禁用模块

a2dismod module_name

管理配置文件 —— conf

/etc/apache2/conf-enabled/config_name.conf -> /etc/apache2/conf-available/config_name.conf

启用配置

a2enconf config_name

config_name是要加载的配置文件名称,不用带后缀名

禁用配置

a2disconf file.conf

使用bt管理Apache

在宝塔面板中,/etc/init.d/bt并不是单独只管理Apache的启动脚本,而是宝塔统一的管理脚本

它的作用类似于传统Linux的服务脚本,但通过一个入口统一管理多个服务

使用的方式类似systemctl,下文以apache2为例

启动

/etc/init.d/bt start apache2

停止

/etc/init.d/bt stop apache2

重启

/etc/init.d/bt restart apache2

重新加载配置

不会中断现有连接

/etc/init.d/bt reload apache2

查看状态

/etc/init.d/bt status apache2  # 或 httpd

主配置文件 (httpd.conf)

主配置文件在各个不同系统的路径不同:

  • 在RHEL/CentOS上通常是/etc/httpd/conf/httpd.conf

  • 在Debian/Ubuntu上是/etc/apache2/apache2.conf

它定义了服务器的全局行为、加载的模块、默认设置以及如何包含其他配置文件

不同系统配置文件使用的语法也差不多,以下是一个典型的httpd.conf(RHEL/CentOS风格)文件的结构:

# -------------------- 全局配置 --------------------
ServerRoot "/etc/httpd"
Listen 80
User apache
Group apache
PidFile run/httpd.pid
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# -------------------- 模块加载与条件判断 --------------------
# 直接加载关键模块
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authz_core_module modules/mod_authz_core.so
# 包含其他模块配置文件
Include conf.modules.d/*.conf

# -------------------- 主服务器配置 --------------------
ServerAdmin root@localhost
# ServerName www.example.com:80

# 使用<IfModule>确保模块存在时才应用指令
<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

DocumentRoot "/var/www/html"

# -------------------- 目录与文件访问控制 --------------------
# 限URL需要认证
<Location /admin>
    AuthType Basic
    AuthName "Admin Area"
    AuthUserFile /etc/httpd/.htpasswd
    Require valid-user
</Location>

# 默认禁止访问所有文件系统
<Directory />
    AllowOverride none
    Require all denied
</Directory>

# 开放 Web 根目录的访问权限
<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

# 使用<Files>块保护敏感文件
<Files ".ht*">
    Require all denied
</Files>

# -------------------- 日志配置 --------------------
ErrorLog "logs/error_log"
LogLevel warn

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog "logs/access_log" combined

# -------------------- 包含其他配置文件 --------------------
IncludeOptional conf.d/*.conf

全局配置

这部分指令定义了Apache服务器的底层运行参数,影响服务器的整体性能和安全

ServerRoot "/etc/httpd"
Listen 80
User apache
Group apache
PidFile run/httpd.pid
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
  • ServerRoot:指定Apache的安装根目录

    配置文件中的所有相对路径(如PidFile, ErrorLog)都将基于此目录进行解析

  • Listen:指定服务器监听的网络地址和端口

    若不指定IP地址,则监听所有网络接口

    可以配置多个Listen指令来监听不同的端口或地址,例如Listen 80Listen 127.0.0.1:8080

  • User & Group:设置运行Apache工作进程的系统用户和用户组

    主进程(master process)以root身份启动以绑定低位端口(<1024),但子进程会切换到此处的低权限用户,这是关键的安全措施

  • PidFile:指定于存放Apache主进程的进程ID(PID)的文件

    这个文件被apachectl等控制脚本用来向主进程发送信号(如stop, restart, reload)

    路径通常是相对于ServerRoot的,如果没写,Apache 会用编译时的默认路径:

    • Debian/Ubuntu/var/run/apache2/apache2.pid
    • RHEL/CentOS/var/run/httpd/httpd.pid
    • 源码安装logs/httpd.pid
  • Timeout:服务器在各种网络操作中等待的秒数,包括等待接收GET请求、在TCP包发送之间等待ACK等

    如果超过此时长,连接将被视为超时并关闭

  • KeepAlive:启用HTTP持久连接

    开启后,客户端可以在同一个TCP连接上发送多个请求,极大减少了TCP握手和慢启动的开销,显著提升网站加载速度,特别是对于包含大量小资源的页面

  • MaxKeepAliveRequests:在KeepAlive开启时,限制单个持久连接上允许处理的最大请求数

    达到此数目后,连接会自动关闭,有助于防止某个客户端长时间占用连接,并能周期性地回收资源

  • KeepAliveTimeout:在KeepAlive开启时,设置服务器完成请求后等待下次请求的最长时间(秒)

    如果超时仍未收到新请求,连接将关闭

    合理的设置(通常是2-5秒)可以在性能和服务器资源消耗之间取得平衡

模块加载与条件判断

Apache的功能是高度模块化的,使用任何高级功能(如SSL、重写、代理)前,必须先加载对应的模块

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authz_core_module modules/mod_authz_core.so
Include conf.modules.d/*.conf

<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>
  • LoadModule:在服务器启动时动态加载指定的模块,使其提供的功能和指令在配置中可用

    语法为:

    LoadModule <模块名> <模块文件路径>
    

    模块名是模块内部定义的标识符,路径通常是相对于ServerRoot

  • Include:把其它配置文件包含进来

    Apache(httpd)的模块配置通常被拆分放在conf.modules.d/目录下,每个模块一个配置文件:

    /etc/httpd/conf.modules.d/00-base.conf
    /etc/httpd/conf.modules.d/00-mpm.conf
    /etc/httpd/conf.modules.d/01-cgi.conf
    

    这些.conf文件里一般只有一两行LoadModule 指令:

    LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
    LoadModule rewrite_module modules/mod_rewrite.so
    LoadModule ssl_module modules/mod_ssl.so
    

    那么主配置文件(httpd.conf)里只要写下面的include命令:

    Include conf.modules.d/*.conf
    

    这样就能把这些模块加载指令全部引入,模块配置更加独立,更好管理

  • <IfModule>块:条件容器块,其内部的指令仅在指定的模块被加载时才会被处理

    这使得配置文件具有更好的可移植性,如果将配置文件部署到一个没有加载特定模块的服务器上,Apache不会因为无法识别模块内的指令而启动失败,而是会忽略整个<IfModule>

    <IfModule dir_module>
        DirectoryIndex index.html index.php
    </IfModule>
    

    在上面的例子,DirectoryIndex指令只有mod_dir模块(在配置文件里显示为dir_module)存在时才生效

主服务器配置

这部分指令定义了“默认服务器”的行为

当一个请求的Host头没有匹配到任何<VirtualHost>块时,Apache会使用这里的配置来处理该请求

ServerAdmin root@localhost
ServerName www.example.com:80
DocumentRoot "/var/www/html"
<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>
  • ServerAdmin:设置了服务器管理员的电子邮件地址

    这个地址会显示在Apache生成的错误页面中,方便用户报告问题

  • ServerName:为服务器设置一个规范的域名

    如果未设置,Apache会尝试通过反向DNS查找来确定,这可能导致启动缓慢或结果不准确

    在全局配置中,它主要用于服务器自我识别和生成重定向URL

  • DocumentRoot:该指令指定了存放网页文件的根目录

    当收到一个请求时,Apache会在此目录下查找对应的文件

  • DirectoryIndex:当客户端请求一个目录(URL以/结尾)时,Apache会在此目录中查找的文件列表

    这是Apache模块dir_module里的命令

    它会按照指令中列出的顺序查找,并返回第一个找到的文件作为响应

    DirectoryIndex index.html index.php
    

    比如上面的命令,如果用户访问http://www.example.com/docs/(这是个目录),Apache会依次查找:

    1. /var/www/example/docs/index.html
    2. /var/www/example/docs/index.php

    然后将找到的第一个存在的文件返回

    如果都没有,可能报403Forbidden,或者交给mod_autoindex显示目录列表

目录与文件访问控制

这是Apache安全配置的核心,它允许对文件系统中的路径和特定文件名进行精细的访问控制

<Location /admin>
    AuthType Basic
    AuthName "Admin Area"
    AuthUserFile /etc/httpd/.htpasswd
    Require valid-user
</Location>

<Directory />
    AllowOverride none
    Require all denied
</Directory>

<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<Files ".ht*">
    Require all denied
</Files>

Apache通过<Directory><Files><Location>这三种核心容器块,提供了对服务器资源精细化的访问控制

他们的语法格式十分相似,大部分内部指令也通用,只有小部分不同

<Directory> / <DirectoryMatch>块 —— 物理路径匹配

将其中的指令应用于服务器文件系统上的物理目录以及这些目录下的所有文件和子目录

格式:

<Directory "物理路径">
...
</Directory>

精确路径:

<Directory "/var/www/html">
...
</Directory>

通配符路径:

<Directory "/var/www/users/*/public_html">
...
</Directory>

正则有两种写法,效果相同:

正则表达式路径(使用<Directory>,以 ~ 开头):

<Directory ~ "^/var/www/project-(a|b)/src">
...
</Directory>

正则表达式路径(使用<DirectoryMatch>):

<DirectoryMatch "^/var/www/project-(a|b)/src">
...
</DirectoryMatch>

<Files> / <FilesMatch> 块 —— 文件名匹配

将其中的指令应用于特定文件名的文件,而不考虑这些文件位于哪个目录下

<Files>格式:

<Files "文件名">
...
</Files>

具体格式参考<Directory>块

<Location> / <LocationMatch>块 —— URL路径匹配

将其中的指令应用于客户端请求的URL路径

它不关心这个URL最终对应到哪个文件,甚至这个URL可能根本不对应任何文件(例如由模块动态生成的内容或代理的请求)

<Location>格式:

<Files "文件名">
...
</Files>

具体格式参考<Location>块

常用指令

以下是在上述容器块中常用的指令,我们会详细说明每个指令的格式、参数和用法

Require:访问授权

用于定义谁可以访问资源

格式

Require [not] <授权类型> [参数]

not是一个可选的修饰符,用来取反

授权类型:

授权类型 参数 说明
all granted / denied 无条件允许或拒绝所有请求
ip IP地址, 子网掩码, 网段 匹配客户端的IP地址
例如192.168.1.110.0.0.0/8
host 主机名, 域名 匹配客户端的主机名
例如example.org
注意:这需要进行DNS查询,可能影响性能
valid-user (无) 要求用户必须通过身份认证
user 用户名列表 要求用户必须是已认证的指定用户之一
例如Require user admin john
group 用户组列表 要求用户必须属于已认证的指定用户组之一
例如Require group administrators

使用Require后,在外层还可以嵌套逻辑容器:

逻辑容器 逻辑关系 说明
<RequireAny> OR 只要有一条Require满足就允许访问
<RequireAll> AND 必须所有Require条件都满足才允许访问
<RequireNone> NOT 如果里面任意一条Require满足,就拒绝访问(取反)

示例:

<Directory "/var/www/private">
    <RequireAny>
        <RequireAll>
            Require ip 192.168.0.0/16
            Require group admins
        </RequireAll>
        Require user superadmin
    </RequireAny>
</Directory>

意思是IP在192.168网段且用户属于admins组,或者用户名是superadmin的,允许访问/var/www/private

Options:特性控制

控制目录中可用的服务器功能和服务,只用于<Directory>

格式:

Options [+-]关键字1 [+-]关键字2 ...

可以列出多个关键字,使用+-前缀可以在现有选项基础上添加或移除单个选项

参数字段:

关键字 说明
Indexes 如果目录中缺少索引文件(如 index.html),则允许服务器生成并显示该目录的文件列表
FollowSymLinks 允许服务器跟随符号链接访问其指向的文件或目录
SymLinksIfOwnerMatch 一个更安全的FollowSymLinks版本,仅当符号链接和目标文件的所有者相同时才跟随
ExecCGI 允许在该目录中执行CGI脚本
MultiViews 启用内容协商功能,当用户请求的URL没有扩展名时,服务器可以根据客户端偏好(如语言)自动选择最合适的文件
All 启用除MultiViews之外的所有选项
None 禁用所有选项

示例:

Apache的Options指令有两种使用方式:

  1. 覆盖式(没有+/-

    Options Indexes FollowSymLinks
    

    这一行会清空继承的配置,然后只启用IndexesFollowSymLinks

  2. 增量式(有+/-

    Options -Indexes -ExecCGI +FollowSymLinks
    

    这一行会在继承父级Options的基础上修改:去掉Indexes,去掉ExecCGI,加上FollowSymLinks

AllowOverride:覆盖控制

决定目录中的.htaccess文件是否可以覆盖主配置文件中的设置,仅能在<Directory>块中使用

下文会详细说明.htaccess文件:.htaccess文件

格式:

AllowOverride 关键字1 关键字2 ...

参数字段:

关键字 说明
None 完全忽略.htaccess文件
All 允许.htaccess中的所有指令生效
AuthConfig 允许使用认证相关的指令
FileInfo 允许使用MIME类型、重写、头信息相关的指令
Indexes 允许使用索引相关的指令
Limit 允许使用访问控制指令
Options 允许在.htaccess中使用Options 指令

示例:

<Directory "/var/www/wordpress">
    AllowOverride FileInfo AuthConfig Limit
</Directory>

Auth*:身份认证系列

这一系列指令共同工作,为资源设置基于用户名和密码的保护

指令 作用 格式 说明
AuthType 设置认证类型 `AuthType Basic Digest`
AuthName 设置认证区域名称 AuthName "提示信息" 浏览器密码输入框会显示该提示信息
AuthUserFile 指定用户及密码文件 AuthUserFile "/path/to/.htpasswd" 文件由 htpasswd 工具创建,存储用户名和加密密码
AuthGroupFile 指定用户组文件 AuthGroupFile "/path/to/.htgroups" 文件定义用户组及其成员,配合 Require group 使用

示例:

<Location "/admin">
    AuthType        Basic
    AuthName        "Admin Area"
    AuthUserFile    "/etc/httpd/.htpasswd"
    Require         valid-user
</Location>

用户访问 http://example.com/admin后:

  1. 要求客户端进行Basic认证
  2. 浏览器弹出登录框,显示Admin Area
  3. 用户输入用户名/密码,Apache 从/etc/httpd/.htpasswd 验证
  4. 验证成功 → 允许访问/admin 验证失败 → 返回401 Unauthorized

SetHandler:处理器指定

指定服务器遇到某个资源时,交给哪种处理器来处理请求

格式:

SetHandler <处理器名称>

参数字段

处理器 说明
server-status mod_status模块处理,生成服务器状态报告
server-info mod_info模块处理,生成服务器详细配置信息
application/x-httpd-php 强制由PHP处理器执行(使用mod_php时)
cgi-script mod_cgimod_cgid处理,执行CGI脚本
cgi mod_cgi处理,通常和cgi-script等价
perl-script mod_perl处理,执行Perl脚本
proxy-server mod_proxy处理,将请求代理到后端服务器
dav mod_dav处理,实现WebDAV功能
imap-file mod_imap处理,用于访问邮件文件

示例:

<Location "/server-status">
    SetHandler server-status
    Require ip 127.0.0.1
</Location>

这段配置开启了Apache的服务器状态监控页面/server-status,但只允许本机访问,常用于管理员调试和性能监控

Header:HTTP头控制

来自mod_headers模块,用于添加、修改或删除HTTP响应头

格式:

Header [condition] action 头部名称 "值"

条件参数:

条件 (condition) 说明
early 在响应生成的早期阶段设置头部(比默认阶段更早)
expr="表达式" 只有当表达式为真时才执行该Header动作
always 无论响应状态码或其他限制,强制应用该Header

动作参数:

动作 (action) 说明
set 设置HTTP响应头,如果同名头已存在,则覆盖它
add 添加HTTP响应头,即使同名头已存在,也会再添加一个
append 将值附加到已存在的同名头值的末尾
unset 从响应中移除指定的HTTP头
echo 仅用于调试,输出指定头的值(很少用)
edit 修改已存在头的值,基于正则替换
merge 合并多个值为同一个头

示例:

<FilesMatch "\.(css|js)$">
    Header set X-Content-Type-Options "nosniff"
	Header set X-Frame-Options "DENY"
	Header append X-Powered-By "Apache"
	Header set Cache-Control "max-age=3600" "expr=%{REQUEST_STATUS} == 200"
	Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</FilesMatch>

.css.js文件设置响应头,防止MIME嗅探和被嵌入iframe,添加服务器标识,同时控制缓存和强制HTTPS

日志配置

ErrorLog "logs/error_log"
LogLevel warn

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog "logs/access_log" combined
  • ErrorLog:错误日志文件的路径

    服务器启动、运行中的错误、模块的诊断信息都会记录在其中

  • LogLevel:记录在错误日志中的信息的详细程度

    每条错误日志条目都会带有一个严重性等级,这些等级是代码里写死的,作为用户无法改变某个错误属于什么等级

    Apache支持的日志级别(从高到低)如下:

    级别 描述
    debug 记录所有信息,主要用于开发或调试,信息量极大,通常需编译时启用
    info 普通信息,如配置加载成功、进程启动、连接创建等
    notice 正常但重要的事件,如配置文件重载、进程关闭等
    warn 警告信息,非致命错误,比如配置中存在问题但可以忽略或继续运行
    error 运行过程中出现的错误,如连接失败、服务不可达等
    crit 严重错误,Nginx可能无法继续运行
    alert 必须立刻处理的严重问题
    emerg 紧急状态,比如系统崩溃,Nginx无法启动

    是否写入日志文件取决于LogLevel设置的阈值,只会写入大于等于当前设置等级的错误事件

    生产环境通常设置为warn以捕捉重要问题,同时避免日志泛滥

  • LogFormat:指定访问日志的格式和名称

    LogFormat "..." combined表示把这个格式命名为combined

    格式字符串由固定的文本和%开头的变量组成,例如 %h (客户端IP), %>s (HTTP状态码), %D (处理请求的时间,单位微秒),后面日志分析部分会详细说明

  • CustomLog:设置日志文件位置,并指定使用的格式

    CustomLog "logs/access_log" combined表示使用名为combined的格式(也就是上一行定义的格式)记录访问信息到logs/access_log文件中

虚拟主机配置文件

虚拟主机是一种技术,它允许一台物理服务器托管多个独立的网站

与Nginx的一个server块就是一台虚拟主机不同,Apache一般将虚拟主机配置文件单独存放

通常,我们会为每个网站创建一个独立的配置文件,在RHEL/CentOS中通常存放在conf.d/conf/vhosts.d/ 目录下,而在Debian/Ubuntu中则存放在 sites-available/ 目录中

<VirtualHost>块

<VirtualHost>块是定义一个虚拟主机所有配置的容器,它通过监听的IP地址和端口号来区分不同的虚拟主机

<VirtualHost [ip-address]:[port]>
...
</VirtualHost>
  • [ip-address]: 虚拟主机将响应的IP地址。*代表所有IP地址
  • [port]: 虚拟主机将监听的端口号。通常是80(HTTP)或443(HTTPS)

在一个虚拟主机配置文件中,我们可以配置与主配置文件中类似的指令,但范围仅限于这个特定的虚拟主机

以下是一个完整的的虚拟主机配置文件示例,它处理了HTTPS服务的配置:

# HTTPS 虚拟主机配置
<VirtualHost *:443>
    # 定义该虚拟主机响应的域名
    ServerName www.example.com
    ServerAlias example.com

    # 为该虚拟主机指定独立的Web根目录
    DocumentRoot "/var/www/example.com"

    # 配置独立的日志文件,便于分析
    ErrorLog "/var/log/httpd/example.com-error.log"
    CustomLog "/var/log/httpd/example.com-access.log" combined

    # 开启HTTPS并指定证书文件
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/example.com.crt
    SSLCertificateKeyFile /etc/pki/tls/private/example.com.key
    SSLCertificateChainFile /etc/pki/tls/certs/chain.crt

    # 为该站点的目录设置权限
    <Directory "/var/www/example.com">
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
  • ServerName

    为该虚拟主机指定一个唯一的域名,当客户端的请求头中的Host字段与此处的ServerNameServerAlias匹配时,该请求就会由这个虚拟主机处理

  • ServerAlias

    为虚拟主机设置一个或多个别名,例如example.com可以作为www.example.com的别名

  • HTTPS 相关的指令:

    • SSLEngine on: 开启SSL/TLS加密引擎
    • SSLCertificateFile: 指定SSL证书文件的路径(公钥,通常是.crt.pem
    • SSLCertificateKeyFile: 指定与证书匹配的私钥文件路径(.key
    • SSLCertificateChainFile: 如果证书需要中间证书链才能被浏览器信任,则需要指定此文件

HTTP到HTTPS跳转

下面是一个经典的例子,它唯一的目的就是利用mod_rewrite模块将所有HTTP请求重定向到对应的HTTPS URL,以确保用户无论如何访问,都会被安全地引导至加密连接

# 将所有 HTTP 请求永久重定向到 HTTPS
<VirtualHost *:80>
    # 定义该虚拟主机响应的域名
    ServerName www.example.com
    ServerAlias example.com

    # 启用URL重写引擎
    RewriteEngine On
    # 定义重定向规则
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
  • <VirtualHost *:80>

    *表示该虚拟主机将响应服务器上任何IP地址的请求,80指定了它只监听来自标准HTTP端口80的请求

  • ServerNameServerAlias

    当一个请求的Host头(域名)与www.example.comexample.com匹配时,就由该虚拟主机来处理

    这确保了即使服务器上托管了多个网站,这条重定向规则也只会应用于example.com这个域名的HTTP请求,而不会影响到其他网站

  • RewriteEngine On

    这是启用Apache mod_rewrite模块重写的开关,必须先开启,其下的RewriteRule指令才能生效

  • RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

    这是整个重定向逻辑的核心,它定义了一条具体的重写规则

    • ^(.\*)$

      它捕获了请求路径的全部内容,例如 /about//images/logo.png?id=123

    • https://%{HTTP_HOST}%{REQUEST_URI}

      这是重定向的目标URL

      **https://:**将协议从HTTP改为HTTPS

      **%{HTTP_HOST}:**这是一个Apache服务器变量,它会动态地获取客户端请求头中的Host字段值

      **%{REQUEST_URI}:**另一个服务器变量,它会动态地获取请求的完整URI路径,包括查询字符串

  • [R=301,L]

    这些是控制重写行为的标志

    • R=301R代表redirect(重定向),301指定了HTTP状态码为301 Moved Permanently,这个状态码告诉浏览器和搜索引擎这个跳转是永久性的,确保SEO权重不丢失

    • Llast,指示Apache一旦这条规则被匹配并执行,就停止处理任何后续的重写规则

当一个用户访问http://www.example.com/login时,整个流程如下:

  1. 客户端向服务器的80端口发送一个HTTP请求
  2. Apache接收到请求,根据Host头匹配到这个<VirtualHost *:80>
  3. RewriteEngine On生效,Apache开始检查RewriteRule
  4. RewriteRule匹配到请求路径/login
  5. Apache根据规则,动态构建出目标URL:https://www.example.com/login
  6. R=301,L标志告诉Apache向客户端发送一个301重定向响应
  7. 客户端浏览器接收到301响应后,会自动向https://www.example.com/login发起一个新的请求,这个请求将由服务器上监听443端口的虚拟主机(即HTTPS配置)来处理

.htaccess文件

.htaccess文件(分布式配置文件)是一个目录级配置片段,只应用于<Directory>块

它允许开发者或非root用户在不修改主配置文件的情况下,对特定目录及其子目录进行配置

工作原理

Apach 在读取配置时并不会一次性加载.htaccess,而是每次处理请求时才去磁盘查找并应用它

比如,当Apache收到一个对/var/www/site/dir/file.html的请求时,它会依次查找以下文件:

  1. /var/www/site/dir/.htaccess
  2. /var/www/site/.htaccess
  3. /var/www/.htaccess

每找到一个.htaccess,就解析并应用里面的配置写在对应<Directory>块中

这种递归查找机制对性能有显著影响,因为它增加了文件系统的I/O开销

因此,除非必要,通常不建议广泛使用.htaccess

.htaccess文件中的指令是否生效,完全取决于前文提到过主文件配置的AllowOverride指令:

AllowOverride:覆盖控制

典型用例与指令

下面是一个典型的.htaccess文件内容:

# 启用重写引擎
RewriteEngine On

# 将所有以.html结尾的请求重定向到不带.html的URL
# 例如:/about.html -> /about
RewriteRule ^(.*)\.html$ /$1 [R=301,L]

# 为目录设置访问密码保护
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /var/www/site/dir/.htpasswd
Require valid-user

# 强制将目录索引文件设置为index.php
DirectoryIndex index.php

# 在响应头中添加自定义信息
<IfModule mod_headers.c>
    Header set X-Custom-Header "My Website"
</IfModule>

在上面的例子中,我们使用了以下指令:

  • RewriteEngineRewriteRule

    URL重写,这在构建“伪静态”URL或实现SEO友好的链接时非常有用

  • Auth*系列指令

    用于对整个目录进行密码保护。这在/admin/private等需要认证的目录中非常常见

  • DirectoryIndex

    用于覆盖主配置文件中定义的索引文件顺序

  • Header

    添加或修改HTTP响应头

这些指令与主配置文件中的用法相同,但其作用范围仅限于.htaccess文件所在的目录

事实上,<Directory>块能够使用的指令,在.htaccess文件大多都能使用,只是范围受制于AllowOverride

这使得它非常灵活,尤其是在共享主机环境中

常用模块

Apache的核心优势在于其高度模块化的设计,几乎所有高级功能都由特定的模块提供。这些模块必须在主配置文件(通常是httpd.confapache2.conf)中通过LoadModule指令加载后才能使用。

本章节将详细介绍几个Apache最常用且功能强大的模块,并讲解它们的配置方法。

mod_rewrite:URL重写

mod_rewrite允许服务器根据正则表达式和规则集来重写请求的URL

这通常用于实现伪静态、URL美化、HTTP重定向等

使用之前,我们要确保在主配置文件中启用了mod_rewrite

  • 在Debian/Ubuntu中:

    a2enmod rewrite
    
  • 在RHEL/CentOS中:

    LoadModule rewrite_module modules/mod_rewrite.so
    

核心指令

RewriteEngine

该指令用于在特定配置上下文中开启或关闭重写引擎

开启:

RewriteEngine On

关闭:

RewriteEngine Off

RewriteRule

这是定义重写规则的指令,其格式为:

RewriteRule 模式 替代 [标志]
参数 含义
模式 用于匹配请求的URI路径(不包含域名和协议)的正则表达式
替代 匹配成功后,用于构建新URL的字符串或路径
标志 可选,用于控制重写规则的行为(如外部重定向、停止处理等)

常用标志:

标志 缩写 含义
L last 停止处理当前规则集中的其他规则
R redirect 执行外部重定向(发送302状态码给浏览器)可指定状态码,如R=301
NC nocase 使模式匹配不区分大小写
P proxy 将请求代理到指定的替代URL,需要mod_proxy模块
QSA qsappend 将原始请求的查询字符串(URL中?之后的部分)附加到替代URL后
NE noescape 禁止对重写后的URL进行特殊字符转义
CO cookie 设置一个Cookie
E env 设置环境变量
G gone 返回410 Gone状态码
F forbidden 返回403 Forbidden状态码
NC nocase 匹配不区分大小写
L last 停止后续规则处理

多个标志可以使用逗号,隔开,比如[R=301,L]

RewriteCond

用于设置条件,当条件满足时才执行紧随其后的RewriteRule

RewriteCond 字段 模式 [标志]
参数 含义
字段 待测试的字符串,比如主机名%{HTTP_HOST}
模式 条件模式,支持正则表达式匹配
标志 可选标志,如 NCOR

常用标志:

标志 含义
NC No Case,匹配时忽略大小写
OR Logical OR,与下一条 RewriteCond 条件做“或”逻辑(默认是“与” AND)
AND Logical AND,与下一条条件做“与”逻辑(默认可省略)
GT Greater Than,仅对数值比较有效
LT Less Than,仅对数值比较有效
EQ Equal,数值比较等于
NE Not Equal,数值比较不等于

示例

示例1:实现伪静态URL

https://example.com/article.php?id=123重写为https://example.com/article/123

# 启用重写引擎
RewriteEngine On
# 编写规则
RewriteRule ^article/([0-9]+)$ /article.php?id=$1 [NC,L]

示例2:强制所有请求到www子域名

example.com重定向到www.example.com,这有助于避免重复内容问题

# 使用RewriteCond指令添加条件
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

mod_proxy:代理模块

mod_proxy允许服务器将客户端的请求转发到其他后端服务器

它使得Apache能够作为前端网关,对后端服务进行路由、负载均衡和安全保护

要使用反向代理功能,必须加载mod_proxy及其子模块

最常用的子模块是mod_proxy_http,用于代理HTTP协议的流量

在Debian/Ubuntu上:

a2enmod proxy proxy_http

在RHEL/CentOS上:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

反向代理

ProxyPass

用于将匹配路径的请求代理到指定的后端 URL

ProxyPass [路径] [URL] [可选参数]
参数 含义
路径 代理匹配的本地 URI 前缀,例如 /app
URL 目标服务器地址,例如 http://127.0.0.1:8080/
可选参数 retry=, timeout=, keepalive=on/off 等,用于控制代理行为

常用参数:

参数 含义
retry=N 后端服务器失败时重试次数(默认 0,表示不重试)
timeout=N 代理请求超时时间(秒),控制连接或响应等待时间
acquire=N 获取连接的超时时间(秒)
keepalive=on/off 是否启用与后端的持久连接(HTTP Keep-Alive)
disablereuse=on/off 禁止复用已建立的后端连接
max=number 最大并发连接数(可与 mod_proxy_balancer 配合)
ttl=N 连接在连接池中存活的时间(秒)
timeout=N 请求超时,连接超时
flushpackets=on/off 每次写数据包时立即刷新到客户端
lbmethod=byrequests/bytraffic/... 仅在负载均衡时使用,选择负载均衡策略
keepalive=on/off 控制是否启用HTTP持久连接

ProxyPassReverse

用于修改后端服务器响应头中的重定向地址,使客户端看到的URL正确

ProxyPassReverse [路径] [URL]
参数 含义
路径 客户端访问的本地URI前缀
URL 后端服务器的URL,对响应头进行重写

基本上写法和ProxyPass保持一致,也就是把url改回去,改成对应域名

比如我们写下配置:

ProxyPass        /app  http://127.0.0.1:8080/myapp
ProxyPassReverse /app  http://127.0.0.1:8080/myapp

客户端请求:

GET /app/ HTTP/1.1
Host: www.example.com

Apache转发给后端:

GET /myapp/ HTTP/1.1
Host: 127.0.0.1:8080

后端响应:

HTTP/1.1 302 Found
Location: http://127.0.0.1:8080/myapp/login

如果没有ProxyPassReverse,客户端会收到真实后端地址,绕过了代理

ProxyPassReverse时,Apache会把返回的Location改写成:

HTTP/1.1 302 Found
Location: http://www.example.com/app/login

客户端依然通过代理访问,保持一致性

ProxyPreserveHost

用来控制在反向代理时,是否保留客户端原始请求中的Host头信息

ProxyPreserveHost On|Off
  • On:Apache 转发请求时,保留客户端原始Host
  • Off(默认):Apache会把Host头改成后端服务器的地址

示例

假设有一个Node.js应用在http://127.0.0.1:3000上运行,我们希望通过Apache的/api/路径来访问它

<VirtualHost *:80>
    ServerName api.example.com
    # 禁用正向代理,后面会提到
    ProxyRequests Off
    # 保留客户端原始Host头
    ProxyPreserveHost On

    # 定义代理规则:将所有 /api/ 请求代理到后端服务器
    ProxyPass /api/ http://127.0.0.1:3000/
    # 重写响应头:将后端返回的 http://127.0.0.1:3000/ 地址重写为 http://api.example.com/api/
    ProxyPassReverse /api/ http://127.0.0.1:3000/
</VirtualHost>

当用户访问http://api.example.com/api/users时,Apache会接收请求,ProxyPass规则会将该请求转发到后端http://127.0.0.1:3000/users

如果后端服务器返回了一个重定向响应(例如,Location: http://127.0.0.1:3000/auth),ProxyPassReverse会修改该头信息,将其替换为http://api.example.com/api/auth,确保用户的浏览器能够正确地跳转

<Proxy>块

<Proxy>

<Proxy>块是一个容器指令,用于对特定的代理URL或一组代理URL应用细粒度的配置

它的使用类似于<Directory><Location>,但针对的是代理目标而不是本地文件系统

虽然ProxyPass指令支持在行内附加参数,但使用<Proxy>块配合ProxySet指令,可以使配置更加清晰

格式:

<Proxy [URL]>
    ...
</Proxy>

[URL]可以是一个完整的URL,一个协议(如http://),或使用通配符*(匹配所有代理目标)

也可以使用<ProxyMatch>进行正则表达式匹配,就像之前的访问控制块一样

ProxySet

<Proxy>容器和<Location>等容器一样,可以使用访问控制相关指令(比如 Require

但它还额外支持一些和代理相关的指令 —— ProxySet

ProxySet允许我们为特定的代理目标设置详细的控制参数

格式:

ProxySet [参数名]=[] [参数名]=[]...
参数 含义
retry=N 后端服务器失败时重试次数(默认 0,表示不重试)
timeout=N 代理请求超时时间(秒),控制连接或响应等待时间
acquire=N 获取连接的超时时间(秒)
keepalive=on/off 是否启用与后端的持久连接(HTTP Keep-Alive)
disablereuse=on/off 禁止复用已建立的后端连接
max=number 最大并发连接数(可与 mod_proxy_balancer 配合)
ttl=N 连接在连接池中存活的时间(秒)
flushpackets=on/off 每次写数据包时立即刷新到客户端

示例

假设我们要代理到两个后端服务:一个API和一个博客,并希望为它们设置不同的超时时间

<VirtualHost *:80>
    ServerName example.com
    ProxyRequests Off
    ProxyPreserveHost On

    # 代理API服务,设置15秒超时,并启用持久连接
    <Proxy "http://127.0.0.1:8080">
        ProxySet timeout=15 keepalive=on
    </Proxy>
    ProxyPass /api/ http://127.0.0.1:8080/
    ProxyPassReverse /api/ http://127.0.0.1:8080/

    # 代理博客服务,不设置特定超时,使用默认配置
    <Proxy "http://127.0.0.1:9000">
        # 可以在此处添加特定配置
    </Proxy>
    ProxyPass /blog/ http://127.0.0.1:9000/
    ProxyPassReverse /blog/ http://127.0.0.1:9000/
</VirtualHost>

此配置比在ProxyPass中添加参数更清晰,且允许对每个后端应用独特的代理行为

正向代理

在正向代理模式下,Apache扮演客户端的代理

当客户端请求外部资源时,请求会首先发送给Apache,由Apache代为访问外部网络

配置

正向代理的配置非常简单:

ProxyRequests On

这是开启正向代理功能的指令

示例

# 开启正向代理功能
ProxyRequests On
<Proxy *>
    # 允许来自特定IP的请求通过此代理
    Require ip 192.168.1.0/24
    # 禁止所有其他请求
    Require all denied
</Proxy>

这里<Proxy *>匹配所有目标地址,启用正向代理后,Apache会接受客户端发来的完整URL请求,然后去请求目标站点,再把响应转发回来,目标站点只会看到Apache的IP,不会看到客户端的真实IP

mod_ssl:SSL/TLS加密模块

mod_ssl是Apache实现HTTPS加密服务的模块,它使用OpenSSL库来处理加密和解密

其配置通常在443端口的<VirtualHost>块中完成

使用之前

大多数现代Linux发行版在安装Apache时,mod_ssl默认已经被加载,如果没有,我们需要手动启用它

在Debian/Ubuntu上:

a2enmod ssl

在RHEL/CentOS上:

LoadModule ssl_module modules/mod_ssl.so

核心指令

这些指令定义了HTTPS服务所需的证书和密钥文件

指令 格式 含义
SSLEngine SSLEngine onSSLEngine off 开启或关闭该虚拟主机上的SSL/TLS引擎
SSLCertificateFile SSLCertificateFile /path/to/fullchain.crt 指定SSL证书文件(公钥)
推荐使用包含服务器证书和所有中间证书的完整链文件
SSLCertificateKeyFile SSLCertificateKeyFile /path/to/private.key 指定与证书配对的私钥文件
此文件必须严格保密
SSLCertificateChainFile SSLCertificateChainFile /path/to/chain.crt 指定中间证书链文件
如果SSLCertificateFile已包含完整链,则此指令可选
Protocols Protocols h2 http/1.1 指定服务器支持的协议版本,可写多个
h2代表HTTP/2
SSLCipherSuite SSLCipherSuite [套件列表] 指定服务器支持的加密套件列表
增强安全性

示例

<VirtualHost *:443>
    ServerName secure.example.com
    DocumentRoot "/var/www/secure.example.com"
    ErrorLog "logs/secure.example.com-error.log"
    CustomLog "logs/secure.example.com-access.log" combined

    # 开启SSL/TLS引擎
    SSLEngine on

    # 指定证书文件和私钥文件
    SSLCertificateFile /etc/pki/tls/certs/secure.example.com.crt
    SSLCertificateKeyFile /etc/pki/tls/private/secure.example.com.key
    SSLCertificateChainFile /etc/pki/tls/certs/chain.crt

    # 推荐的安全性设置
    Protocols h2 http/1.1
    SSLHonorCipherOrder on
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM
</VirtualHost>

该配置块定义了一个监听443端口的虚拟主机

它通过SSLEngine on指令开启了HTTPS服务,并使用SSLCertificateFileSSLCertificateKeyFileSSLCertificateChainFile指令指定了相应的证书和密钥

ProtocolsSSLCipherSuite指令则用于限制协议版本和加密算法,以确保安全性和性能

日志分析

访问日志(access_log

访问日志记录了所有客户端对服务器的请求

日志格式

Apache默认使用combined格式,它是一种全面且常用的格式,记录了请求的方方面面

日志格式通过LogFormat指令定义,并由CustomLog指令引用:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog "logs/access_log" combined

格式字段

下表详细解释了combined日志格式中的每个字段

字段标识符 含义 示例
%h 远程主机
客户端的IP地址
123.123.123.123
%l 远程登录名
identd确定,通常为-
-
%u 远程用户
由HTTP认证确定的用户名
用户名 (如果进行了认证),否则为 -
%t 时间
服务器收到请求的本地时间
[10/Oct/2000:13:55:36 -0700]
\"%r\" 请求行
完整的HTTP请求行,包括方法、路径和协议
"GET /apache_pb.gif HTTP/1.0"
%>s 状态码
返回给客户端的HTTP状态码
%s:最初请求的状态码
%>s:最终响应状态码(如果有内部重定向,记录重定向后的状态码)
200404301500
%b 响应体大小
响应体的大小(字节),不包括响应头
2326
\"%{Referer}i\" 来源
请求的来源URL
"http://www.example.com/start.html"
\"%{User-Agent}i\" 用户代理
客户端浏览器或设备信息
"Mozilla/4.08 [en] (Win98; I ;Nav)"

实际示例

下面是一些常见的日志条目:

  1. 成功请求 (200 OK)

    10.0.0.5 - - [20/Aug/2025:10:30:01 +0800] "GET /index.html HTTP/1.1" 200 450 "http://example.com/home" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
    

    来自内网IP10.0.0.5的客户端,使用Chrome浏览器访问http://example.com/home成功请求了根目录下的index.html文件,服务器返回了200状态码,响应体大小为450字节

  2. 文件未找到 (404 Not Found)

    8.8.4.4 - - [20/Aug/2025:10:30:15 +0800] "GET /robots.txt HTTP/1.1" 404 213 "https://www.google.com/search?q=site:example.com" "Googlebot/2.1 (+http://www.google.com/bot.html)"
    

    Google爬虫(Googlebot)从搜索引擎结果页进入,请求了robots.txt文件,但服务器返回了 404 错误,表示该文件不存在,响应体大小为213字节,通常是Apache默认的404错误页面

  3. 永久重定向 (301 Moved Permanently)

    123.123.123.123 - - [20/Aug/2025:10:30:20 +0800] "GET /old-page HTTP/1.1" 301 245 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/106.0.5249.101 Mobile/15E148 Safari/604.1"
    

    来自IP123.123.123.123的iPhone客户端请求了/old-page,但服务器配置了301重定向,将请求永久指向了新地址,浏览器从HTTPS页面跳转到HTTP页面时,出于安全考虑,默认不会发送Referer,故而referer字段为空

  4. 服务器内部错误 (500 Internal Server Error)

    192.168.1.10 - - [20/Aug/2025:10:30:35 +0800] "GET /api/data HTTP/1.1" 500 503 "-" "curl/7.68.0"
    

    内网IP192.168.1.10请求http://example.com/dashboard页面(可能是一个脚本或API调用)返回了500内部服务器错误,这通常意味着后端脚本(如PHP或Python)执行失败,要排查具体原因,必须查看错误日志

错误日志(error_log

错误日志记录了服务器启动、运行、关闭过程中的所有诊断信息和错误

格式与字段

error.log条目的通用格式如下:

[时间戳] [模块:日志级别] [pid 进程ID:tid 线程ID] [client 客户端IP:端口] 错误描述
  • [时间戳]

    日志事件发生的时间

  • [模块:日志级别]

    指明产生日志的Apache模块(如coreproxy_http等)以及该事件的严重程度,具体看:日志配置

  • [pid 进程ID:tid 线程ID]

    指明是哪个Apache进程和线程产生了该日志,这在调试多进程或多线程问题时很有用

  • [client 客户端IP:端口]

    指明导致错误的客户端IP地址和端口

示例

下面是一些常见的错误日志条目:

  1. 文件权限问题

    [Wed Aug 20 10:30:00.123456 2025] [core:crit] [pid 12345] (13)Permission denied: AH00035: Unable to change to root directory: /var/www/site/dir
    

    这是一个严重的错误(crit),通常发生在Apache启动时,它表明Apache进程(PID为12345)没有权限访问或切换到/var/www/site/dir目录,通常是由于文件或目录权限设置不正确所致,需要检查该目录的用户和组是否与httpd.conf中定义的UserGroup匹配

  2. 配置文件语法错误

    [Wed Aug 20 10:31:00.987654 2025] [core:warn] [pid 12345] AH00547: The document root /var/www/example.com/public does not exist
    

    这是一个警告(warn),服务器尝试启动,但发现DocumentRoot指令中指定的 /var/www/example.com/public目录不存在,Apache虽然可以启动,但网站将无法正常访问

  3. 后端连接失败

    [Wed Aug 20 10:32:00.123456 2025] [proxy:error] [pid 12345:tid 67890] [client 192.168.1.50:12345] AH00959: ap_proxy_connect_backend disabling connection: (111)Connection refused
    

    这是一个错误(error),proxy模块无法连接到后端服务器,因为它返回了“连接被拒绝”(Connection refused)的错误,这通常意味着后端应用服务没有运行,或者防火墙阻止了连接

  4. mod_rewrite 调试信息

    [Wed Aug 20 10:33:00.789012 2025] [rewrite:trace1] [pid 12345] (2) init rewrite engine with requested uri /about
    [Wed Aug 20 10:33:00.789012 2025] [rewrite:trace3] [pid 12345] applying pattern '^(.*)$' to uri '/about'
    

    这些是级别为trace1trace3的调试信息,它们在 LogLevel 设置为 trace 时才会出现,这对于排查复杂的mod_rewrite规则非常有用,可以逐行跟踪规则的匹配和处理过程

Docker环境中日志的特殊格式

有时,在使用官方httpdDocker镜像时,通过docker logs命令看到的日志格式与直接查看文件日志略有不同

根据设置,Docker的日志驱动程序在将容器的stdoutstderr流捕获并输出时,可能会给每一行日志加上额外的前缀信息,这个前缀通常包含时间戳日志流的来源stdoutstderr),其标准格式为:

[时间戳] [日志流] [原始日志内容]
字段 含义 示例
时间戳 Docker记录该日志的时间,精确到纳秒 2025-08-20T02:30:00.123456789Z
日志流 指明日志来源:
标准输出:stdout,对应访问日志
标准错误:stderr`,对应错误日志
stdoutstderr

示例

一个完整的docker logs访问日志条目看起来像这样:

2025-08-20T02:30:00.123456789Z stdout 172.17.0.3 - - [20/Aug/2025:02:30:00 +0000] "GET / HTTP/1.1" 200 45 "-" "curl/7.64.1"

一个完整的错误日志条目看起来像这样:

2025-08-20T02:30:05.987654321Z stderr [Wed Aug 20 02:30:05.987654 2025] [core:error] [pid 1] AH00037: File not found: /usr/local/apache2/htdocs/non-existent-file.html

分析技巧

以下命令示例均基于access.log文件

统计访问量最多的IP地址

cut -d ' ' -f 1 access.log | sort | uniq -c | sort -rn | head -10
  • cut -d ' ' -f 1 access.log

    使用 cut 命令以空格为分隔符(-d ' '),提取每行的第一个字段(-f 1),即客户端 IP 地址

  • sort

    对提取出的所有 IP 地址进行排序,这是uniq命令去重和计数的前提

  • uniq -c

    统计每个 IP 地址出现的次数(-c 表示计数)

  • sort -rn

    对上一步的结果进行再次排序

    -r表示降序排序,-n表示按数值大小排序(而不是按字典顺序),确保最高的访问次数排在最前面

  • head -10

    输出排序后的前10行,即访问次数最多的前10个IP地址及其次数

统计特定页面或文件的访问次数

grep -c "/index.php" access.log
  • grep "/index.php" access.log

    access.log文件中搜索所有包含/index.php字符串的行

  • -c选项

    告诉grep只输出匹配的行数,而不显示匹配的行本身

统计特定IP地址的访问总次数

grep -w "192.168.200.2" access.log | wc -l
  • grep -w "192.168.200.2" access.log

    使用grep搜索 IP 地址

    -w选项确保只匹配一个完整的“单词”,即只匹配192.168.200.2这个完整的IP地址

  • |

    管道符,将grep命令的输出作为wc命令的输入

  • wc -l

    统计来自管道的行数(-l表示行)

    每行代表一次访问,因此行数即为总访问次数

统计特定时间段内的独立IP访问数

grep "03/Aug/2023:08:" access.log | awk '{print $1}' | sort | uniq | wc -l
  • grep "03/Aug/2023:08:" access.log

    根据日志中的时间戳格式,筛选出所有在 2023年8月03日8时这个小时段内的访问记录

  • awk '{print $1}'

    awk命令默认以空格分隔字段,{print $1}提取每行的第一个字段,即IP地址

  • sort

    对所有提取出的IP地址进行排序

  • uniq

    去重,只保留唯一的IP地址

  • wc -l

    统计去重后剩下的行数,即独立IP地址的数量

查找特定IP地址的详细访问记录

grep "192.168.200.2" access.log | more
  • grep "192.168.200.2" access.log

    搜索包含该IP地址的所有日志行

  • | more

    如果匹配的行数太多,more命令会进行分页显示,方便逐页查看,按空格键翻页,按q键退出


文章至此告一段落,笔者使用的也不多,之后边学边更新吧

距离小站第一行代码被置下已经过去
使用 Hugo 构建
主题 StackJimmy 设计
...当然还有kakahuote🤓👆