Публикация SPA

Хочу поделиться опытом публикации SPA, где под публикацией подразумеваю более-менее готовый сайт, который нужно разместить на хостинге. Расскажу о базовых моментах, связанных с настройкой сервера, добавлении в поисковые системы и немного про то, как сделать сайт дружелюбнее с поисковиками.

В целом есть несколько способов, чтобы опубликовать сайт. Есть как более простые способы, например, хостинг с предустановленным ПО, но менее гибкие как раз из-за ограниченного набора приложений, так и способы, где нужно больше действий для настройки сервера, например, VPS/VDS или выделенный физический сервер а не виртуальный.

При выборе сервера также нельзя забывать, что потребуется операционная система, и тут можно сэкономить, выбрав одну из бесплатных ОС семейства Unix, конечно, это может подойти не всем, Windows, как мне кажется, пока еще более привычная операционка.

Перед тем как арендовать что-либо, подумайте, что подходит для вас лучше всего. В моем случае, кроме самого SPA, мне нужно запустить несколько приложений на сервере, хранить файлы и иметь возможность поставить любое freeware ПО, поэтому был арендован один небольшой VPS c Ubuntu 18.04. Еще, конечно, потому что в ней есть systemctl, очень похожа на Windows Services — можно добавлять свои приложения как сервисы.

В первую очередь, если у вас уже есть доменное имя, сопоставьте его с IP-адресом VPS в настройках DNS, потому что Whois будет обновлятся примерно 24 часа. Далее нужен клиент для доступа к серверу, выбрал классический Putty.

Устанавливаем соединение с сервером и авторизуемся. Сразу же создаем отдельную учетку с правами администратора, и это правда очень важно на любой ОС, потратьте немного времени чтобы ее создать.

adduser <username> usermod -aG sudo <username>

После можно сменить пользователя командой su <username> или попробуйте перезайти на сервер под новым пользователем. Когда залогинитесь под новой учетной записью, нужно сначала установить Firewall - ufw и настроить его. Более подробно про настройку можно найти по ссылке ниже.

#Обновляем пакеты sudo apt update sudo apt install ufw #Открываем необходимые порты sudo ufw allow ssh sudo ufw allow http sudo ufw allow https sudo ufw enable

С помощью этих команд устанавливаем Firewall, открываем порты: 22, 80, 443 для доступа извне, и включаем его.

И перед тем как делать что-то дальше, появился вопрос, как перенести build приложения (сам сайт) на удаленный сервер. Есть несколько вариантов: через утилиту pscp поставляемую с putty, то есть через SSH-соединение, расшарить директорию на своей машине или на удаленной. Мне приглянулся вариант с созданием «общей» папки на VPS. Для этого можно установить приложение Samba. Опять же, более подробно почитайте тут:

sudo apt install samba #Исключение для firewall sudo ufw allow samba #Создаем корневую директорию специально для общего доступа sudo mkdir /shared #Разрешаем доступ к директории всем из группы sambashare sudo chgrp sambashare /shared #Директория для нового пользователя sudo mkdir /samba/<samba user> #Создаем нового пользователя sudo useradd -M -d /samba/<samba user> -s /usr/sbin/nologin -G sambashare <samba user>

Дальше настраиваем директорию пользователя таким образом, чтобы все из группы sambashare могли ее менять.

sudo chown <samba user>:sambashare /samba/<samba user>

И добавляем пользователя в базу Samba.

sudo smbpasswd -a <samba user>

Открываем файл конфигурации.

sudo nano /etc/samba/smb.conf

В конец файла конфигурации Samba копируем следующие строки, где <samba user> — это пользователь, которого вы создали специально для работы с этой расшаренной папкой:

[<samba user>] #Фактически название директории к которой будете подключаться path = /shared/<samba user> browseable = no read only = no force create mode = 0660 force directory mode = 2770 valid users = <samba user>

И перезапускаем приложение.

sudo systemctl restart smbd sudo systemctl restart nmbd

После, в зависимости от вашей ОС, подключаемся к общей папке. В Windows открываем проводник и прописываем в адресной строке:

\\ip адрес\[<samba user>]

Вводим логин и пароль пользователя, и теперь можно скопировать сайт на сервер в расшаренную папку. А на самом сервере переносим приложение в стандартную директорию для сайтов.

sudo cp -a /shared/<samba user>/<website>/ /var/www/

Теперь можно установить прокси сервер, к примеру Nginx. С помощью него будем отдавать сайт по указанному адресу.

sudo apt install nginx

Можно использовать файл default, изменив конфигурацию по умолчанию, но лучше создать отдельный файл конфигурации для сайта с его именем.

sudo nano /etc/nginx/sites-available/<website>

И скопировать настройки, написанные ниже, заменив <domain name> на свой домен.

