跳转至内容

Apache HTTP Server

来自 ArchWiki

Apache HTTP Server(简称 Apache)是一个非常流行的网络服务器,由 Apache 软件基金会开发。

本文介绍了如何设置 Apache 以及如何将其与 PHP 集成。

安装

安装 apache 软件包。

配置

Apache 配置文件位于 /etc/httpd/conf。主配置文件是 /etc/httpd/conf/httpd.conf,其中包含了其他各类配置文件。默认配置适用于简单设置。默认情况下,它会向访问网站的任何人提供 /srv/http 目录的内容。

要运行 Apache,请启动 httpd.service。如果一切运行正常,访问 https:/// 应该会显示一个简单的索引页。

有关进一步的配置,请参阅以下章节。

高级选项

请参阅 Apache 配置指令完整列表指令快速参考

/etc/httpd/conf/httpd.conf 中的以下选项可能对您有用

User http
出于安全考虑,一旦 Apache 由 root 用户启动(直接启动或通过启动脚本),它就会切换到此 UID。默认用户是 http,它在安装过程中自动创建。
Listen 80
这是 Apache 将监听的端口。如果通过路由器进行互联网访问,您必须转发该端口。
如果您想设置 Apache 用于本地开发,可能希望它仅能从本机访问。那么请将此行更改为 Listen 127.0.0.1:80
ServerAdmin you@example.com
这是管理员的电子邮件地址,会显示在错误页面等处。
DocumentRoot "/srv/http"
这是您应该放置网页的目录。
您可以根据需要更改它,但请记得同时更改 <Directory "/srv/http">,否则在访问新的文档根目录时,您很可能会收到 403 错误(权限不足)。不要忘记将 Require all denied 行更改为 Require all granted,否则也会收到 403 错误。请记住,DocumentRoot 目录及其父文件夹必须允许其他用户拥有执行权限(可以使用 chmod o+x /path/to/DocumentRoot 设置),否则会收到 403 错误
AllowOverride None
<Directory> 部分中的此指令会导致 Apache 完全忽略 .htaccess 文件。请注意,这是 Apache 2.4 的默认设置,因此如果您计划使用 .htaccess 文件,则需要显式允许覆盖。如果您打算在 .htaccess 文件中使用 mod_rewrite 或其他设置,则可以允许在该文件中声明哪些指令可以覆盖服务器配置。有关更多信息,请参阅 Apache 文档
提示 如果您的配置有问题,可以使用以下命令让 Apache 检查配置:apachectl configtest

更多设置可以在 /etc/httpd/conf/extra/httpd-default.conf 中找到

关闭服务器签名

ServerSignature Off

隐藏 Apache 和 PHP 版本等服务器信息

ServerTokens Prod

用户目录

默认情况下,用户目录可以通过 https:///~yourusername/ 访问,并显示 ~/public_html 的内容(可以在 /etc/httpd/conf/extra/httpd-userdir.conf 中更改)。

如果您不希望在 Web 上提供用户目录,请注释掉 /etc/httpd/conf/httpd.conf 中的以下行

Include conf/extra/httpd-userdir.conf

确保 Apache Web 服务器具有遍历用户主目录并访问 ~/public_html 内文件的足够权限。目录遍历需要在路径中的每个父目录上拥有执行 (+x) 权限,这独立于目标文件上的读取 (r) 权限。

推荐的方法是使用 访问控制列表 (ACL) 仅授予 http 用户访问权限

$ setfacl -m u:http:x ~
$ setfacl -R -m u:http:rx ~/public_html

避免使用全局可执行权限(例如 chmod o+x),因为这会削弱您主目录的安全性。

您还需要在嵌入式文件 /etc/systemd/system/httpd.service.d/hardening.conf 中编辑 systemd 服务的配置

[Service]
ProtectHome=no

执行 daemon-reload重启 httpd.service 以应用更改。另请参阅 Umask#设置掩码值

TLS

警告 如果您部署 TLS,请务必遵循 weakdh.org 的指南 以防止漏洞。有关更多信息,请参阅 服务器端 TLS

首先获取证书。如果您拥有公共域名,则可以使用 传输层安全性 (TLS)#ACME 客户端

/etc/httpd/conf/httpd.conf 中,取消注释以下三行

LoadModule ssl_module modules/mod_ssl.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
Include conf/extra/httpd-ssl.conf

如果使用 Certbot (certbot --apache),则还需要取消注释以下行

LoadModule rewrite_module modules/mod_rewrite.so

获取密钥和证书后,确保 /etc/httpd/conf/extra/httpd-ssl.conf 中的 SSLCertificateFileSSLCertificateKeyFile 行指向该密钥和证书。如果还生成了级联 CA 证书链,请将该文件名添加到 SSLCertificateChainFile 中。

