Если пару лет назад инструмент PageSpeed показывал оценку близкую к 100, то сегодня она может быть даже не 50, а 39, как в случае моего Pet-проекта. Большинство изменений, о которых пойдет речь ниже, связано с отказом от устаревающих решений.

Про метрики Core Web Vitals уже кто только не написал, и дабы не раздувать текст избавлю вас от сто первого рассказа об их важности. Кому нужны подробности, то вот статья Дениса Стасьева, которую недавно опубликовали в блоге Mail.ru.

День 1 – обновление серверного окружения


Для начала сервер должен быстро ответить, а уже потом следует думать о передаче файлов, отрисовке сайта и взаимодействии с ним. Из рекомендаций Google у нас три направления:

  • Оптимизировать сервер;
  • Ускорить работу с базами данных;
  • Выделить больше оперативки и мощности процессора.

Первое, что оставим в прошлом – виртуальный хостинг. На виртуальном выделенном сервере мы получим больше ресурсов, гибкости настроек и почти ничего не потеряем. За бекапами и обновлением серверного ПО придется следить самостоятельно.

Нам нужен VPS/VDS c Debian 11 без дополнительного ПО. После оплаты виртуального сервера в панели провайдера станет доступен root пароль и ip или их вышлют на e-mail. Для управления сервером понадобится небольшая программка для удалённого доступа по SSH — PuTTY. Скачивайте клиент только с официального сайта. Также джентельменский набор включает в себя FileZilla и WinSCP.

Выбор панели управления


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

  • ISPmanager – мощный инструмент, который уничтожили жадной дистрибуцией: каждый мажорный релиз приходится покупать заново. Ничего не имею против подписочного способа монетизации, но когда покупаешь «вечную» лицензию, ожидаешь получать обновления дольше, чем один год.
  • VestaCP – поражает своей простотой. Сайты на ней могли работать годами, только иногда приходилось закрывать уязвимости PHP, exim и в паре других пакетов, которые не имеют отношения к самой Весте. Пик популярности этой волшебной и бесплатной панели пришелся на лето 2017 года. А потом что-то пошло не так: обновления стали редкими, новые функции не добавлялись. С марта 2021 известны незакрытые уязвимости, их можно залатать руками, но брошенным софтом пользоваться уже как-то не хочется.
  • HestiaCP – благо есть форк, в который навнедряли все накопившиеся предложения. Например, индивидуальные версии PHP для каждого сайта. Добавлена поддержка Debian 11. И вообще то, что надо для сайтов современного веба.

Настройка виртуального сервера


Запускаем PuTTY, вводим ip сервера. Далее нас попросят ввести логин (root) и пароль. Не пугайтесь, если видите командную строку впервые, главное – решиться и начать.

#Обновляем ОС
apt update && apt upgrade

#скачиваем скрипт для bash, который установит нам панель
wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh

#запускаем установку, подставляем свой домен, почту и пароль
bash hst-install.sh --hostname %domain.com% --email %email% --password %password%

#Панель открывается по адресу https://%IPсервера%:8083


Переносим файлы сайта и базу данных, меняем DNS (советую использовать Cloudflare, но в Hestia есть свой сервис), подключаем автоматическое обновление сертификата Let's Encrypt в разделе WEB для вашего домена. Не забываем самостоятельно скачивать и проверять целостность бекапов в разделе BACKUPS.

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

scp root@%старыйIP%:/backup/%пользователь-и-дата-бекапа%.tar /backup/

v-restore-user admin %пользователь-и-дата-бекапа%.tar


Советую сразу провести небольшой тюнинг. Включим строгий (можно еще сказать «точный») режим для сессий и кэширование в PHP:

В панели кликаем на шестеренку в шапке Server -> Apache -> Edit -> Configure PHP. Wordpress со стандартным набором плагинов хорошо работает со значениями memory_limit 512mb и post_max_size 32mb. Если хотите загружать большие файлы из админки сайта, то поставьте и upload_max_filesize 32mb.

В Advanced Options нужно добавить или раскомментировать строки:

[Session]
session.use_strict_mode = 1

[opcache]
opcache.enable=1
opcache.memory_consumption=512
opcache.max_accelerated_files=65407
opcache.max_wasted_percentage=10


Устанавливаем систему хранения данных в памяти для быстрого извлечения и работы кэша Wordpress: Redis или Memcached, оба используют NoSQL и хранят данные в виде пар ключ-значение. Для плагина W3 Total Cache выберем Memcached:

apt-get install memcached php-memcached php7.4-memcached php8.1-memcached 

