Nginx no-www до www та www до no-www


497

Я використовую nginx у хмарі Rackspace, виходячи з навчального посібника та провідавши мережу, і поки що не можу це відсортувати.

Я хочу, щоб www.mysite.com перейшов на mysite.com як звичайний .htaccess для SEO та інших причин.

Мій /etc/nginx/sites-available/www.example.com.vhost config:

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

Я також спробував

server {
       listen 80;
       server_name example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

Я також спробував. Обидві другі спроби дають помилки циклу перенаправлення.

if ($host = 'www.example.com' ) {
rewrite ^ http://example.com$uri permanent;
}

Мій DNS налаштовано стандартно:

site.com 192.192.6.8 A type at 300 seconds
www.site.com 192.192.6.8 A type at 300 seconds

(наприклад, IP-адреси та папки використовуються для прикладів та для допомоги людям у майбутньому). Я використовую Ubuntu 11.


1
Я змушений прокоментувати, що якщо ви працюєте з веб-сайтом WordPress, перевірте Dashboard > Settings > General Settingsта переконайтеся, що немає wwwв URL-адресах WordPress / адреса сайту. Незалежно від того, як ви налаштовуєте nginx, якщо у вас є www у цих URL-адресах, він буде переспрямований на той, у якому є www.
Абхінав Суд

Відповіді:


792

HTTP рішення

З документації "правильним способом є визначення окремого сервера для example.org":

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

server {
    listen       80;
    server_name  www.example.com;
    ...
}

Рішення HTTPS

Для тих, хто хоче рішення, включаючи https://...

server {
        listen 80;
        server_name www.domain.com;
        # $scheme will get the http protocol
        # and 301 is best practice for tablet, phone, desktop and seo
        return 301 $scheme://domain.com$request_uri;
}

server {
        listen 80;
        server_name domain.com;
        # here goes the rest of your config file
        # example 
        location / {

            rewrite ^/cp/login?$ /cp/login.php last;
            # etc etc...

        }
}

Примітка. Первісно я не включений https://у своє рішення, оскільки ми використовуємо балансири вантажів, а наш https: // сервер є високошвидкісним сервером платежів SSL: ми не змішуємо https: // та http: //.


Щоб перевірити версію nginx, використовуйте nginx -v.

Стріпте www з URL з перенаправленням nginx

server {
    server_name  www.domain.com;
    rewrite ^(.*) http://domain.com$1 permanent;
}

server {
    server_name  domain.com;
    #The rest of your configuration goes here#
}

Отже, вам потрібно мати ДВІ коди сервера.

Додайте www до URL-адреси за допомогою переадресації nginx

Якщо вам потрібно навпаки, для перенаправлення з домену.com на www.domain.com, ви можете скористатися цим:

server {
    server_name  domain.com;
    rewrite ^(.*) http://www.domain.com$1 permanent;
}

server {
    server_name  www.domain.com;
    #The rest of your configuration goes here#
}

Як ви можете собі уявити, це якраз навпаки і працює так само, як перший приклад. Таким чином, ви не отримуєте відмітки SEO, оскільки це повне переадресація та переміщення перм. Не WWW змушений і каталог показаний!

Деякі з мого коду показано нижче для кращого перегляду:

server {
    server_name  www.google.com;
    rewrite ^(.*) http://google.com$1 permanent;
}
server {
       listen 80;
       server_name google.com;
       index index.php index.html;
       ####
       # now pull the site from one directory #
       root /var/www/www.google.com/web;
       # done #
       location = /favicon.ico {
                log_not_found off;
                access_log off;
       }
}

3
@puk цінуй це. Nginx - це дивовижна, але хороша документація, яка завжди в курсі версії сервера та зміни ОС та сервера, є досить стомлюючою. Найкращий ресурс, який обслуговує мене, - howtoforge.com, оскільки він підтримує хмарні версії RackSpace. Деякі команди, наведені вище, не працюватимуть у пізніших версіях. Але цей nginx / 0.8.54 - повірте, найкращий сервер nginx) не потребує оновлення чи оновлення. Добре працює. 100 000 унікальних звернень на день із 4200 транзакціями в середньому на день. Nginx - RAPID. як-от використання веб-сайту без трафіку.
TheBlackBenzKid

