我将 nginx 与多个 fastcgi 后端(php-cgi、mod-mono-fastcgi4)一起使用。现在我需要向fastcgi后端发送一个额外的http标头,基本上与使用nginx作为反向代理时的proxy_set_header相同。但根据我的发现,nginx中没有fastcgi_set_header这样的东西。
有人知道如何做到这一点吗?我不想使用额外的 nginx 模块,因为解决方案必须能够轻松部署在各种客户系统上。
我快速浏览了手册,我认为您会发现最接近的是传递 fastcgi 参数:
请求标头以参数的形式传输到FastCGI服务器。在从 FastCGI 服务器运行的应用程序和脚本中,这些参数通常可以以环境变量的形式访问。例如,标头“User-agent”作为参数 HTTP_USER_AGENT 进行传输。除了 HTTP 请求的标头之外,还可以借助指令 fastcgi_param 传输任意参数。
http://wiki.nginx.org/HttpFcgiModule#Parameters.2C_transferred_to_FastCGI-server.
fastcgi_param
语法:fastcgi_param参数值
上述 nginx wiki 文章的 URL 已损坏。
nginx 通过前缀为 $http_ 的变量公开请求标头值,因此可以通过 $http_user_agent 获得 HTTP_USER_AGENT 的请求标头。
同样,名为 CHICKEN_SOUP 的请求标头可以通过 $http_chicken_soup 获得。
下面的示例展示了如何将 Authorization HTTP 请求标头传递给在 php-fpm(PHP FastCGI 进程管理器)下运行的 PHP 脚本。
location ~ \.php$ {
fastcgi_pass unix:/path/to/socket;
fastcgi_index index.php;
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
... other settings
}
我认为Zoot的答案很好,并基于它,我想为任何它能帮助的人走得更远。为了涵盖这两种情况,“上游反向代理”和“独立”,所以我将发布我为完成任务以将正确的标头转发到“最后一个”服务器所做的工作,以便应用程序可以拥有必要的信息(通过
SSL_*
标头)来分配正确的用户标识,而不是只允许通过而不管身份。这些示例涵盖 php 和 fastcgi,但我确信如果需要,它们可以轻松适应其他堆栈:
首先,在“独立”服务器(即中间没有反向代理)中执行验证:
server {
listen 443 ssl http2;
...
ssl_certificate /etc/XXX.pem;
ssl_certificate_key /etc/XXX.key;
ssl_client_certificate /etc/XXX/CA.pem;
ssl_verify_client optional; # Or whatever
location ~ ^/index\.php(/|$) {
fastcgi_pass php;
# The provided fastcgi script by nginx
include snippets/fastcgi-php.conf;
# A custom snippet to manage headers
include snippets/sslclient-fastcgi.conf;
}
}
定制
sslclient-fastcgi.conf
:
# Custom snippet to be used in a standalone server that performs verification
# by using a x509 client certificate. The nginx variables are transformed into
# SSL_* headers (trying to mimic Apache documentation with StdEnvVars and ExportCertData)
# and passes the result to an upstream using cgi to process headers.
fastcgi_param SSL_CIPHER $ssl_cipher;
fastcgi_param SSL_CLIENT_CERT $ssl_client_raw_cert;
fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
fastcgi_param SSL_CLIENT_V_END $ssl_client_v_end;
fastcgi_param SSL_CLIENT_V_REMAIN $ssl_client_v_remain;
fastcgi_param SSL_CLIENT_V_START $ssl_client_v_start;
fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify; # “SUCCESS”, “FAILED:reason”, and “NONE”
fastcgi_param SSL_PROTOCOL $ssl_protocol;
fastcgi_param SSL_SERVER_S_DN $ssl_server_name;
这样,应用程序只需读取正确的
SSL_*
标头并根据内容进行管理。
接下来是使用反向代理(执行验证)并将结果转发到上游 http 服务器的场景。一、反向代理的相关部分:
server {
listen 443 ssl http2;
...
ssl_certificate /etc/XXX.pem;
ssl_certificate_key /etc/XXX.key;
ssl_client_certificate /etc/XXX/CA.pem;
ssl_verify_client optional; # Or whatever
## PROXY backend
location / {
proxy_pass http://upstream:8080;
# Custom snippet to manage the proxy headers
include snippets/proxy_ssl_client-upstream.conf;
}
}
现在,
proxy_ssl_client-upstream.conf
文件:
# Snippet to be included in a reverse proxy server to catch the custom SSL_* headers
# (which will be seen as HTTP_SSL_* in the upstream) during the SSL verification process
# performed in the same proxy server, These headers should be transformed back
# to SSL_ for the web app, by using the corresponding
# $http_* variables generated by nginx. The web app should take care of
# SSL_* headers only.
# This is to prevent a warning about the bucket size
proxy_headers_hash_bucket_size 128;
# Here the standard SSL headers for a reverse SSL proxy
include snippets/proxy_ssl_standard-upstream.conf;
# And the set of headers, trying to mimic as much as possible the same headers
# that Apache generates via StdEnvVars and ExportCertData options in a SSLOptions directive
proxy_set_header SSL-CIPHER $ssl_cipher;
proxy_set_header SSL-CLIENT-CERT $ssl_client_escaped_cert;
proxy_set_header SSL-CLIENT-I-DN $ssl_client_i_dn;
proxy_set_header SSL-CLIENT-S-DN $ssl_client_s_dn;
proxy_set_header SSL-CLIENT-V-END $ssl_client_v_end;
proxy_set_header SSL-CLIENT-V-REMAIN $ssl_client_v_remain;
proxy_set_header SSL-CLIENT-V-START $ssl_client_v_start;
proxy_set_header SSL-CLIENT-VERIFY $ssl_client_verify; # “SUCCESS”, “FAILED:reason”, and “NONE”
proxy_set_header SSL-PROTOCOL $ssl_protocol;
proxy_set_header SSL-SERVER-S-DN $ssl_server_name;
并且自定义包括
proxy_ssl_standard-upstream.conf
(当不涉及客户端证书时,应该包括它而不是 proxy_ssl_client-upstream.conf
):
# forward standard headers to an upstream server
add_header Front-End-Https on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
最后是上游服务器的相关部分:
server {
listen 8080;
...
# PROD
location ~ ^/index\.php(/|$) {
fastcgi_pass php;
# The standard snippet provided by nginx
include snippets/fastcgi-php.conf;
# A custom snippet to manage the headers forwarded by the reverse proxy
include snippets/proxy_ssl_client-fastcgi.conf;
}
包含的
ssl_proxy_client-fastcgi.conf
:
# Snippet to be included in an upstream server to catch the custom HTTP_SSL_* headers
# generated by another custom snippet during the SSL verification process
# performed by a reverse proxy server. This snippet transforms these generated
# HTTP_SSL_* headers as SSL_* to the web app via fastcgi, by using the corresponding
# $http_* variables generated by nginx. The web app should take care of
# SSL_* headers only.
fastcgi_param SSL_CIPHER $http_ssl_cipher;
fastcgi_param SSL_CLIENT_CERT $http_ssl_client_cert;
fastcgi_param SSL_CLIENT_I_DN $http_ssl_client_i_dn;
fastcgi_param SSL_CLIENT_S_DN $http_ssl_client_s_dn;
fastcgi_param SSL_CLIENT_V_END $http_ssl_client_v_end;
fastcgi_param SSL_CLIENT_V_REMAIN $http_ssl_client_v_remain;
fastcgi_param SSL_CLIENT_V_START $http_ssl_client_v_start;
fastcgi_param SSL_CLIENT_VERIFY $http_ssl_client_verify; # “SUCCESS”, “FAILED:reason”, and “NONE”
fastcgi_param SSL_PROTOCOL $http_ssl_protocol;
fastcgi_param SSL_SERVER_S_DN $http_ssl_server_s_dn;
# Clean up already used HTTP_* headers from proxy
fastcgi_pass_request_headers off;
我希望这可以帮助解决有关如何在 nginx 中管理 ssl 客户端证书的任何问题。
您可以使用第三方模块ngx_headers_more来完成此操作。构建包含此模块的 nginx 后,您可以在配置中执行以下操作:
location / {
more_set_input_headers 'Foo: bar baz';
...
}
Nginx 现在有:
fastcgi_pass_header 'Cache-Control: no-cache, must-revalidate';
如果您要添加请求中尚未指定的标头,则可以在您的位置规则中使用它。默认情况下 fastcgi 使用:
fastcgi_pass_request_headers on;
这会将请求中的所有传入标头传递给 fastcgi。