В настройках три секции server.

Первая для того, чтобы перенаправить все запросы с 80 порта на 443. Вторая секция, чтобы перенаправить все запросы с 443 порта с www в начале на сокращенное доменное имя. В последней секции server все настройки соединения с несколькими location.

Начну с последнего @prerender, как вы поняли исходя из названия, для пререндеринга, эту часть была добавлена после взаимодействия с поисковыми системами, и подробнее, почему я это сделал, можно почитать дальше (про поисковые системы).

Остальные два локейшена: в первом записано местоположения сайта, и изначально вместо try_files $uri @prerenderбыл try_files $uri $uri/ /index.html, во втором переадресация на API-сервис, поэтому и соответствующие условия можно прочитать, как ~ ^/api — содержащее /api в адресной строке, и ~ ^/(?!(api)) — не содержащее /api в адресной строке. Да, помимо сайта есть ещё Web API, но здесь я не буду о нем говорить.

#Первая секция. Перенаправляем все запросы с http на https server { listen 80; listen [::]:80; server_name <domain name> www.<domain name>; return 301 https://<domain name>$request_uri; } #Вторая секция. Перенаправляем запросы с www вначале на сокращенное имя server { listen 443 ssl; ssl_certificate /etc/ssl/<domain name>.crt; ssl_certificate_key /etc/ssl/<domain name>.key; server_name www.<domain name>; return 301 https://<domain name>$request_uri; } #Третья секция. Здесь описываем где искать сайт локально и другие параметры. server{ listen 443 ssl; index index.html; root /var/www/<website>; ssl_certificate /etc/ssl/<domain name>.crt; ssl_certificate_key /etc/ssl/<domain name>.key; server_name <domain name>; gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied expired no-cache no-store private auth; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/x-javascript application/javascript; gzip_disable "MSIE [1-6]\."; charset utf-8; # Запрос самого сайта location ~ ^/(?!(api)) { gzip_static on; try_files $uri @prerender; } # Запрос дополнительных данных c api location ~ ^/api { proxy_pass https://localhost:3004; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Host $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } location @prerender { proxy_set_header X-Prerender-Token <token>; set $prerender 0; if($http_user_agent ~* "bingbot|yandex|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest\/0\.|pinterestbot|slackbot|vkShare|W3C_Validator|whatsapp") { set $prerender 1; } if ($args ~ "_escaped_fragment_") { set $prerender 1; } if ($http_user_agent ~ "Prerender") { set $prerender 0; } if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") { set $prerender 0; } #resolve using DNS server to force DNS resolution and prevent caching of IPs resolver 1.1.1.1; if ($prerender = 1) { #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing set $prerender "service.prerender.io"; rewrite .* /$scheme://$host$request_uri? break; proxy_pass http://$prerender; } if ($prerender = 0) { rewrite .* /index.html break; } } }

Важным в этих настройках является активация сжатия gzip, чтобы весь контент до пользователя доставлялся быстрее, ну и в Chrome Audits получить более высокий рейтинг. 🙃

Для активации всех настроек, создаем ссылку для Nginx на этот файл.

sudo ln -s /etc/nginx/sites-available/<website> /etc/nginx/sites-enabled/

После всех изменений нужно убедиться, что в файлах конфигураций нет ошибок. Поэтому, на мой взгляд, каждый раз лучше запустить команду, и если что-то не так, команда вернет ошибку.

sudo nginx -t

В завершение настройки перезапускаем Nginx.

sudo systemctl restart nginx

При условии того, что все DNS обновились, можно заглянуть на сайт по доменному имени и убедиться, что все работает. Следующим шагом, хотя его лучше проделать заранее, но я сделал уже потом, воспользоваться средствами Chrome браузера для проверки работы сайта утилитой Audits. Открываем Chrome в режиме инкогнито (чтобы не было влияния расширений браузера и всего остального), нажимаем F12 и выбираем Audits.

​

На этой вкладке генерируем отчет для выбранного устройства, мобильного или настольного ПК. В отчете можно будет посмотреть ключевые параметры, зависящие от вас, которые вы могли бы изменить в лучшую сторону. Например, как раз размер передаваемых данных (не забыли ли вы включить сжатие на сервере gzip) или, допустим, объемные изображения.

​Отчет Chrome - Audits
​Отчет Chrome - Audits

С помощью этого отчета как раз подумал, что нужно сжать все изображения, используемые на сайте. Самый удобный способ, который я использовал, пожалуй, TinyPNG.

Так как можно сжимать PNG с прозрачным задним слоем, но, конечно, существует и ограничения — без платного аккаунта максимальный размер файла в 5 МБ. Суммарно позволило снизить вес картинок на ~50–70%.