#Добавим памяти, для конфигураций сервера более 4гб можно поставить с запасом
nano /etc/memcached.conf
# меняем значение -m 512mb

service memcached restart


Разница между производительностью Wordpress на версиях PHP 5.6 и 7.4 может достигать 50%. Разница между 7.4 и 8.1RC2 меньше – 22%, но по меркам веба очень крутой результат. Еще скорость улучшил (количественно измерить не удалось) переход с Debian 9 на Debian 11.



Что еще можно сделать? Выкинуть Apache на свалку истории, но тогда придется переписать редиректы под Nginx и настроить движки, которые установлены во вложенные папки, а не в корневую. Вы ведь уже скачали и проверили бекап? Значит осталось почистить базу данных плагином или вручную.

День 2 – отказ от jQuery и других инструментов


Была уверенность, что с ростом производительности чипов лагающие интерфейсы со временем станут быстрыми, но от внимания разработчиков ускользают два факта. Первый – увеличение частоты обновления экранов – 60 кадров в секунду должно быть достаточно для каждого. Но теперь экраны 90, 120, 144 и больше герц добавляют и в бюджетные устройства. Второй – с ростом абонентской базы пропускной способности современных сетей не хватит.

Когда внедрялась в 2006 году библиотека jQuery, браузеры переходили к новому витку развития. Разработчики тратили время на поддержку устаревших браузеров. Все проще, когда за совместимость отвечает библиотека или фреймворк. CSS в третьем поколении научился в трансформации и анимации, чем дублирует функционал JavaScript, но делает это быстрее. Рост популярности jQuery продолжается и сегодня, но все же он замедлился.



В Wordpress по умолчанию подключается jQuery версии 1.12. В Wordpress 5.8.1 вместе с jQuery v3.6.0 подключается еще скрипт для сохранения обратной совместимости jQuery Migrate v3.3.2. Никто не обрадуется, когда очередное обновления Wordpress поломает их сайт.

Да, версия 1.12 jQuery официально поддерживает Internet Explorer 6, 7, и 8. Их распространение, по данным статистики Liveinternet, давно стало ниже 0.0%.

Отключается jQuery добавлением кода в файл functions.php, только разместить его нужно как можно выше, иначе могут быть конфликты с объявлением или отключением некоторых функций.

function my_init() {
    if (!is_admin()) {
        wp_deregister_script('jquery');
        wp_register_script('jquery', false);
    }
}
add_action('init', 'my_init');


Или если ваша тема чувствительна к полному отключению jQuery, то вот код с подключением свежей версии без jQuery Migrate:

if (!is_admin()) {
	wp_deregister_script('jquery');
	wp_register_script('jquery', ("https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"), false);
	wp_enqueue_script('jquery');
}


Перед глазами маячат рекомендации «Устраните ресурсы, блокирующие отображение» и «Удалите неиспользуемый код JavaScript и CSS». А чем дальше в лес, тем строже метрики. Попробуем избавиться от css и javascript, хотя полностью это вряд ли получится.

Не стоит экономить на ощущениях восприятия дизайна. Интерфейсы без обратной связи похожи на пустыню: жизнь, может, и есть, но она едва заметна. Навел на элемент – должна появиться подсказка. Нажал на кнопку – она не просто среагировала эффектом, да еще и появилось сообщение о произошедшем действии.

CSS не блокирует основной поток браузера и работает всегда быстро, в отличие от JavaScript. CSS может хранить состояния с помощью инпутов. Если что-то реализуемо на CSS, то за этим решением приоритет. За исключением, наверное, жестов – когда нужно контролировать анимации в реальном времени.

Примеры, как и где можно заменить jQuery и JavaScript на CSS:


В CSS нет селекторов верхнего уровня и по родителю. Существует реляционный селектор :has, но он сейчас не поддерживается в браузерах. Естественно, CSS не умеет управлять содержимым блоков и обмениваться данными с сервером.

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

На главной странице остается рекомендация «Сократите размер структуры DOM». Лечится добавлением отсроченной загрузки блоков.

***

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

Файлы минифицируются плагином Autoptimize перед передачей пользователю. Картинки пережимаются в оптимальный формат плагином EWWW Image Optimizer.

Wordpress автоматически добавляет атрибут loading=«lazy» к картинкам. Но это может негативно повлиять на LCP, когда картинка попадает на первый экран. Код, который отключает ленивую загрузку у первой картинки в записях:

add_filter('the_content', 'remove_first_lazy');
function remove_first_lazy( $post_content ){
    $postxt = strpos($post_content, 'loading="lazy"');
  return $postxt!==false ? substr_replace($post_content, '', $postxt, strlen('loading="lazy"')) : $post_content;
}


