Nginx не перенаправляет без www на www

Nginx не перенаправляет без www на www

Мне нужна моя настройка Nginx для перенаправления пользователей на www.example.com, если они вводят example.com в браузере. Причина в том, что наш консультант по SEO сказал, что должен быть только один предпочтительный домен, иначе Google посчитает это дублированием контента. В любом случае...

Итак, суть в том, что у меня также установлен SSL от Letsencrypt на сервере, но я не могу добиться перенаправления с example.com на www.example.com (сервер принимает обе версии). Вот конфигурация, которую я использую:

server {
    listen 80; 
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name example.com www.example.com;
    root /home/my_site;
    index index.php index.html index.htm;

    # for letsencrypt
    location ~ /.well-known {
        allow all;
    }   

    location / { 
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }   

    error_page 404 /404.html;

    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/share/nginx/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

==== Обновление ====

Теперь я изменил свою конфигурацию в соответствии с рекомендациями Тима (и я всегда так nginx -tделаю restart) в одном из ответов на следующие вопросы:

server {
    listen 80; 
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}    

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    root /home/ankush/wp_ankushthakur;
    index index.php index.html index.htm;

    # for letsencrypt
    location ~ /.well-known {
        allow all;
    }   

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    error_page 404 /404.html;

    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/share/nginx/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

Вот выходные данные curl -kи логи доступа для всех вариантов (я не собирал Nginx из исходников, потому что надеюсь на более простое решение и не хочу портить сервер):

curl -k http://example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k http://www.example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k https://example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k https://www.example.com
Curl output: <Blank>
Access logs: "GET / HTTP/1.1" 301 5 "-" "curl/7.47.0"

Обратите внимание на последний раздел, где вывод CURL пуст, а журналы доступа по-прежнему выдают постоянное перенаправление.

Забавно, но если я закомментирую второй serverблок и перезапущу Nginx, то получу эффект, обратный желаемому: www перенаправляет на не-www! Я удивлен, что это происходит, потому что HTTPS-версия www.example.com нигде не упоминается в этой (третьей) версии конфигурации.

решение1

Вероятно, это потому, что вы перенаправляете только на HTTP, но не на HTTPS. Вам следует добавить HTTPS к вашему перенаправляющему vhost и оставить там только example.comимя.

Более того, то, что вы делаете, противоположно тому, что люди делают сегодня: общепринятый подход — похоронить наследие.wwwпрефиксы старой эпохи и использовать только простые доменные имена, безwww.

решение2

Ключевым моментом здесь является то, что вам нужно иметь дело с четырьмя URL-адресами - http и https-версиями доменов www и без www. Ваша проблема в том, что вы перенаправляете http-версию домена www и без www наhttps://wwwдомен, но ваш основной серверный блок прослушивает обаhttps://example.comиhttps://www.example.com

Все, что вам нужно сделать, это создать отдельный серверный блок для пересылкиhttps://example.comкhttps://www.example.comсервер. Вам необходимо включить в это настройку https.

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  include snippets/ssl-example.com.conf;
  include snippets/ssl-params.conf;

  server_name example.com;
  return 301 https://www.example.com$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  include snippets/ssl-example.com.conf;
  include snippets/ssl-params.conf;

  server_name  www.example.com;

  # Main server block for main server continues
}

Стандартный пример

У меня естьучебникс загружаемыми файлами конфигурации. Стандартный пример ниже.

Если это не сработает, используйте curl для каждого варианта (http и https, www и без www) с опцией -k, чтобы отобразить заголовки, и отредактируйте свой вопрос, включив их.

# Main server
server {
  server_name www.example.com;
  listen 443 ssl http2;
  # etc, add all locations, call PHP or servers, etc
}


# Forward http requests to https www server
server {
  listen       80;
  server_name  example.com www.example.com;
  return       301 https://www.example.com$request_uri;
}

# Forward https non-www requests to the https www server
# Requires https setup for this server
server {
  listen 443 ssl http2;
  server_name example.com;

  ssl_certificate /var/lib/acme/certs/***CERT_DIRECTORY/fullchain;
  ssl_certificate_key /var/lib/acme/certs/***CERT_DIRECTORY/privkey;

  # Set up preferred protocols and ciphers. TLS1.2 is required for HTTP/2
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

  return 301 https://www.example.com$request_uri;
}

Решение проблем Лучший способ диагностики проблем:

  • используйте "curl -k" (показать заголовки) для каждого варианта домена в сочетании с журналом доступа. Возвращаемые коды статуса http говорят вам, что происходит. 200 — страница, 301 — постоянное перенаправление, 302 — временное перенаправление
  • Убедитесь, что в Nginx есть модуль headers_more, это можно сделать следующим образом:сборка Nginx из исходников, что довольно просто. Это позволяет вам добавлять заголовки https к ответу. Это отличный диагностический инструмент. Вы можете использовать такие операторы, чтобы определить, какие блоки выполняются

add_header Z_DEBUG "имя_местоположения_или_сообщение";

решение3

Мне наконец удалось убедить нашего специалиста по SEO считать домен без www основным. Конфигурация, которая сработала для перенаправления www на без www, была следующей. Хотя моя попытка добиться обратного имела похожую конфигурацию, я не уверен, что помешало этому.

server {
    listen 80; 
    listen [::]:80;

    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name example.com;

    root /home/mysite;
    index index.php;

    location ~ /.well-known {
        allow all;
    }

    location / {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        try_files $uri $uri/ /index.php?$query_string;
        set $path_info $fastcgi_path_info;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

Связанный контент