将所有流量重定向到 HTTP(一个 URL 除外)

将所有流量重定向到 HTTP(一个 URL 除外)

我一直很困惑,因为所有的论坛都说,下面的简单代码应该可以将所有流量从 HTTPS 重定向到 HTTP,除了一个位置(Nginx:强制在一个路径上使用 SSL,在其他路径上使用非 SSL)但就我而言,它没有按预期工作

这是 Magento 网站,具有以下 nginx 配置

upstream examplecombackend {
    server unix:/var/run/php-fcgi-examplecom.sock;
}

server {
    listen 111.11.111.111:80;

    server_name example.com *.example.com;

    access_log /home/www/vhosts/example.com/logs/access.log;
    error_log /home/www/vhosts/example.com/logs/error.log;
    root /home/www/vhosts/example.com/httpdocs;

    location / {
        index index.html index.php;
        try_files $uri $uri/ @handler;
        expires 30d;
    }

    location /checkout/ {
        rewrite ^ https://$host$request_uri? permanent;
    }

    location @handler {
        rewrite / /index.php;
    }

    location ~ .php/ {
        rewrite ^(.*.php)/ $1 last;
    }

    location ~ .php$ {
        if (!-e $request_filename) {
            rewrite / /index.php last;
        }
        expires        off;
        fastcgi_pass   examplecombackend;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

server {
    listen 111.11.111.111:443 ssl;
    ssl_certificate      /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key  /etc/nginx/ssl/example.com.key;
    ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;

    server_name example.com *.example.com;

    root /home/www/vhosts/example.com/httpdocs;

    location / {
        rewrite ^ http://$host$request_uri? permanent;
    }

    location /checkout/ {
    }
}

现在,当我转到 SSL 时,执行此操作后https://example.com/它正确地转发到非 SSLhttp://example.com/但如果我去https://example.com/checkout它说

404 Not Found
nginx/1.8.1

不确定我在这里遗漏了什么......

答案1

首先,我不会自己做这样的配置。在同一个网站上混合使用会使http安全性变弱,并使你的网站面临中间人攻击。httpshttps

然而,如果您确实想要设置这样的东西,这里应该有一个适合您的工作配置。

您的配置中的主要问题是缺少 URI 的 PHP 定义/checkout

我会进行如下配置。这还包含针对您的配置的优化:

upstream examplecombackend {
    server unix:/var/run/php-fcgi-examplecom.sock;
}

server {
    listen 111.11.111.111:80;

    server_name example.com *.example.com;

    access_log /home/www/vhosts/example.com/logs/access.log;
    error_log /home/www/vhosts/example.com/logs/error.log;
    root /home/www/vhosts/example.com/httpdocs;

    location / {
        index index.html index.php;
        try_files $uri $uri/ /index.php;
        expires 30d;
    }

    location /checkout {
        rewrite ^ https://$host$request_uri? permanent;
    }

    location ~ (.+\.php)/ {
        rewrite ^ $1 last;
    }

    location ~ \.php$ {
        expires        off;
        fastcgi_pass   examplecombackend;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

server {
    listen 111.11.111.111:443 ssl;
    ssl_certificate      /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key  /etc/nginx/ssl/example.com.key;
    ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;

    server_name example.com *.example.com;

    root /home/www/vhosts/example.com/httpdocs;

    location /checkout {
        rewrite ^ /index.php;
    }

    location ~ \.php$ {
        expires        off;
        fastcgi_pass   examplecombackend;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    location / {
        rewrite ^ http://$host$request_uri? permanent;
    }
}

我做的改变:

location / {
    index index.html index.php;
    try_files $uri $uri/ /index.php;
    expires 30d;
}

我删除了位置,因为它与指令的最后一个元素@handler相同。index.phptry_files

location ~ .php/ {
    rewrite ^(.*.php)/ $1 last;
}

我改变了正则表达式捕获以使其在级别上发生location,因此在与此位置匹配的每个请求中发生的正则表达式匹配会少一个,因为我们可以^在指令中使用简单作为匹配条件rewrite

    location ~ \.php$ {
        if (!-e $request_filename) {
            rewrite / /index.php last;
        }

我在location正则表达式条件中添加了反斜杠转义符,因为如果没有反斜杠,它就会匹配,例如/path/to/aphp,因为.它本身可以匹配任何字符。

我还if从块中删除了上面显示的测试,因为相同的测试已经在try_files之前的指令中发生了。

最后,解决您的实际问题:

在您的serverhttps 块中,我更改了location如下块:

    location /checkout {
        rewrite ^ /index.php;
    }

    location ~ \.php$ {
        expires        off;
        fastcgi_pass   examplecombackend;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

因此,该location /checkout块告诉 nginx 将所有请求重写为/index.php,就像在http服务器块中一样。此外,PHP 处理location与块中的相同http

http但是,Magento 创建的链接以及在和之间重定向请求的方式可能仍然存在问题https。Cookie 安全设置是可能导致问题的因素之一。

答案2

尝试一下这个小改动。~* 应该告诉 Nginx 不区分大小写地匹配任何包含 /checkout/ 的 URL,而不仅仅是精确的 URL /checkout/。

我有点生疏,记不清精确的位置匹配顺序和语法,但值得尝试。

location ~* /checkout/ {

答案3

条件重写可能对你的情况有帮助:

server {
    listen 111.11.111.111:80;
    listen 111.11.111.111:443 ssl;   

    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key  /etc/nginx/ssl/example.com.key;
    ssl_protocols   TLSv1 TLSv1.1 TLSv1.2;

    server_name example.com *.example.com;

    access_log /home/www/vhosts/example.com/logs/access.log;
    error_log /home/www/vhosts/example.com/logs/error.log;

    root /home/www/vhosts/example.com/httpdocs;

    location / {
        if ($scheme = "https") {
            return 301 http://$server_name$request_uri;
            break;
        }
        index index.html index.php;
        try_files $uri $uri/ @handler;
        expires 30d;
    } 

    location /checkout/ {
        if ($scheme = "http") {
            return 301 https://$server_name$request_uri;
            break;
        }
    }

    location @handler {
        rewrite / /index.php;
    }

    location ~ .php/ {
        rewrite ^(.*.php)/ $1 last;
    }

    location ~ .php$ {
        if (!-e $request_filename) { rewrite / /index.php last; }
        expires        off;
        fastcgi_pass   examplecombackend;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

相关内容