Как развернуть и настроить статический сайт на Nginx в Ubuntu
Опубликовано:
В этом руководстве мы исходим из того, что вы уже авторизовались на VPS, обновили ОС, в случае использования UFW выполнили его первоначальную настройку. Если вы создавали пользователя, а не работаете под администратором системы, то перед большинством приводимых ниже команд надо писать sudo.
Установка Nginx, добавление профиля в UFW
Устанавливаем Nginx:
# apt install nginx
Проверяем наличие профилей Nginx в UFW:
# ufw app list Available applications: Nginx Full Nginx HTTP Nginx HTTPS Nginx QUIC OpenSSH
Включаем Nginx Full:
# ufw allow 'Nginx Full'
Проверяем, что входящий трафик для протокола SSH и веб-сервера Nginx позволен:
# ufw status Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)
Проверяем, что Nginx запущен:
# systemctl status nginx
Если в выводе среди прочего вы видите active (running), значит это так. Чтобы выйти из вывода статуса службы, нажмите q.
При этом дефолтный сайт уже будет доступен по IP.
Создание каталога сайта и загрузка файлов на сервер
Как и в случае с Apache файлы этого сайта находятся в каталоге /var/www/html/:
# ls /var/www/html/ index.nginx-debian.html
Для файлов своего сайта лучше создать отдельный каталог:
# mkdir /var/www/mysite
Загружаем сюда файлы с вашего локального компьютера, например с помощью утилиты rsync:
ivan@home:~$ rsync -avz site/ root@159.194.228.243:/var/www/mysite/
Также можно создать архив (об утилите tar), загрузить его с помощью scp, на сервере распаковать. Кроме этого, у Бегета для VPS доступен браузерный файловый менеджер:
Создание для сайта конфигурационного файла Nginx
В каталоге /etc/nginx/sites-available/ создаем конфигурационный файл для нашего сайта, который будет запускаться на Nginx. Сделать это можно с помощью vim:
# vim /etc/nginx/sites-available/mysite.conf
Пример начальных инструкций в файле, когда сертификат безопасности еще не выпущен:
server { listen 80; server_name mysite.name www.mysite.name; root /var/www/mysite; index index.html; location / { try_files $uri $uri/ =404; } }
Теперь надо создать ссылку в каталог sites-enabled:
# ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/
Проверяем правильность конфигурации:
# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Перезапускаем веб-сервер:
# systemctl restart nginx
Привязка домена к серверу: настройка DNS-записей
Теперь для домена надо прописаны IP данного VPS. Если домен находится под управлением другого регистратора, а не там, где вы заказывали VPS, то у первого в настройках домена должны быть прописаны DNS-сервера второго. В панели хостера вы также создаете этот домен, и в его A-записях указываете IP. Сделать это надо и для домена без www, и с ним.
После этого через небольшое время сайт должен открываться по имени домена, однако только по протоколу HTTP. Вам надо кликнуть в адресную строку браузера и исправить там https на http.
Запрет прямого доступа к серверу по IP-адресу в Nginx
Сейчас у вас на веб-сервере имеется два сайта: один доступен по IP, другой — по имени домена. По IP лучше устанавливать запрет доступа (403, Forbidden), чем настраивать редирект на домен или оставлять как есть. Поэтому следует открыть файл конфигурации дефолтного сайта (/etc/nginx/site-available/default) и оставить там только такие инструкции:
server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 403; }
Далее также проверяем безошибочность конфигурации и перезапускаем веб-сервер:
# sudo nginx -t # systemctl reload nginx
При обращении по https к IP-адресу в Nginx часто используют сброс соединения без ответа (ошибка 444, "Страница недоступна", или "Не удалось получить доступ к сайту / ERR_CONNECTION_CLOSED"). Для этого в дефолтный файл конфигурации добавляют:
# Ловушка для HTTPS (порт 443) — сбросит соединение server { listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; # Нужен любой, даже самоподписанный сертификат, чтобы Nginx не ругался при старте ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem; ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key; return 444; }
Сертификаты уже могут присутствовать в Ubuntu. Проверяем:
# ls -l /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/private/ssl-cert-snakeoil.key
Если нет, то устанавливаем утилиту и генерируем их:
# apt install ssl-cert -y && make-ssl-cert generate-default-snakeoil --force-overwrite
Конфигурацию следует проверить, сервер перезапустить.
Выпуск бесплатного SSL-сертификата Let's Encrypt через Certbot
Выпуск сертификата безопасности происходит также как для Apache, но используется ключ --nginx:
# apt install snapd # snap install --classic certbot # ln -s /snap/bin/certbot /usr/bin/certbot # certbot --nginx -d mysite.name -d www.mysite.name
В конфигурационном файле дописываем http2 on, чтобы сайт передавался по протоколу h2. Итоговое содержание файла конфигурации:
server { server_name mysite.name www.mysite.name; root /var/www/mysite; index index.html; location / { try_files $uri $uri/ =404; } listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mysite.name/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mysite.name/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot http2 on; } server { if ($host = www.mysite.name) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = mysite.name) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; server_name mysite.name www.mysite.name; return 404; # managed by Certbot }
Если ваш VPS поддерживает IPv6, желательно внутри первого серверного блока (где listen 443 ssl;) дописать строчку для IPv6:
listen [::]:443 ssl;
А во второй блок (где listen 80;) дописать:
listen [::]:80;
Настройка 301-редиректа с WWW на домен без WWW в Nginx
Для редиректа с www на без-www надо добавить отдельный серверный блок (виртуальный хост), который будет обрабатывать запросы на www и выполнять редирект. При этом необходимо убрать упоминание домена с www из директивы server_name других блоков.
# ... # Редирект с www на без-www (для HTTP и HTTPS) server { listen 80; listen 443 ssl; server_name www.mysite.name; # Пути к SSL-сертификатам (скопируйте их из основного блока) ssl_certificate /etc/letsencrypt/live/mysite.name/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mysite.name/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Сам редирект (код 301 — постоянный редирект) return 301 https://mysite.name$request_uri; }
Однако в таком случае, с учетом команд в блоке порта 80, если страница будет запрашиваться по http и с www, то сначала произойдет редирект на https с www, и только потом на без-www. Поэтому оптимизированным решением будет сразу с порта 80 в обоих случаях перенаправлять на https без-www, а в серверном блоке, обрабатывающем www, оставить только протокол 443.
# ... server { listen 80; server_name mysite.name www.mysite.name; return 301 https://mysite.name$request_uri; } server { listen 443 ssl; http2 on; server_name www.mysite.name; ssl_certificate /etc/letsencrypt/live/mysite.name/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mysite.name/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot return 301 https://mysite.name$request_uri; }
Скрытие расширения .html, редирект на адрес без расширения
Чтобы Nginx читал файлы с расширением .html, когда адресация на сайте без них (ЧПУ — человеко-понятный URL), надо внести изменения в директиву location:
location / { # Было: # try_files $uri $uri/ =404; # Стало: сначала ищем точный файл, затем папку, затем файл с расширением .html, и если ничего нет — 404 try_files $uri $uri/ $uri.html =404; }
Чтобы при вводе .html в адресной строке происходил редирект на адрес без расширения, добавляем директиву частной маршрутизации:
location ~ \.html$ { if ($request_uri ~ ^/(.*)\.html$) { return 301 /$1; } try_files $uri =404; }
Поадресный редирект в Nginx
Если на сайте много перенаправлений, лучше всего составить карту редиректов с помощью директивы map.
# Создаем таблицу редиректов в самом начале файла (ВНЕ блока server) map $request_uri $new_uri { default ; # Левая колонка — старый адрес, правая — куда перенаправлять /kotlin0/null /kotlin/null-operators; /pygame/ /pygame/course; # ... }
В location / до try_files помещаем условие перенаправления:
if ($new_uri != ) { return 301 $new_uri; }
Сжатие и кэширование в Nginx
Чтобы работало сжатие, надо раскомментировать следующие строки в файле /etc/nginx/nginx.conf:
gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; # Оптимальный уровень сжатия (от 1 до 9) gzip_buffers 16 8k; gzip_http_version 1.1; # Список типов файлов, которые ОБЯЗАТЕЛЬНО нужно сжимать: gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
Для настройки кэширования статики добавляют отдельный блок location с регулярным выражением, указав в нём типы кэшируемых файлов (изображения, стили и скрипты):
# Кэширование шрифтов, изображений, видео, стилей и скриптов на 1 месяц location ~* \.(woff2|ttf|ttc|webp|png|jpeg|jpg|svg|gif|ico|webm|css|js)$ { expires 30d; add_header Cache-Control "public, no-transform"; access_log off; }
Готовый пример конфигурационного файла Nginx для статического сайта
map $request_uri $new_uri { default ""; # Левая колонка — старый адрес, правая — куда перенаправлять /offer /policy/offer; /kotlin0/null /kotlin/null-operators; /python/task/index /python/task/; } server { listen 443 ssl; http2 on; server_name mysite.name; root /var/www/mysite; index index.html; ssl_certificate /etc/letsencrypt/live/mysite.name/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mysite.name/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot location / { if ($new_uri != "") { return 301 $new_uri; } # Защита от грязных ссылок, которые ведут на страницы с параметрами, которых не существует # Если в аргументах (параметрах URL) есть page= с любым значением if ($args ~* "(^|&)page=") { return 404; } try_files $uri $uri/ $uri.html =404; } location ~ \.html$ { if ($request_uri ~ ^/(.*)\.html$) { return 301 /$1; } try_files $uri =404; } location ~* \.(woff2|ttf|ttc|webp|png|ico|webm|css|js)$ { expires 30d; add_header Cache-Control "public, no-transform"; access_log off; log_not_found off; try_files $uri =404; } } server { listen 80; server_name mysite.name www.mysite.name; return 301 https://mysite.name$request_uri; } server { listen 443 ssl; http2 on; server_name www.mysite.name; ssl_certificate /etc/letsencrypt/live/mysite.name/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mysite.name/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot return 301 https://mysite.name$request_uri; }