PageSpeed не всегда прямо пишет, что именно можно еще поправить. Когда оценка никак не могла шагнуть в зеленую зону, а все пункты вроде бы были выполнены, причина оказалась в добавлении форматов и разрешений картинок с помощью JavaScript. Используйте тег picture.

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

От чего ещё отказался:

  • Фреймворк форума Invision Community;
  • Fontawesome – иконки можно собрать в свой шрифт, нарисовать средствами CSS или разместить на одно изображение.

День 3 – заключительная уборка


Сайты зарабатывают на взаимодействии пользователей с ними. Нажал на кнопку – хорошо. Дочитал статью до конца – отлично. Поделился ссылкой – замечательно.

Излишки кода мешают пользователям: их устройствам приходится загружать все нужное и не очень. Это как обойти все отделы супермаркета ради одного хлеба. Решил переосмыслить непопулярный функционал и убрать каталог стримов Twitch и GoodGame, форум и даже комментарии.

Особенно жалко было стримы из-за их гениального исполнения: сортировались в реальном времени и переключались без необходимости обновлять страницу – аналог пульта для телевизора. Но раз ими пользовалось меньше 100 пользователей в день, удаляем. Иногда очень важно и нужно менять глобально, переосмыслять то, что не взлетает.



Выводы


  • Обновление PHP и настройка кэширования значительно повышают производительность;
  • Отказом от Apache и тюнингом конфигов можно сэкономить еще пару миллисекунд;
  • Библиотеки и фреймворки устаревают, ничто не вечно;
  • JavaScript в некоторых случаях получается заменить быстрым CSS;
  • Если что-то неэффективно или не пользуется популярностью – надо убирать.

Иллюстрации выполнила Маша Зимина. За вдохновение и инвайт спасибо Филиппу Ранжину fillpackart

