Nginx без 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.

TheBlackBenzKid
источник
1
Я чувствую себя обязанным прокомментировать, что если вы работаете с сайтом WordPress, проверьте Dashboard > Settings > General Settingsи убедитесь, что wwwв URL-адресах WordPress Address / Site Address их нет. Независимо от того, как вы сконфигурируете свой nginx, если у вас есть www в этих URL, он будет перенаправлен на тот, в котором есть www.
Абхинав Суд

Ответы:

793

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://в свое решение, поскольку мы используем loadbalancers, а наш https: // сервер является сервером платежей SSL с высоким трафиком: мы не смешиваем https: // и http: //.


Чтобы проверить версию nginx, используйте nginx -v.

Уберите www с URL с помощью nginx redirect

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

Если вам нужно обратное, для перенаправления с domain.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;
       }
}
TheBlackBenzKid
источник
3
@puk ценю это. Nginx удивителен, но хорошая документация, которая обновляется с учетом версии сервера, изменений ОС и серверного оборудования, довольно утомительна. Лучший ресурс, который мне подходит, это howtoforge.com, поскольку он поддерживает облачные версии RackSpace. Некоторые из приведенных выше команд не будут работать в более поздних версиях. Но этот nginx / 0.8.54 - это, поверьте, лучший сервер nginx) не нужно обновлять или обновлять. Работает отлично. 100 000 уникальных хитов в день, в среднем 4200 транзакций в день. Nginx БЫСТРО. как использовать сайт без трафика.
TheBlackBenzKid
17
Ваши переписывания должны стать возвратами, как в return 301 $scheme://domain.com$request_uri;. Нет необходимости фиксировать какие-либо закономерности, см. Подводные камни Nginx
Роберто
4
@TheBlackBenzKid Извините, может быть, я что-то пропустил, но обновленное решение не работает. Это потому, что слушайте 80 - с этим вы говорите, что только HTTP соответствует этому. Должно быть больше портов для прослушивания, если для HTTP и HTTPS используется одинаковая конфигурация ... Или? Но мне определенно помогли +1. Спасибо за ответ. Приветствия.
Томис
3
@TheBlackBenzKid Это было просто примечание. Я нашел рабочее решение. В вашем примере, только Listen 443 должен быть добавлен и завершить работу.
Томис
2
ответ неверный. он перенаправляет все субдомены на www.
r3wt
399

На самом деле вам даже не нужно переписывать.

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...
}

Я полагаю, что теперь вы можете представить себе другие соединения с этим паттерном самостоятельно.

Больше моих конфигов? Иди сюда и сюда .

Fleshgrinder
источник
3
Ваш Chrome не сможет перейти на ваш домен www, если вы используете HSTS. Пожалуйста, откройте новый вопрос с максимально возможным количеством деталей, и я вам помогу (вы можете опубликовать URL-адрес вопроса в качестве комментария здесь).
Флешгриндер
1
@Fleshgrinder Я пытаюсь реализовать ваши настройки, но получаю следующую проблему на stackoverflow.com/questions/29451409/… Есть идеи о том, как заставить это работать?
YPCrumble
4
Во 2-м блоке «Перенаправить оба, не-SSL и SSL, к их аналогам, отличным от www:», оба блока сервера должны иметь директивы SSL, так как браузер должен проверить сертификат для www.example.com, прежде чем перенаправить к примеру. .com.
Джефф Цай
1
Конечно, я добавил это, а также краткую информацию о HSTS.
Fleshgrinder
1
@YPCrumble: да, так намного быстрее, потому что мы не выполняем сопоставление регулярных выражений для каждого запроса. Мы только перенаправляем, если знаем, что мы должны перенаправить. Нет проверок, нет проверки, ничего: просто перенаправить. =)
Флешгриндер
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-записи.

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, так как у вас должен быть один сертификат для всех ваших доменных имен, если вы хотите, чтобы это работало правильно.


non- wwwto www/ 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чтобы не www/ 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;
}

Тестирование регулярных выражений с 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;
}

Ссылки:

CNST
источник
16

Это решение исходит из моего личного опыта. Мы использовали несколько корзин Amazon S3 и один сервер для перенаправления non-wwwна wwwдоменные имена в соответствии с политикой заголовка S3 «Host» .

Я использовал следующую конфигурацию для сервера 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_certificatessl_certificate_key
VisioN
никто не использует http в настоящее время. Я читал руководство в Google, которое показало ваш пример только с добавленной строкой listen 443 ssl с отсутствующим сертификатом. Это привычка работать и вызывает некоторую серьезную головную боль.
Toskan
Я не знаю, о каком руководстве ты говоришь. У меня эта конфигурация успешно работает почти три года. В прошлом году я добавил поддержку 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 без 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 ;
}
Andriyun
источник
1
Вы можете сделать это универсальным, написав это так: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Ramast
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.com/resources/wiki/start/topics/tutorials/config_pitfalls/…
Рикардо
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;  
stevek
источник
2

Если вы не хотите жестко задавать доменное имя, вы можете использовать этот блок перенаправления. Домен без ведущего www сохраняется как переменная, $domainкоторую можно использовать в операторе redirect.

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

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

Дрейки
источник
0
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}
Дядя Кара
источник
-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-адрес (очевидно).

Примечание: ssl crt и местоположение ключа должны быть определены для правильного перенаправления запросов https

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

service nginx restart
undoIT
источник
3
/etc/init.d/nginx reloadВы также можете reloadсервер, который не вызывает простоев.
TheBlackBenzKid