我有一台在代理设置中同时运行 Nginx 和 Apache 的服务器,Nginx 提供静态内容,Apache 提供动态内容,效果非常好。
此设置当前托管同一站点的两个版本,我们将其称为 production.com 和 staging.com。
我刚刚使用 SSL 设置完了 production.com 网站,它也运行得很好,但发现如果我也使用 SSL 浏览 staging.com,我就会得到 production.com 的 Web 根目录的内容,这显然是错误的。
有人告诉我对 SSL 和非 SSL 都使用一个默认处理程序,这将消除这种行为,但这正是我遇到麻烦的地方。
现在我在 nginx.conf 中包含了此配置
默认80.confserver {
listen 80;
server_name "";
return 444;
}
默认_443.conf
server {
listen 443 default_server ssl;
server_name "";
return 444;
}
staging.com.conf
server {
listen 80;
server_name staging.com;
access_log /var/log/nginx/staging.com.log;
# static content folders
location ^~ /(images|css|js) {
root /var/www/staging.com/current;
access_log /var/log/nginx/staging.com.static.log;
}
# static content files
location ~* \.(js|css|rdf|xml|ico|txt|jpg|gif|png|jpeg)$ {
root /var/www/staging.com/current;
access_log /var/log/nginx/staging.com.static.log;
}
# proxy the rest to apache
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}
生产环境.com.conf
server {
listen 80;
server_name production.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
server_name production.com;
access_log /var/log/nginx/production.com.log;
ssl_certificate /etc/httpd/conf.d/SSL/ev.crt;
ssl_certificate_key /etc/httpd/conf.d/SSL/server.key;
keepalive_timeout 60;
# static content folders
location ^~ /(images|css|js) {
root /var/www/production.com/current;
access_log /var/log/nginx/production.com.static.log;
}
# static content files
location ~* \.(js|css|rdf|xml|ico|txt|jpg|gif|png|jpeg)$ {
root /var/www/production.com/current;
access_log /var/log/nginx/production.com.static.log;
}
# proxy the rest to apache
location / {
# proxy settings
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}
此设置将终止对两个站点中任何一个站点的所有类型的 SSL 访问,而如果我从 default_443.conf 中删除“default_server”指令,则它可以对两个站点都起作用。
所以问题是,我如何关闭 SSL 访问(https://staging.com为 staging.com 返回 444) 并在 production.com 上启用它?
致以最诚挚的问候 Lars
答案1
首先,如果您使用其中一个奇怪的发行版,请确认您的 Nginx 版本是否支持 SNI(您应该在顶部看到启用的 TLS SNI 支持):
nginx -V
我已经发布了以下设置,下面是我的盒子上的结果(/var/www/production/index.html 包含 PRODUCTION 和 /var/www/staging/index.html,STAGING)
http://192.168.56.101连接重置(444)
https://192.168.56.101连接重置(444)
http://staging.example.com分期
https://staging.example.com重定向到 http
http://production.example.com重定向到 https
https://production.example.com生产
作为参考,我使用了 Debian 存储库中的稳定版 nginx (0.7.67),但我在 1.0.something 上有一个非常相似的设置,其工作原理几乎完全相同。如果您无法使其工作,请告诉我们您的确切版本。
就您而言,您可能希望将两个默认值都更改为 default_server。您可能还希望使重写永久生效,并且如果您的 nginx 版本允许,也许可以将其更改为返回 301。
/etc/nginx/sites-enabled/default
server {
listen 80 default;
return 444;
}
server {
listen 443 default;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
return 444;
}
/etc/nginx/sites-enabled/production
server {
listen 80; ## listen for ipv4
server_name production.example.com;
rewrite ^ https://production.example.com$request_uri?;
}
server {
listen 443;
server_name production.example.com;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
keepalive_timeout 60;
location / {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
/etc/nginx/sites-enabled/staging
server {
listen 80;
server_name staging.example.com;
keepalive_timeout 60;
location / {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 443; ## listen for ipv4
server_name staging.example.com;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
keepalive_timeout 60;
rewrite ^(.*) http://staging.example.com$1;
}
/etc/apache2/sites-enabled/production
<VirtualHost *:81>
ServerAdmin webmaster@localhost
ServerAlias production.example.com
DocumentRoot /var/www/production
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/production>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
/etc/apache2/sites-enabled/staging
<VirtualHost *:81>
ServerAdmin webmaster@localhost
ServerAlias staging.example.com
DocumentRoot /var/www/staging
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/staging>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
/etc/apache2/ports.conf
NameVirtualHost *:81
Listen 81
答案2
我(在 IRC 上 3molo 的帮助下)通过为 staging.com 添加一个使用 ssl 的服务器块并重写为 HTTP 解决了这个问题,在我看来这是一个公认的解决方法。
server {
listen 443 ssl;
server_name staging.com;
ssl_certificate /etc/httpd/conf.d/SSL/ev.crt;
ssl_certificate_key /etc/httpd/conf.d/SSL/server.key;
keepalive_timeout 60;
rewrite ^ http://$server_name$request_uri? permanent;
}
但问题仍然存在,当 $http_host 和 server_name 不匹配时,Nginx 究竟为什么会提供内容?如果有人知道这个问题的答案,我很乐意听听。
答案3
如果 staging.com 和 production.com 指向相同的 IP 地址,那么这超出了您的控制范围,因为 SSL 是在客户端发送主机头之前协商的。
如果可能的话,每个站点使用一个 IP,如果不可能,您可能能够在 production.com 的服务器上下文中“if $host = staging.com ..”