Комментарии (12)


  1. mobi
    13.10.2021 21:39

    В WordPress по умолчанию подключается jQuery версии 1.12

    Начиная с WordPress 5.6 вроде бы подключается одна из последних версий jQuery (так, текущий релиз WordPress 5.8.1 поставляется с jQuery 3.6.0).


    1. Khov1 Автор
      13.10.2021 21:51

      Спасибо. Подключаются два файла: jQuery v3.6.0 и jQuery Migrate v3.3.2.


  1. Goodwinnew
    13.10.2021 22:46
    +2

    Надо бы серверу помочь перестать заниматься фигней вместо работы:

    • берем не VPS/VDS - а именно VDS, это действительно отдельный виртуальный сервер, он же KVM

    • VPS не берем (OpenVZ) - это фактически контейнер с общим ядром Линукс, память и диск - там проблемы, зато дешево

    • меняем порт 22 на что-нибудь свое (там на 22 порт будет порядка 20-30 запросов в секунду с китайских серверов), fail2ban не поможет, там гигантский пул IP адресов

    • баним IP желающих подобрать что-либо в url по 404 ошибке (ошибки в лог на сервере + fail2ban на этот лог) - тоже полно желающих 20-30 запросов в секунду

    • перекидываем wp-config.php на уровень выше, так к нему тоже 20-30 запросов от подборщиков

    • возвращаем обработку ошибок 404 по указанию левых файлов на уровень Апач (вместо обработки WP)

    • меняем url админки на другой (через плагин)

    и тогда большая часть тупых ботов останется без работы и наконец-то сервер займется реальными пользователями :)

    И переход на следующий уровень сложности - включаем FastCGI в апаче - улучшатель обработки многопользовательского режима - сам апач однопоточный

    Переход на следующий уровень - да, выкидываем Апач и работаем через связку Nginx-PHP-FPM

    А потом можно уже и WP заняться или какой-либо другой CRM. Базу там поменять с MySQL на её форк. При использовании KVM сделать виртуальный диск в оперативку и базу туда закинуть = основные тормоза сайта на 50% к запросам к базе


    1. Smashrock
      13.10.2021 23:47
      +2

      Раз едем, то можно заняться и безопасностью сервера:
      1. Берём и запихиваем nginx в контейнер, или используем systemd sandboxing или почти готовое решение bunkerity/bunkerized-nginx: ????️ -- и подключаем modsecurity (или naxsi для желающих хардкора) и crowdsec (последний что-то типа fail2ban на стероидах, который может подрубаться и к iptables - классная вещь). Можно и вот это впихнуть mitchellkrogza/nginx-ultimate-bad-bot-blocker . Если не использовали bunkerized-nginx, то посмотрите в сторону и этого модуля kyprizel/testcookie-nginx-module .

      Если используете WAF modsecurity и его собратьев, то минимизируете риск взлома сайта, но будут возможны атаки на сам сервер и его зависимости. Если хотите и этот риск минимизировать, то ставьте IPS перед сервером типа Snort, но тут нужно придумать способ, чтобы IPS смотрел незашифрованный трафик. Хз, может поставить nginx, который расшифровывает трафик пользователей и пускает незашифрованный через IPS на другой NGINX или Apache - тут у меня пока опыта мало :)

      2. Генерим конфиг nginx тут NGINXConfig | DigitalOcean и сверяем с новыми рекомендациями Mozilla тут Mozilla SSL Configuration Generator - врубаем OCSP stapling тоже из-за прибавки к скорости. Если на сайте операции с кредитками не будут проводится, то врубайте 0-RTT в TLS 1.3 - ага, штука с уязвимостью, но бустит скорость, и не забываем о HTTP/2. Также компилим динамические модули brotli, pagespeed (этот по желанию), http headers и другие, и подключаем.

      Обязательно запиливаем все крутые хедеры типа HSTS со всеми опциями и продолжительностью минимум в год (заносимся в список HSTS Preload List Submission), не забываем про защиту кукисов. Со CSP сложнее, но вы можете использовать Laboratory (Content Security Policy / CSP Toolkit) или CSP Wizard от report-uri.com, ну там ещё SRI запилить. (Удачи с CSP - нервовыносящая штука, но мощная).

      3. Конечно же получаем сертификат Let's encrypt, но с OCSP must staple и подписью ECDSA P-256. Для OCSP must staple при генерации добавляем --must-staple, с подписью сами разберётесь. Пока что браузеры кладут на OCSP staple, а тем более на OCSP must staple, но мы верим в светлое будущее. Я настолько верю, что даже указываю в DNS HTTPS RR, ведь Firefox уже их смотрит.

      4. Берём тулзу Lynis, аудируем систему и укрепляем её. Устанавливаем OSSEC HIDS и настраиваем на посылку отчётов в Slack (есть плагин), правда, у меня эта сволочь не компилится на последней стабильно Ubuntu. Тут уже заходим в /etc/sysctl.conf и начинаем укрепление - гайдов много, но будьте аккуратны особенно с kernel.modules_disabled = 0. Вместо того, чтобы его прописывать в sysctl.conf, сделайте вот такой скрипт и поставьте на автозапуск через crontab с помощью @reboot path_to_your_script. Таким образом, kernel.modules_disabled врубится после загрузки всех основных модулей в ядро, а потом запретит добавлять новые:

      #!/bin/bash

      sleep 300

      echo 1 > /proc/sys/kernel/modules_disabled

      Я уже забыл, что ещё сделал ради удовлетворения своего любопытства.


      Основные принципы работы с wordpress:

      1. Скачать Google Fonts и раздавать со своего сервера либо CDN - намного отзывчивость повышается. Не пытайтесь даже рассчитать SRI на Google Fonts - там таблица стилей меняется для каждого клиента, поэтому ничего у вас не выйдет.

      2. Придумать способ, чтобы сжать ресурсы сайта сразу на сервере и хранить сжатыми. Таким образом, серверу не придётся каждый раз тратить ресурсы на сжатие-пережатие, а это, возможно, очень трудозатратно. Идеально - минимизировать всё (включая очистку и минификацию svg - World's Best SVG Compressor (vecta.io)), сжать и раздавать. Где-то очень давно читал про этот способ, но позабыл его.

      3. Использовать Webp (уже все браузеры его поддерживают) и Mozjpeg. Для конкретных размеров png используем панду TinyPNG, а для остального Squoosh

      4. Лучше самому прописать все фавиконки сайта, чем полагаться на сам Wordpress, он не учитывает некоторые разновидности. Есть подвох - если у вас будет ico указана, то все браузеры благополучно забьют на модный svg, png и будут только показывать ico.

      5. Лучше ручками прописать все preload, prefetch, preconnect в head - очень классные вещи. Preload, prefetch и другие теги

      6. Ну и проводим аудит безопасности Wordpress с Security Ninja. Я пока не могу понять, лучше modsecurity или Wordfence WAF, но, думаю, что лучше использовать специализированные для Wordpress для большей защищённости, тогда как modsecurity, возможно, даст большую производительность. Также не забываем защитить БД (куча гайдов), PHP (офигенная вещь - jvoisin/snuffleupagus ) и изменить способ хеширования паролей на Argon2id (например PHP Native password hash). Ну и меняем ссыль на админскую панель, вешаем на неё hCaptcha и двухфакторку.

      Больше пока ночью ничего в голову не приходит :) Надеюсь, что хоть кому-то поможет этот длиннотекст.

      P.S. я до сих пор не понимаю, зачем админить сервак, на котором ты единственный живой пользователь, не под root. Можно же сделать так:

      1. Использовать модифицированный sshd Obfuscated OpenSSH Patches и сделать магическим словом рандомный пароль 100+ символов. Сканеры портов в душе не поймут, что тот странный порт оказывается sshd сервер с обфускацией рукопожатия.
      2. Аутентифицироваться только по ключу.
      3. Запилить двухфакторку на sshd - How To Set Up Multi-Factor Authentication for SSH

      Ну и ставим офигенно длинный пароль на root, который хешируется sha512 с кол-во hashing rounds 100к+.

      Какой тогда вектор атаки может применить хакер чтобы через все дебри запихнуться под root?


      P.P.S. я просто менеджер, который увлекается ковырянием вот в этом всём - к советам подходите очень критично.


      1. Smashrock
        14.10.2021 00:19

        Для ребят, которые хотят максимума, заходите в этот репозиторий и утаскивайте себе понравившиеся решения Whonix/security-misc: Kernel Hardening; Protect Linux User Accounts against Brute Force Attacks; Improve Entropy Collection; Strong Linux User Account Separation; Enhances Misc Security Settings

        Не забывайте ещё пошаманить с apparmor:
        1. apt install apparmor apparmor-profiles apparmor-profiles-extra apparmor-utils
        2. Профиль для nginx apparmor-profiles/usr.bin.nginx


        1. Smashrock
          14.10.2021 00:22

          Это пока моя конфигурация для systemd sandboxing nginx (вносим через команду systemctl edit nginx):

          [Service]
           ProtectHome=true
           ProtectSystem=full
           SystemCallFilter=@system-service
           LogsDirectory=nginx
           NoNewPrivileges=true
           ProtectKernelTunables=true
           ProtectKernelModules=true
           ProtectKernelLogs=true
           ProtectControlGroups=true
           RestrictSUIDSGID=true
           KeyringMode=private
           ProtectClock=true
           RestrictRealtime=true
           PrivateDevices=true
           PrivateTmp=true
           ProtectHostname=true
           RuntimeDirectory=nginx
           LogsDirectory=nginx
           LockPersonality=true
           ConditionSecurity=apparmor
           DevicePolicy=closed

          А это для unbound:
          unbound/unbound.service.in


      1. Khov1 Автор
        14.10.2021 10:20
        +1

        Спасибо за такие развернутые комментарии. Сервер можно настраивать бесконечно. А безопасности никогда не бывает достаточно. Hestia CP из коробки уже умеет многое (PHP-FPM, HTTP/2, ssl_stapling, HSTS...) и сравнительно безопасна.

        В статью мне надо еще добавить про плагин Limit Login Attempts Reloaded, полегче, чем комбайн Wordfence. Сейчас кто только не пытается подбирать пароли к админке WP.


  1. djkobraz
    14.10.2021 01:40

    Отличный материал, но ещё можно было бы отметить возможность кеширования страниц тем же Varnish, так же есть нюансы с тюнингом базы данных, фильтрации не желательных ботов, и многое другое. Мы шаблонизируем это все и делаем немного больше в пакете. Если кому интересно предлагаю присмотрется к https://zahid.host/ru/services/woocommerce/ . Если есть желающие улучшить наше предложение обращайтесь, обсудим ;)


    1. Khov1 Автор
      14.10.2021 11:03

      Плагины кеширования WP дают больше свободы действий с авторизованными пользователями. Как этим управлять в Varnish даже не представляю. Выше еще написали комментарий про FastCGI.


  1. Farmatique
    14.10.2021 08:58
    +1

    Это все очень круто и здорово если у тебя сайт не обвешан дополнительно всякой аналитическо-маркетинговой хренью, которая всеми способами норовит максимально снизить pagespeed score. Там какаято хрень вызовет смещение макета, а там модальное окно с cookie compliance сожрёт ещё TTI и т.д. и т.п.


    1. Khov1 Автор
      14.10.2021 10:37

      Рекламным платформам плевать на ваш сайт. Аналитикс и Метрика загружают скрипты, которые могут весить больше, чем страница с 10 картинками. Пробовал старую версию кода Метрики, но она все равно снижает производительность. У Liveinternet оптимальный подход: подключением картинки/пикселя.


      1. urvanov
        14.10.2021 14:25

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