17
Ваші переписування повинні стати поверненнями, як і в return 301 $scheme://domain.com$request_uri;. Немає необхідності робити знімки, дивіться підводні камені Nginx
Роберто

4
@TheBlackBenzKid Вибачте, можливо, я щось пропустив, але оновлене рішення не працює. Це тому, що слухайте 80 - з цим ви говорите, що лише HTTP відповідає цьому. Для прослуховування, якщо однакова конфігурація використовується для HTTP та HTTPS, повинно бути більше портів. Або? Але остаточно мені допомогли, +1. Дякуємо за відповідь Ура.
tomis

3
@TheBlackBenzKid Це було просто зауваження. Я знайшов робоче рішення. У вашому прикладі слід додати лише Слухати 443 і завершити роботу.
tomis

2
відповідь неправильна. він перенаправляє всі субдомени на www.
r3wt

398

Насправді вам навіть не потрібно переписувати.

server {
    #listen 80 is default
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    #listen 80 is default
    server_name example.com;
    ## here goes the rest of your conf...
}

Оскільки моя відповідь набирає все більше голосів, але вище. У rewriteцьому контексті ніколи не слід використовувати . Чому? Тому що nginx має обробити та розпочати пошук. Якщо ви використовуєте return(який повинен бути доступний у будь-якій версії nginx), це безпосередньо зупиняє виконання. Це бажано в будь-якому контексті.

Перенаправляйте обидва, не-SSL та SSL, на їх не-www колегу:

server {
    listen               80;
    listen               443 ssl;
    server_name          www.example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    return 301 $scheme://example.com$request_uri;
}

server {
    listen               80;
    listen               443 ssl;
    server_name          example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    # rest goes here...
}

$schemeМінлива міститиме тільки httpякщо ваш сервер слухає тільки порт 80 ( по замовчуванню) і слухати варіант не містить sslключове слово. Якщо не використовувати змінну, ви не отримаєте жодної продуктивності.

Зверніть увагу, що вам потрібно ще більше серверів блоків, якщо ви використовуєте HSTS, оскільки заголовки HSTS не повинні надсилатися через незашифровані з'єднання. Отже, вам потрібні незашифровані серверні блоки з переадресаціями та зашифровані серверні блоки з переспрямуванням та заголовками HSTS.

Перенаправляйте все на SSL (персональний конфігурація в UNIX з IPv4, IPv6, SPDY, ...):

#
# Redirect all www to non-www
#
server {
    server_name          www.example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:80;
    listen               *:443 ssl spdy;
    listen               [::]:80 ipv6only=on;
    listen               [::]:443 ssl spdy ipv6only=on;

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

#
# Redirect all non-encrypted to encrypted
#
server {
    server_name          example.com;
    listen               *:80;
    listen               [::]:80;

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

#
# There we go!
#
server {
    server_name          example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:443 ssl spdy;
    listen               [::]:443 ssl spdy;

    # rest goes here...
}

Напевно, ви можете собі уявити інші сполуки з цим малюнком.

Більше моїх конфігурацій? Іди сюди і сюди .


3
Ваш Chrome не повинен мати можливість переходити до вашого домену www, якщо ви використовуєте HSTS. Будь ласка, відкрийте нове запитання з якомога більше деталей, і я допоможу вам (ви можете опублікувати URL-адресу питання як коментар тут).
Fleshgrinder

1
@Fleshgrinder Я намагаюся реалізувати вашу настройку, але отримую наступну проблему на stackoverflow.com/questions/29451409/… Будь-які ідеї, як змусити її працювати?
YPCrumble

4
У другому блоці "Перенаправити обидва, не-SSL та SSL на їх не-www колегу:", обидва серверні блоки повинні мати директиви SSL, оскільки браузер повинен перевірити сертифікат на www.example.com, перш ніж він перенаправляє на приклад .com
Джефф Цай

1
Звичайно, я додав це, а також коротку інформацію про HSTS.
Fleshgrinder

1
@YPCrumble так, це набагато швидше, тому що ми не виконуємо регулярне узгодження виразів у кожному запиті. Ми переспрямовуємо лише тоді, коли знаємо, що мусимо перенаправлятись. Ні перевірок, ні перевірки, нічого: просто переадресація. =)
Fleshgrinder

37

Ви можете дізнатися, що хочете використовувати той самий конфігурацію для більшості доменів.

Наступний фрагмент видаляє www перед будь-яким доменом:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}