最后,重启 httpd.service 以应用任何更改。

提示 Mozilla 有一篇有用的 SSL/TLS 文章 以及一个自动化工具,可帮助创建更安全的配置。

虚拟主机

注意 您需要添加一个单独的 <VirtualHost *:443> 部分以支持虚拟主机 SSL。请参阅 #管理多个虚拟主机 获取示例文件。

如果您想拥有多个主机,请取消注释 /etc/httpd/conf/httpd.conf 中的以下行

Include conf/extra/httpd-vhosts.conf

/etc/httpd/conf/extra/httpd-vhosts.conf 中设置您的虚拟主机。默认文件包含一个详尽的示例,应该可以帮助您入门。

要在本地计算机上测试虚拟主机,请将虚拟名称添加到您的 /etc/hosts 文件中

127.0.0.1 domainname1.dom 
127.0.0.1 domainname2.dom

重启 httpd.service 以应用任何更改。

管理多个虚拟主机

注意 如果您计划使用 certbot 部署 TLS 证书,则必须将虚拟服务器分隔为单独的文件。将所有虚拟服务器列在单个文件中(默认做法)会导致 certbot 无法正确部署证书。

如果您有大量的虚拟主机,可能需要轻松地禁用和启用它们。建议为每个虚拟主机创建一个配置文件,并将它们全部存储在一个文件夹中,例如:/etc/httpd/conf/vhosts

首先创建文件夹

# mkdir /etc/httpd/conf/vhosts

然后将单个配置文件放入其中

# nano /etc/httpd/conf/vhosts/domainname1.dom
# nano /etc/httpd/conf/vhosts/domainname2.dom
...

最后,在 /etc/httpd/conf/httpd.confInclude 这些单独的配置

#Enabled Vhosts:
Include conf/vhosts/domainname1.dom
Include conf/vhosts/domainname2.dom

您可以通过注释或取消注释来启用和禁用单个虚拟主机。

一个非常基础的虚拟主机文件如下所示

/etc/httpd/conf/vhosts/domainname1.dom
<VirtualHost *:80>
    ServerAdmin webmaster@domainname1.dom
    DocumentRoot "/home/user/http/domainname1.dom"
    ServerName domainname1.dom
    ServerAlias domainname1.dom
    ErrorLog "/var/log/httpd/domainname1.dom-error_log"
    CustomLog "/var/log/httpd/domainname1.dom-access_log" common

    <Directory "/home/user/http/domainname1.dom">
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin webmaster@domainname1.dom
    DocumentRoot "/home/user/http/domainname1.dom"
    ServerName domainname1.dom:443
    ServerAlias domainname1.dom:443
    SSLEngine on
    SSLCertificateFile "/etc/httpd/conf/server.crt"
    SSLCertificateKeyFile "/etc/httpd/conf/server.key"
    ErrorLog "/var/log/httpd/domainname1.dom-error_log"
    CustomLog "/var/log/httpd/domainname1.dom-access_log" common

    <Directory "/home/user/http/domainname1.dom">
        Require all granted
    </Directory>
</VirtualHost>

扩展

PHP

首先安装 PHP,然后按照以下三个小节之一进行操作。最后,按照最后一节所述测试安装。

使用 libphp

