Перенаправление с www на основной домен в Nginx
Пошаговая настройка постоянного перенаправления с www-поддомена на основной домен в Nginx с сохранением URI и параметров запроса.
Один сайт может быть доступен сразу по двум адресам:
https://example.com
https://www.example.com
Чтобы пользователи и поисковые системы всегда использовали один основной адрес, настраивают постоянное перенаправление с дополнительного имени на canonical domain.
В этой инструкции рассматривается только перенаправление:
www.example.com → example.com
с сохранением пути и параметров запроса.
Проверено на: Ubuntu Server 24.04 LTS
Уровень сложности: начальный
Время выполнения: около 10–15 минут
Требуемый доступ: пользователь с правамиsudo
Что будет настроено
После выполнения инструкции:
- будет выбран основной домен;
- будет проверена DNS-запись
www; - будет проверен TLS-сертификат;
- будет создан отдельный redirect server block;
- путь и query string будут сохраняться;
- будет проверен код
301; - будут разобраны циклические перенаправления;
- будет показан безопасный откат.
Исходная схема
Основной адрес:
https://example.com
Дополнительный адрес:
https://www.example.com
Ожидаемое поведение:
https://www.example.com/catalog/item?id=10
перенаправляется на:
https://example.com/catalog/item?id=10
Почему нужен один основной домен
Единый canonical domain помогает:
- исключить дублирование адресов;
- упростить cookies и сессии;
- избежать разных абсолютных ссылок;
- упростить аналитику;
- централизовать HTTPS;
- сделать поведение сайта предсказуемым.
Выбор основного имени
До настройки определите основной адрес.
В этой статье используется:
example.com
Вариант с основным www.example.com также возможен, но направление redirect будет обратным.
Не настраивайте оба направления одновременно.
Проверка DNS основного домена
dig +short example.com
Ожидается IP Nginx-сервера.
Проверьте:
getent hosts example.com
Проверка DNS для www
dig +short www.example.com
Допустимые варианты:
A-запись на SERVER_IP
или:
CNAME на example.com
Оба имени должны приводить клиента на сервер, который выполняет redirect.
Пример A-записей
example.com A SERVER_IP
www.example.com A SERVER_IP
Пример CNAME
www.example.com CNAME example.com
Для корневого домена CNAME обычно не используется в классическом DNS.
Проверка HTTP-доступа
curl -I http://example.com
curl -I http://www.example.com
Оба имени должны достигать Nginx.
Проверка HTTPS
curl -I https://example.com
curl -I https://www.example.com
Если сертификат не включает www.example.com, браузер получит TLS-ошибку ещё до обработки HTTP redirect.
Почему сертификат должен включать www
При HTTPS сначала выполняется TLS handshake, и только потом Nginx возвращает 301.
Поэтому сертификат должен быть действителен для:
www.example.com
даже если этот адрес сразу перенаправляется.
Проверка SAN сертификата
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null |
openssl x509 -noout -ext subjectAltName
В списке должен быть:
DNS:www.example.com
Проверка Certbot
sudo certbot certificates
Убедитесь, что сертификат включает:
example.com
www.example.com
Добавление www в сертификат
Если сертификат выпущен только для основного домена:
sudo certbot --nginx --cert-name example.com -d example.com -d www.example.com --expand
Перед выполнением DNS-запись www должна указывать на этот сервер.
Создание резервной копии
sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.before-www-redirect
Проверьте:
ls -l /etc/nginx/sites-available/example.com*
Правильная структура конфигурации
Для основного домена и redirect лучше использовать отдельные server block:
server block 1 — основной сайт
server block 2 — перенаправление www
Это проще и надёжнее, чем смешивать оба поведения в одном блоке.
Основной HTTPS server block
Пример:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
HTTPS redirect с www
Добавьте отдельный блок:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
Как работает request_uri
Переменная:
$request_uri
содержит исходный путь и query string.
Пример:
/products/item?id=10
Поэтому:
return 301 https://example.com$request_uri;
сохраняет:
- путь;
- имя файла;
- параметры запроса;
- URL-encoding.
HTTP redirect для обоих имён
Отдельный блок для порта 80:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
В результате:
http://example.com/path
и:
http://www.example.com/path
перенаправляются на:
https://example.com/path
Полная конфигурация
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Redirect для reverse proxy
Основной блок может проксировать приложение:
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Redirect-блок остаётся таким же:
server {
listen 443 ssl;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
Почему лучше использовать return
Для простого перенаправления предпочтительнее:
return 301 ...
Вместо:
rewrite ...
return:
- проще;
- понятнее;
- быстрее;
- снижает риск ошибки регулярного выражения;
- точно подходит для смены hostname.
Код 301
301 Moved Permanently
означает постоянное перенаправление.
Браузеры и поисковые системы могут кэшировать такой redirect.
До окончательной проверки можно временно использовать:
return 302 https://example.com$request_uri;
После успешного теста заменить 302 на 301.
Разница между 301 и 302
301
Постоянное перенаправление.
Используется для окончательно выбранного canonical domain.
302
Временное перенаправление.
Удобно для тестирования и временных изменений.
Проверка конфигурации
sudo nginx -t
Ожидаемый результат:
syntax is ok
test is successful
Применение
sudo systemctl reload nginx
Проверьте:
systemctl status nginx --no-pager
Проверка www по HTTPS
curl -I https://www.example.com
Ожидается:
HTTP/2 301
Location: https://example.com/
Проверка пути
curl -I https://www.example.com/catalog/item
Ожидается:
Location: https://example.com/catalog/item
Проверка query string
curl -I 'https://www.example.com/search?q=nginx&page=2'
Ожидается:
Location: https://example.com/search?q=nginx&page=2
Проверка всей цепочки
curl -IL 'http://www.example.com/search?q=nginx'
Ожидаемая цепочка:
http://www.example.com
→ https://example.com
→ 200 OK
Желательно избегать лишней цепочки:
http://www
→ https://www
→ https://example.com
Лучше сразу перенаправлять HTTP на финальный canonical URL.
Проверка без DNS-кэша
curl -I --resolve www.example.com:443:SERVER_IP https://www.example.com/test
Для HTTPS имя в URL и SNI остаётся www.example.com, а соединение направляется на указанный IP.
Проверка основного домена
curl -I https://example.com
Основной домен не должен перенаправляться обратно на www.
Проверка активных server block
sudo nginx -T |
grep -nE 'server_name|return 301|listen 443'
Для конкретного домена:
sudo nginx -T |
grep -n -A15 -B5 'server_name www.example.com'
Проверка журнала доступа
Если redirect использует общий журнал:
sudo tail -50 /var/log/nginx/access.log
Можно добавить отдельный журнал:
access_log /var/log/nginx/www.example.com.redirect.log;
Отдельный журнал redirect
Пример:
server {
listen 443 ssl;
server_name www.example.com;
access_log /var/log/nginx/www.example.com.redirect.log;
return 301 https://example.com$request_uri;
}
Проверка:
sudo tail -f /var/log/nginx/www.example.com.redirect.log
Циклическое перенаправление
Цикл возникает, если:
www → без www
и одновременно:
без www → www
Проверьте все конфигурации:
sudo grep -RniE 'return 30[128]|rewrite' /etc/nginx/
Пример ошибочного цикла
В одном блоке:
return 301 https://example.com$request_uri;
В другом:
return 301 https://www.example.com$request_uri;
Оставьте только одно направление.
Redirect на неправильную схему
Ошибочный вариант:
return 301 http://example.com$request_uri;
Для production-сайта с TLS используйте:
return 301 https://example.com$request_uri;
Потеря query string
Плохой вариант:
return 301 https://example.com;
Он отправит все запросы только на главную страницу.
Правильный вариант:
return 301 https://example.com$request_uri;
Использование uri вместо request_uri
Переменная:
$uri
может быть нормализована и не содержит исходный query string.
Для полного сохранения запроса используйте:
$request_uri
Порт в redirect
Не добавляйте:
:443
без необходимости.
Достаточно:
https://example.com$request_uri
Порт 443 подразумевается автоматически.
Redirect для нестандартного HTTPS-порта
Если сайт действительно работает на нестандартном порту:
return 301 https://example.com:8443$request_uri;
Для обычного публичного сайта это не требуется.
Несколько дополнительных имён
Можно перенаправлять несколько alias:
server_name www.example.com old.example.com legacy.example.com;
return 301 https://example.com$request_uri;
Все имена должны:
- указывать на Nginx;
- иметь действующий сертификат;
- действительно принадлежать владельцу сайта.
Отдельные сертификаты
Redirect может использовать отдельный сертификат:
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
Но обычно удобнее один SAN-сертификат для:
example.com
www.example.com
HSTS
Если на основном домене настроен HSTS:
add_header Strict-Transport-Security "max-age=31536000" always;
не забывайте, что includeSubDomains распространяет HTTPS-политику и на www.
Поскольку www обслуживается по HTTPS, это нормальная схема.
Cookies
После перехода на основной домен приложение должно создавать cookies для правильного hostname.
Проверьте:
Domain;Secure;SameSite;- session callback URL;
- allowed origins.
Nginx redirect не исправляет настройки cookies приложения автоматически.
OAuth и callback URL
Если приложение использует OAuth или SSO, обновите callback URL:
https://example.com/callback
Старый адрес с www может оставаться зарегистрированным у внешнего провайдера и вызывать ошибки.
CORS
Проверьте allowed origins приложения.
После выбора canonical domain разрешённым origin должен быть:
https://example.com
Redirect не заменяет корректную CORS-конфигурацию.
Sitemap и canonical
В HTML желательно использовать:
<link rel="canonical" href="https://example.com/page">
Также обновите:
- sitemap;
- robots.txt;
- абсолютные ссылки;
- Open Graph URL;
- RSS;
- API documentation.
Это уже уровень приложения, а не Nginx.
Ошибка сертификата на www
Проверьте SAN:
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null |
openssl x509 -noout -ext subjectAltName
Если www отсутствует, перевыпустите сертификат.
Redirect не срабатывает
Проверьте:
- DNS;
- active server block;
server_name;- символическую ссылку в
sites-enabled; - выполнен ли reload;
- не перехватывает ли запрос другой default server.
Команда:
sudo nginx -T |
grep -n 'www.example.com'
Открывается другой сайт
Проверьте:
curl -vkI https://www.example.com
Проверьте SNI, сертификат и server_name.
Убедитесь, что www.example.com не указан в другом server block.
Возвращается 200 вместо 301
Вероятно, www.example.com включён в основной server block:
server_name example.com www.example.com;
Уберите www из блока, который обслуживает контент, и создайте отдельный redirect block.
Возвращается 404
Проверьте, что запрос попал в правильный server block.
Redirect block не должен содержать root или proxy_pass.
Слишком длинная цепочка redirect
Проверьте:
curl -IL http://www.example.com
Оптимально получить один redirect сразу на финальный URL.
Кэшированный 301 в браузере
Браузер может помнить старый redirect.
Для диагностики используйте:
curl -I
или приватное окно браузера.
Во время настройки используйте 302.
Проверка через разные протоколы
curl -I http://example.com
curl -I http://www.example.com
curl -I https://example.com
curl -I https://www.example.com
Ожидаемо:
HTTP example.com → HTTPS example.com
HTTP www.example.com → HTTPS example.com
HTTPS example.com → 200
HTTPS www.example.com → HTTPS example.com
Откат конфигурации
Восстановите резервную копию:
sudo cp /etc/nginx/sites-available/example.com.before-www-redirect /etc/nginx/sites-available/example.com
Проверьте:
sudo nginx -t
Примените:
sudo systemctl reload nginx
Удаление redirect block
Удалите только блок:
server_name www.example.com;
с директивой:
return 301 ...
Не удаляйте основной server block.
Безопасный порядок настройки
- Выбрать canonical domain.
- Проверить DNS обоих имён.
- Проверить сертификат для обоих имён.
- Создать резервную копию.
- Временно настроить
302. - Выполнить
nginx -t. - Выполнить reload.
- Проверить путь и query string.
- Проверить отсутствие цикла.
- Заменить
302на301. - Повторно проверить.
- Обновить настройки приложения.
Быстрый пример
HTTP:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
HTTPS для www:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
Быстрая проверка
sudo nginx -t &&
sudo systemctl reload nginx
curl -IL 'http://www.example.com/test?id=10'
Итог
После выполнения инструкции:
- выбран основной домен;
- проверены DNS-записи;
- проверен TLS-сертификат для
www; - создан отдельный redirect server block;
- сохранены URI и query string;
- настроен постоянный код
301; - исключена лишняя цепочка перенаправлений;
- разобраны циклы и типичные ошибки.
У сайта должен быть один основной публичный адрес, а дополнительные имена должны перенаправляться непосредственно на него.