7
Мені це подобається краще, ніж виділені серверні блоки. Зміна httpдо$scheme
ck_

2
Набагато краще, я не можу повірити, що багато хто з них буде жорстко кодувати домени для налаштування цього завдання.
MrYellow

1
@Oli Це посилання не (на сьогоднішній день) не згадує продуктивність, а швидше, що вони не на 100% безпечні. Він говорить "Єдині 100% безпечні речі, які можна зробити всередині, якщо в контексті розташування є: return ...і rewrite ... last". Будь-які оновлені посилання на проблеми з продуктивністю?
Адам

1
Це не спрацювало для мене. Не вдалося отримати помилку в браузері, сказавши недійсну відповідь.
Ніко Бреннер

1
На жаль, я не знайшов способу без "якщо". Я використовую однаковий конфігурацію для багатьох доменів, жорстке кодування доменних імен - це не варіант. Будь-яка пропозиція / коментар цінується!
Мартін Хьогер

27

Вам потрібні два серверні блоки.

Помістіть їх у свій конфігураційний файл, наприклад /etc/nginx/sites-available/sitename

Скажімо, ви вирішили створити http://example.com як основну адресу для використання.

Ваш конфігураційний файл повинен виглядати так:

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

        # this is the main server block
        # insert ALL other config or settings in this server block
}

Перший блок сервера буде містити вказівки щодо переадресації будь-яких запитів із префіксом 'www'. Він слухає запити на URL з префіксом "www" та переспрямуванням.

Він більше нічого не робить.

Другий серверний блок буде містити вашу головну адресу - URL-адресу, яку ви хочете використовувати. Всі інші настройки йдуть сюди , як root, index,location і т.д. Перевірте файл за умовчанням для цих інших параметрів , які можна включити в блоці сервера.

Серверу потрібні два записи DNS A.

Name: @ IPAddress: your-ip-address (for the example.com URL)

Name: www IPAddress: your-ip-address (for the www.example.com URL)

Для ipv6 створіть пару записів AAAA, використовуючи вашу-ipv6-адресу.


23

Ось як це зробити для кількох імен серверів www до no-www (я використовував це для субдоменів):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}

20
  1. Найкраща практика: окремі serverж / жорсткі кодиserver_name

Найкраща практика для nginx - використовувати окремий serverдля перенаправлення на зразок цього (не поділяється зserver вашою основною конфігурацією), для жорсткого кодування всього і взагалі не використовувати регулярні вирази.

Можливо, також знадобиться жорсткий код доменів, якщо ви використовуєте HTTPS, оскільки ви повинні знати заздалегідь, які сертифікати ви надаєте.

server {
    server_name www.example.com;
    return  301 $scheme://example.com$request_uri;
}
server {
    server_name www.example.org;
    return  301 $scheme://example.org$request_uri;
}
server {
    server_name example.com example.org;
    # real configuration goes here
}

  1. Використання регулярних виразів всередині server_name

Якщо у вас є кілька сайтів, і ви не дбаєте про найвищу ефективність, але хочете, щоб кожен з них мав однакову політику щодо www.префікса, тоді ви можете використовувати регулярні вирази. Найкраща практика використання окремих serverвсе ще залишатиметься.

Зауважте, що це рішення стає складним, якщо ви використовуєте https, оскільки тоді ви повинні мати єдиний сертифікат для покриття всіх доменних імен, якщо ви хочете, щоб це працювало належним чином.


не wwwдля wwww / regex у спеціальному синглі serverдля всіх сайтів:

server {
    server_name ~^(?!www\.)(?<domain>.+)$;
    return  301 $scheme://www.$domain$request_uri;
}

wwwдо non- wwww / regex у спеціальному синглі serverдля всіх сайтів:

server {
    server_name ~^www\.(?<domain>.+)$;
    return  301 $scheme://$domain$request_uri;
}

wwwдо non- wwww / regex у виділеномуserver для деяких сайтів:

Може знадобитися обмежити регулярний вираз лише кількома доменами, тоді ви можете використовувати щось подібне лише для відповідності www.example.org, www.example.comі www.subdomain.example.net:

server {
    server_name ~^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$;
    return  301 $scheme://$domain$request_uri;
}

Тестування регулярних виразів w / nginx

Ви можете перевірити, що регулярний вираз працює pcretestу вашій системі так, як очікувалося. Це точно така ж pcreбібліотека, яку буде використовувати ваш nginx для регулярних виразів:

% pcretest 
PCRE version 8.35 2014-04-04

  re> #^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$#
data> test
No match
data> www.example.org
 0: www.example.org
 1: example.org
data> www.test.example.org
No match
data> www.example.com
 0: www.example.com
 1: example.com
data> www.subdomain.example.net
 0: www.subdomain.example.net
 1: subdomain.example.net
data> subdomain.example.net
No match
data> www.subdomain.example.net.
No match
data> 

Зауважте, що вам не потрібно хвилюватися з приводу крапок або регістру, оскільки nginx вже піклується про це, відповідно до регексу імені сервера nginx, коли в заголовку "Host" є кінцева крапка .


  1. Посипати ifвсередині існуючих server/ HTTPS:

Це остаточне рішення, як правило, не вважається найкращою практикою, однак воно все одно працює і виконує свою роботу.

Насправді, якщо ви використовуєте HTTPS, то це остаточне рішення може бути простішим у обслуговуванні, оскільки вам не доведеться копіювати та вставляти цілу купу директив ssl між різними serverвизначеннями, а замість цього можна розміщувати фрагменти лише у потрібні сервери, що полегшує налагодження та обслуговування ваших сайтів.


не wwwдля www:

if ($host ~ ^(?!www\.)(?<domain>.+)$) {
    return  301 $scheme://www.$domain$request_uri;
}

wwwдля не www:

if ($host ~ ^www\.(?<domain>.+)$) {
    return  301 $scheme://$domain$request_uri;
}

жорстке кодування одного кращого домену

Якщо ви хочете трохи збільшити продуктивність, а також узгодженість між декількома доменами, які serverможе використовуватись один, можливо, все одно має сенс чітко ввести жорсткий код одного бажаного домену:

if ($host != "example.com") {
    return  301 $scheme://example.com$request_uri;
}

Список літератури:


16

Це рішення випливає з мого особистого досвіду. Ми використовували кілька відро Amazon S3 та один сервер для перенаправлення non-wwwдо wwwдоменних імен, щоб відповідати політиці заголовків S3 "Хост" .

Я використовував таку конфігурацію для сервера nginx :

server {
    listen 80;
    server_name ~^(?!www\.)(?<domain>.+)$;
    return 301 $scheme://www.$domain$request_uri;
}

Це відповідає всім доменним іменам, які вказували на сервер, починаючи з будь-якого, але www.перенаправлення до нього www.<domain>. Таким же чином ви можете зробити зворотну переадресацію з wwwна non-www.


як щодо https? примітка: https НЕОБХІДНО в сертифікаті
Toskan

Тут з HTTPS абсолютно немає проблем. Після listen 80вам потрібно додати listen 443 sslі потім, ssl_certificateіssl_certificate_key директиви.
VisioN

нині ніхто не використовує http. Я читав керівництво в Google, перераховане вгорі, яке показало ваш приклад лише з доданим рядком listen 443 ssl із відсутнім сертифікатом. Це бажання працює і викликає серйозні головні болі.
Тоскан

Я не знаю, про який путівник ви говорите. У мене ця конфігурація успішно працює майже три роки. Минулого року я додав підтримку SSL, і вона працює як очікувалося. І звичайно вам потрібно мати сертифікат із приватним ключем у руці.
VisioN

тож це дозволить заглушити всі субдомени, крім www, правильно?
Метаграф

15

Я поєднав найкращі з простих відповідей, без жорстко зашифрованих доменів.

301 постійне переадресація з не-www на www (HTTP або HTTPS):

server {
    if ($host !~ ^www\.) {
        rewrite ^ $scheme://www.$host$request_uri permanent;
    }

    # Regular location configs...
}

Якщо ви віддаєте перевагу не HTTPS, не www для HTTPS, www одночасно переспрямовуйте:

server {
    listen 80;

    if ($host !~ ^www\.) {
        rewrite ^ https://www.$host$request_uri permanent;
    }

    rewrite ^ https://$host$request_uri permanent;
}

