Nginx 使用 https 访问时提供来自错误“虚拟主机”的内容

Nginx 使用 https 访问时提供来自错误“虚拟主机”的内容

我有一台在代理设置中同时运行 Nginx 和 Apache 的服务器,Nginx 提供静态内容,Apache 提供动态内容,效果非常好。

此设置当前托管同一站点的两个版本,我们将其称为 production.com 和 staging.com。

我刚刚使用 SSL 设置完了 production.com 网站,它也运行得很好,但发现如果我也使用 SSL 浏览 staging.com,我就会得到 production.com 的 Web 根目录的内容,这显然是错误的。

有人告诉我对 SSL 和非 SSL 都使用一个默认处理程序,这将消除这种行为,但这正是我遇到麻烦的地方。

现在我在 nginx.conf 中包含了此配置

默认80.conf
server {
    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 ..”

相关内容