Еще из отчета понял, что мои шрифты могут не отображаться какое-то время при загрузке странице, так как не использовал функцию swap, чтобы если шрифт не успел загрузиться, был отображен шрифт системы по умолчанию. В общем, полезная штука, но по поводу Yandex.Metrica/Google Analytics, которые все время попадают в отчет, лучше не заморачиваться.

Про поисковые системы

Вообще я использовал только 3 поисковые консоли (вебмастеры): это Google, Bing и Yandex. Чтобы видеть информацию по сайту в различных поисковиках, нужно создать для каждого поисковика свой аккаунт или по крайней мере зарегистрировать только один в Google, тем самым снизив число аккаунтов.

В них можно привязать сайт к аккаунту, добавив meta тег с ключом, или добавив XML-файл в корневой каталог (public) сайта, или же можно добавить ключ в файл конфигурации DNS.

Перед тем как привязывать сайт к аккаунту, я решил немного подождать и посмотреть, будет ли проиндексирован сайт в этих поисковиках. В общем, только Google проиндексировал все страницы SPA и нашел sitemap.xml который указан в robots.txt.

Bing добавил в индекс только главную страницу. Индексация произошла спустя примерно 1 неделю для Google, чуть больше недели для Bing после сопоставления доменного имени и IP-адреса. Yandex так и не проиндексировал сайт спустя две недели, может, было недостаточно времени.

Следующим этапом привязал сайт и добавил sitemap на обход. И через 3–4 дня я осознал, что только Google может обходить и индексировать SPA со всеми страницами. Yandex пометил все страницы, кроме основной, как дубликаты и не добавил в поисковую базу.

Почитав немного про эту проблему, понял, что лучше делать пререндеринг страниц локально или же с помощью какого-то сервиса. Ну и так как арендованная VPS не с самой лучшей конфигураций, воспользовался сервисом от prerender.io.

Необходимым и достаточным в этом случае оказалось: создание бесплатного аккаунта, чтобы получить токен, добавление условия маршрутизации для Nginx и добавление необходимых URL для кэширования на сервисе. Сама конфигурация любезно предоставлена в документации и выложена на Github.

В ней прописаны все известные user agents, то есть боты, а также файлы, которые будут запрошены с вашего сервера (location @prerender). При использовании бесплатного аккаунта есть ограничение в количестве кэшируемых страниц, равное 250. В целом для маленьких сайтов, я думаю, подходит.

Да, и еще важный момент, необходимо вернуть правильный статус-код страницы, если ее не существует. Для этого в приложении должна быть реализована отдельная страница «404», при рендеринге которой должен добавляться тег

<meta name="prerender-status-code" content="404"></meta>

в заголовок страницы. Таким образом prerender.io вернет правильный статус код для робота.

После проделанных изменений запустил все страницы на пере обход в «Яндекс.Вебмастера», правда, так и не понял до конца, есть ли в этом смысл, потому что переобходятся они почти сразу, а вот обновляются спустя примерно 5 дней.

Помимо этой проблемы, была еще проблема с favicon, точнее с тем, чтобы она не отображалась при выдаче в поисковиках. В «Яндексе» и Google разное описание того, какие должны быть характеристики у иконки, ну да ладно. Воспользовался еще одним сервисом, чтобы сгенерировать множество разных иконок, так же сервис генерирует все нужный теги с атрибутами для вставки на сайт.

Обновил и подумал, что теперь точно должно все заработать, но эта была неудачная попытка. Тогда решил, что просто посмотрю теги сайта, у которого точно есть иконка как в «Яндексе», так и в Google, выбрал YouTube (можно конечно и у vc.ru взять, у них хотя бы паук в разметке есть 🕷). Немного изменил свои теги:

<link rel="shortcut icon" href="https://<domain name>/favicon.ico" type="image/x-icon" /> <link rel="icon" sizes="32x32" href="https://<domain name>/favicon-32x32.png" type="image/png" /> <link rel="icon" sizes="48x48" href="https://<domain name>/favicon-48x48.png" type="image/png" /> <link rel="icon" sizes="96x96" href="https://<domain name>/favicon-96x96.png" type="image/png" /> <link rel="icon" sizes="144x144" href="https://<domain name>/favicon-144x144.png" type="image/png" /> <link rel="icon" sizes="192x192" href="https://<domain name>/android-icon-192x192.png" type="image/png" />

И спустя пару дней иконка наконец появилась в результатах выдачи поисковиков.

P.S. В конце захотел посмотреть, обходит ли Mail.ru сайты, спойлер — нет. И создавать аккаунт нужно именно мейловский.

88
2 комментария

Я ничего не понял, но сегодня сяду и всё это сделаю со своим сайтом 

Еще я бы добавил service worker для быстрого кеширования на клиенте.