11

Перенаправити не на www на www

Для одного домену:

server {
        server_name example.com;
        return 301 $scheme://www.example.com$request_uri;
}

Для всіх доменів:

server {
        server_name "~^(?!www\.).*" ;
        return 301 $scheme://www.$host$request_uri;
}

Перенаправлення www на не www для одного домену:

server {
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}

Для всіх доменів:

server {
         server_name "~^www\.(.*)$" ;
         return 301 $scheme://$1$request_uri ;
}

Чи можете ви надати диференціацію між 80та 443?
Хассан Байг

1
Здається, listenдля мене працює без директив (nginx 1.4.6).
Ібрагім

11

спробуйте це

    if ($host !~* ^www\.){
        rewrite ^(.*)$ https://www.yoursite.com$1;
    }

Інший спосіб: від Nginx no-www до www

server {
  listen       80;
  server_name  yoursite.com;
  root /path/;
  index index.php;
  return       301 https://www.yoursite.com$request_uri;
}

і www до no-www

server {
  listen       80;
  server_name  www.yoursite.com;
  root /path/;
  index index.php;
  return       301 https://yoursite.com$request_uri;
}

Чому автори надали if-заяву в nginx, а потім сказали людям уникати цього? Мені звучить легковажно.
Грег Сметеллс

4
Там зазначено "ЯКЩО в розташуванні це зло". Ви можете сміливо помістити, якщо у свій серверний блок
Кукунін

Пряма цитата з вищенаведеного посилання ... Єдині 100% безпечні речі, які можна зробити всередині, якщо в контексті розташування є: return ...; переписати ... останнє;
Джастін Е

8

Унікальний формат:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}

1
Ви можете зробити це загальним, записавши це так: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Рамаст

5
location / { 
    if ($http_host !~ "^www.domain.com"){ 
        rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
    } 
}

1
$scheme://www.domain.com$1щоб уникнути подвійної косої риси
karimhossenbux

3

не впевнений, чи хтось помітить, що може бути правильним повернути 301, але браузери задушилися

rewrite ^(.*)$ https://yoursite.com$1; 

швидше, ніж:

return 301 $scheme://yoursite.com$request_uri;


1
мій коментар був спрямований на браузер не для ефективності з боку nginx! при переадресації браузер робить 2 запити проти 1 запиту при перезавантаженні
Стівен

2

Блог привидів

для того, щоб зробити рекомендований метод nginx для return 301 $scheme://example.com$request_uri;роботи з Ghost, вам потрібно буде додати ваш основний блок сервера:

proxy_set_header    X-Real-IP           $remote_addr;
proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
proxy_set_header    Host                $http_host;
proxy_set_header    X-Forwarded-Proto   $scheme;
proxy_set_header    X-NginX-Proxy       true;

proxy_pass_header   X-CSRF-TOKEN;
proxy_buffering     off;
proxy_redirect      off;  

2

Якщо ви не хочете жорстко кодувати доменне ім’я, ви можете використовувати цей блок переадресації. Домен без провідного www зберігається як змінна, $domainяку можна повторно використати в операторі переспрямування.

server {
    ...
    # Redirect www to non-www
    if ( $host ~ ^www\.(?<domain>.+) ) {
       rewrite ^/(.*)$ $scheme://$domain/$1;
    }
}

REF: перенаправлення субдомену з регулярним виразом у nginx



-6

Якщо у вас виникли проблеми з роботою, можливо, вам доведеться додати IP-адресу вашого сервера. Наприклад:

server {
listen XXX.XXX.XXX.XXX:80;
listen XXX.XXX.XXX.XXX:443 ssl;
ssl_certificate /var/www/example.com/web/ssl/example.com.crt;
ssl_certificate_key /var/www/example.com/web/ssl/example.com.key;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}

де XXX.XXX.XXX.XXX - IP-адреса (очевидно).

Примітка: для належного перенаправлення https-запитів повинні бути визначені ssl crt та розташування ключів

Не забудьте перезапустити nginx після внесення змін:

service nginx restart

3
/etc/init.d/nginx reloadВи також можете reloadсервер, що не спричиняє простоїв.
TheBlackBenzKid
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.