这种方法可能是最简单的,但也是可扩展性最差的:它适用于轻量负载。它还需要您更改 MPM 模块,这可能会导致其他扩展出现问题(例如,它与 #HTTP/2 不兼容)。

安装 php-apache

注意 如果您使用的是 AUR 中固定了旧版本的 PHP,则应该安装相应固定版本的 php-apache,例如 php56-apacheAUR 对应 php56AUR

/etc/httpd/conf/httpd.conf 中,注释掉以下行

#LoadModule mpm_event_module modules/mod_mpm_event.so

并取消注释以下行

LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
注意 以上操作是必需的,因为软件包中包含的 libphp.so 不能与 mod_mpm_event 一起使用,只能与 mod_mpm_prefork 一起使用。(FS#39218

否则,您将收到以下错误

Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe.  You need to recompile PHP.
AH00013: Pre-configuration failed
httpd.service: control process exited, code=exited status=1
或者,您可以使用 mod_proxy_fcgi(请参阅下文 #使用 php-fpm 和 mod_proxy_fcgi)。

要启用 PHP,请将这些行添加到 /etc/httpd/conf/httpd.conf

  • 将其放在 LoadModule 列表的末尾
LoadModule php_module modules/libphp.so
AddHandler php-script .php
  • 将其放在 Include 列表的末尾
Include conf/extra/php_module.conf

然后 重启 httpd.service

注意 对于 AUR 固定版本的 PHP,请相应地替换上述的 php_modulelibphp.sophp_module.conf。例如,对于 php56-apacheAUR,应为 php5_modulelibphp56.sophp56-module.conf


如果您不确定正确的替换项,请使用 pacman -Ql phpXX-apache 列出 libphp.sophp_module.conf 的正确替换项,然后使用 nm /usr/lib/httpd/modules/libphpXX.so 找到 php_module 的正确替换项。

使用 apache2-mpm-worker 和 mod_fcgid

这种方法在服务多个请求时提供了更高的性能和内存利用率。

安装 mod_fcgidAURphp-cgi

创建所需的目录并为 PHP 包装器创建符号链接

# mkdir /srv/http/fcgid-bin
# ln -s /usr/bin/php-cgi /srv/http/fcgid-bin/php-fcgid-wrapper

创建 /etc/httpd/conf/extra/php-fcgid.conf 并写入以下内容

/etc/httpd/conf/extra/php-fcgid.conf
# Required modules: fcgid_module

<IfModule fcgid_module>
    AddHandler php-fcgid .php
    AddType application/x-httpd-php .php
    Action php-fcgid /fcgid-bin/php-fcgid-wrapper
    ScriptAlias /fcgid-bin/ /srv/http/fcgid-bin/
    SocketPath /var/run/httpd/fcgidsock
    SharememPath /var/run/httpd/fcgid_shm
        # If you don't allow bigger requests many applications may fail (such as WordPress login)
        FcgidMaxRequestLen 536870912
        # Path to php.ini – defaults to /etc/phpX/cgi
        DefaultInitEnv PHPRC=/etc/php/
        # Number of PHP children that will be launched. Leave undefined to let PHP decide.
        #DefaultInitEnv PHP_FCGI_CHILDREN 3
        # Maximum requests before a process is stopped and a new one is launched
        #DefaultInitEnv PHP_FCGI_MAX_REQUESTS 5000
    <Location /fcgid-bin/>
        SetHandler fcgid-script
        Options +ExecCGI
        Require all granted
    </Location>
</IfModule>

编辑 /etc/httpd/conf/httpd.conf

  • 取消注释对 actions 模块的加载
    LoadModule actions_module modules/mod_actions.so
  • 在加载 unixd 模块(它依赖于此模块)之后加载 FCGID 模块 - 您可能希望将其放在 <IfModule unixd_module> 块内
    LoadModule fcgid_module modules/mod_fcgid.so
  • 确保取消注释对 MPM 配置的包含(默认安装的版本中已取消注释)
    Include conf/extra/httpd-mpm.conf
  • 添加对您的新 FCGID 配置的包含
    Include conf/extra/php-fcgid.conf

重启 httpd.service

使用 php-fpm 和 mod_proxy_fcgi

这种方法提供了“一种替代的 PHP FastCGI 实现,具有一些(主要)对高负载网站有用的附加功能” [1]

注意 与使用 ProxyPass 的常见设置不同,使用 SetHandler 的代理配置尊重其他 Apache 指令(如 DirectoryIndex)。这确保了与为 libphp、mod_fastcgi 和 mod_fcgid 设计的软件有更好的兼容性。如果您仍想尝试 ProxyPass,请尝试使用类似这样的行
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php-fpm/php-fpm.sock|fcgi:///srv/http/$1

安装 php-fpm

启用代理模块

/etc/httpd/conf/httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

创建 /etc/httpd/conf/extra/php-fpm.conf 并写入以下内容

DirectoryIndex index.php index.html
<FilesMatch \.php$>
    SetHandler "proxy:unix:/run/php-fpm/php-fpm.sock|fcgi:///"
</FilesMatch>

并在 /etc/httpd/conf/httpd.conf 的底部包含它

Include conf/extra/php-fpm.conf
注意 sockfcgi 之间的管道符号周围不允许有空格!localhost 可以替换为任何字符串。更多信息请见此处

您可以在 /etc/php/php-fpm.d/www.conf 中配置 PHP-FPM,但默认设置应该可以正常工作。

启动启用 php-fpm.service,然后 重启 httpd.service

测试 PHP 是否工作

要测试 PHP 是否已正确配置,请在您的 Apache DocumentRoot 目录(例如 /srv/http/~<username>/public_html/)中创建一个名为 test.php 的文件,并包含以下内容

<?php phpinfo(); ?>

然后根据需要转到 https:///test.php 或 https:///~<username>/test.php。

HTTP/2

  • 虽然 Apache 支持通过 TCP 进行未加密的 HTTP/2 (h2c),但常见的浏览器并不支持。因此,为了在后者上使用,必须首先启用 #TLS
  • 如果支持的客户端没有使用 HTTP/2 而使用 HTTP/1.1,并且使用了 Mozilla 的配置生成器(其中已经包含了下方的 Protocols 行)来设置 #TLS,请尝试在后者的输出之后 Include httpd-ssl.conf
  • 测试方法包括 curl -sI https://your.website 或使用 http indicator(同时支持基于 chromium 的浏览器和基于 firefox 的浏览器)。

要启用基于 TLS 的 HTTP/2 支持,请取消注释 httpd.conf 中的以下行

LoadModule http2_module modules/mod_http2.so

并添加以下行

Protocols h2 http/1.1

要调试,您可以仅将模块设置为 debuginfo,而不是将整个服务器设置为该级别

<IfModule http2_module>
    LogLevel http2:info
</IfModule>

有关更多信息(包括其他 HTTP/2 功能设置),请参阅 mod_http2 文档。

警告 http2_module 与旧配置广泛用于设置 PHP 的 mpm_prefork_module 不兼容。考虑改用 php-fpm

故障排除

Apache 状态和日志

使用 systemctl 查看 Apache 守护进程的状态。

Apache 日志位于 /var/log/httpd/

错误:启动后 PID 文件 /run/httpd/httpd.pid 无法读取

注释掉 httpd.conf 中的 unique_id_module 行:#LoadModule unique_id_module modules/mod_unique_id.so

启动时未创建 /run/httpd

如果以 root 用户身份运行 systemd-tmpfiles --create 时提示“unsafe path transition”,请检查根目录的所有权。

ls -la /
chown root:root /

Apache 运行的是线程化 MPM,但 PHP 模块未编译为线程安全

如果在加载 php_modulehttpd.service 失败,您可能会在日志中看到类似这样的错误

Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe.  You need to recompile PHP.

这是因为 PHP 包含对非线程安全模块的支持,而您正在尝试使用线程化 MPM。解决此问题的一种方法是使用非线程化 MPM。尝试将 mpm_event_module 替换为 mpm_prefork_module

/etc/httpd/conf/httpd.conf
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

重启 httpd.service

警告mpm_prefork 激活时,其他一些模块(如 http2_module)会自动禁用。

AH00534: httpd: 配置错误:未加载 MPM。

最近升级后您可能会遇到此错误。这仅仅是 httpd.conf 中最近的更改导致的,您可能没有在本地配置中同步这些更改。要修复它,请取消注释以下行

/etc/httpd/conf/httpd.conf
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

重启 httpd.service

AH00072: make_sock: 无法绑定到地址

这可能是由多种原因引起的。最常见的问题是某些内容已经在监听给定端口,请通过 ss 检查这种情况

# ss -lnp | grep -e :80 -e :443

如果有任何输出,请停止占用该端口的特定服务或杀死导致端口被绑定的失控进程,然后重试。

另一个问题可能是 Apache 出于某种原因没有以 root 身份启动 - 尝试手动启动它,看看是否仍然收到 AH0072 错误。

# httpd -k start

最后,您的配置也可能存在错误,即您在给定端口上监听了两次。以下是会导致此问题的错误配置示例

Listen 0.0.0.0:80
Listen [::]:80

AH01071: 收到错误 'Primary script unknown'

如果您在 /home(例如在虚拟主机环境中)中提供文件,这可能是由 php-fpm systemd 单元文件中的 ProtectHome=true 引起的。您可以通过 编辑 php-fpm 单元文件重启 php-fpm.service 来禁用此功能。或者,移动您的文档根目录。

更改 php.ini 中的 max_execution_time 无效

如果您将 php.ini 中的 max_execution_time 更改为大于 30(秒)的值,您可能在 30 秒后仍然会从 Apache 收到 503 Service Unavailable 响应。要解决此问题,请在 <FilesMatch \.php$> 块之前立即在 http 配置中添加 ProxyTimeout 指令

/etc/httpd/conf/httpd.conf
ProxyTimeout 300

重启 httpd.service

PHP-FPM:错误日志未按虚拟主机分开记录

如果您有多个虚拟主机,可能希望它们各自将错误日志输出到单独的文件中(使用 ErrorLog Apache 指令)。如果这对您不起作用,请确认 PHP-FPM 已配置为将错误记录到 syslog

/etc/php/php-fpm.conf
error_log = syslog

也有可能是池配置覆盖了它。确保注释掉以下行

/etc/php/php-fpm.d/www.conf
;php_admin_value[error_log] = /var/log/fpm-php.www.log

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.