最近我更加关注 nginx(并且使用它来运行 HTTP/2 没有任何问题),但是我对 Apache 完全感到困惑,似乎无法让它通过 HTTP/2 为网站提供服务。
服务器是 Debian 8。我通过启用 Debian“测试”存储库安装了 Apache 2.4.27 和 openssl1.1.0f。
以下是一些有用的信息和服务器配置:
Apache 版本
root@server:~# apachectl -V
Server version: Apache/2.4.27 (Debian)
Server built: 2017-07-16T21:01:10
Server's Module Magic Number: 20120211:68
Server loaded: APR 1.5.1, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture: 64-bit
Server MPM: prefork
threaded: no
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_SYSVSEM_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="/etc/apache2"
-D SUEXEC_BIN="/usr/lib/apache2/suexec"
-D DEFAULT_PIDLOG="/var/run/apache2.pid"
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
-D DEFAULT_ERRORLOG="logs/error_log"
-D AP_TYPES_CONFIG_FILE="mime.types"
-D SERVER_CONFIG_FILE="apache2.conf"
Apache 模块
root@server:~# apachectl -M
Loaded Modules:
core_module (static)
so_module (static)
watchdog_module (static)
http_module (static)
log_config_module (static)
logio_module (static)
version_module (static)
unixd_module (static)
access_compat_module (shared)
alias_module (shared)
auth_basic_module (shared)
authn_core_module (shared)
authn_file_module (shared)
authz_core_module (shared)
authz_host_module (shared)
authz_user_module (shared)
autoindex_module (shared)
deflate_module (shared)
dir_module (shared)
env_module (shared)
expires_module (shared)
filter_module (shared)
headers_module (shared)
http2_module (shared)
mime_module (shared)
mpm_prefork_module (shared)
negotiation_module (shared)
php5_module (shared)
reqtimeout_module (shared)
rewrite_module (shared)
setenvif_module (shared)
socache_shmcb_module (shared)
ssl_module (shared)
status_module (shared)
OpenSSL 版本
root@server:/root# openssl version
OpenSSL 1.1.0f 25 May 2017
Apache 基本配置
root@server:~# cat /etc/apache2/apache2.conf
DefaultRuntimeDir ${APACHE_RUN_DIR}
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
AccessFileName .htaccess
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
Apache SSL 配置
root@server:~# cat /etc/apache2/mods-available/ssl.conf
<IfModule mod_ssl.c>
SSLRandomSeed startup builtin
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect builtin
SSLRandomSeed connect file:/dev/urandom 512
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
SSLSessionCacheTimeout 300
SSLCipherSuite 'EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS'
SSLHonorCipherOrder on
SSLProtocol all -SSLv3
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
SSLOpenSSLConfCmd DHParameters "/etc/apache2/ssl/dhparam.pem"
<FilesMatch "\.php$">
SSLOptions +StdEnvVars
</FilesMatch>
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</IfModule>
Apache HTTP2 配置
root@server:~# cat /etc/apache2/mods-enabled/http2.conf
H2Push on
H2PushPriority * after
H2PushPriority text/css before
H2PushPriority image/jpeg after 32
H2PushPriority image/png after 32
H2PushPriority application/javascript interleaved
Apache 安全配置
root@server:~# cat /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
TraceEnable Off
<IfModule mod_headers.c>
Header set X-UA-Compatible "IE=Edge"
Header always set Strict-Transport-Security "max-age=15768000"
<FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ico|jpe?g|js|json(ld)?|m4[av]|manifest|map|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|webmanifest|woff2?|xloc|xml|xpi)$">
Header unset X-UA-Compatible
</FilesMatch>
Header always append X-Frame-Options SAMEORIGIN
Header set X-Content-Type-Options nosniff
Header set X-XSS-Protection "1; mode=block"
</IfModule>
<IfModule mod_setenvif.c>
SetEnvIf Request_URI "^/(browserconfig\.xml|manifest\.json|robots\.txt|sitemap\.xml|.well-known/.*)$" dontlog
</IfModule>
<IfModule mod_rewrite.c>
<FilesMatch "^/(browserconfig\.xml|manifest\.json|robots\.txt|sitemap\.xml)$">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</FilesMatch>
</IfModule>
<FilesMatch "(?:^|/)\.">
Require all denied
</FilesMatch>
<FilesMatch "(?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$">
Require all denied
</FilesMatch>
Apache VirtualHost 配置
root@server:~# cat /etc/apache2/sites-available/www_xxxxxx_com.conf
ServerName server
<VirtualHost *:80>
ServerName xxxxxx.com
Redirect 301 / https://www.xxxxxx.com/
</VirtualHost>
<VirtualHost *:80>
ServerName www.xxxxxx.com
Redirect 301 / https://www.xxxxxx.com/
</VirtualHost>
<VirtualHost *:443>
ServerName xxxxxx.com
Redirect 301 / https://www.xxxxxx.com/
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xxxxxx.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
SSLCACertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
Protocols h2 http/1.1
</VirtualHost>
<VirtualHost *:443>
ServerName www.xxxxxx.com
ServerAdmin webmaster@localhost
DocumentRoot /data/www_xxxxxx_com/public_html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined env=!dontlog
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xxxxxx.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
SSLCACertificateFile /etc/letsencrypt/live/xxxxxx.com/fullchain.pem
Protocols h2 http/1.1
<Directory /data/www_xxxxxx_com/public_html/>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
我使用以下方法测试了这一切https://tools.keycdn.com/http2-test结果是负面的,再加上使用 curl (版本 7.55.1 - 支持 HTTP2):
➜ ~ curl -v --http2 https://www.xxxxxx.com
* Rebuilt URL to: https://www.xxxxxx.com/
* Trying XXX.XXX.XXX.XXX...
* TCP_NODELAY set
* Connected to www.xxxxxx.com (XXX.XXX.XXX.XXX) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /usr/local/etc/openssl/cert.pem
CApath: /usr/local/etc/openssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=xxxxxx.com
* start date: Aug 24 11:07:00 2017 GMT
* expire date: Nov 22 11:07:00 2017 GMT
* subjectAltName: host "www.xxxxxx.com" matched cert's "www.xxxxxx.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
HTTP/1.1 200 OK
Date: Thu, 24 Aug 2017 15:30:35 GMT
Server: Apache
Strict-Transport-Security: max-age=15768000
X-Frame-Options: SAMEORIGIN
Upgrade: h2
Connection: Upgrade
Set-Cookie: PHPSESSID=knqh31ge9fqd60g4r40r7ngum4; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-UA-Compatible: IE=Edge
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: text/html; charset=UTF-8
有谁知道我在这里错过了什么,因为它让我发疯?
干杯!
答案1
哦,天哪——为什么我几乎总是在发布问题后才弄清楚这些事情。哦,好吧——希望这对其他人有帮助。
答案就在错误日志中:
[Thu Aug 24 17:55:09.795729 2017] [http2:info] [pid 16949] AH03090: mod_http2 (v1.10.7, feats=CHPRIO+SHA256+INVHD+DWINS, nghttp2 1.24.0), initializing...
[Thu Aug 24 17:55:09.795846 2017] [http2:warn] [pid 16949] AH10034: The mpm module (prefork.c) is not supported by mod_http2. The mpm determines how things are processed in your server. HTTP/2 has more demands in this regard and the currently selected mpm will just not do. This is an advisory warning. Your server will continue to work, but the HTTP/2 protocol will be inactive.
[Thu Aug 24 17:55:09.827124 2017] [mpm_prefork:notice] [pid 16949] AH00163: Apache/2.4.27 (Debian) OpenSSL/1.0.2l configured -- resuming normal operations
因此我们开始吧——只需使用“event”或“worker”MPM,而不是prefork。