Миграция с LAMP на Hugo

Сегодня у меня наконец-то от LAMP-стека осталась только буква L.

Теперь вместо связки Linux+Apache+MySQL+PHP у меня используется Linux+Nginx.

Далее будет небольшая хронология событий.

Начались проблемы с недоступностью сайтов

У меня есть несколько маленьких сайтов, которые уютно сосуществуют на одном виртуальном сервере.

Это данный блог и еще пара сайтов уровня “домашняя страничка”. Эти сайты были сделаны в разное время разными людьми, не приносят денег и серьёзно ими никто не занимается.

Некоторое время назад все эти сайты разом начали ложиться из-за того, что Apache начал выедать всю доступную оперативную память при нескольких висящих HTTP-подключениях. Реального трафика по данным HTTP-подключениям не было.

Я пытался подтюнить Apache, но это не сильно помогло.

Для решения этой проблемы для HTTP перед Apache был установлен Nginx. При этом HTTPS трафик заходил на Apache напрямую.

Полная замена Apache на Nginx была отложена до момента миграции всей виртуальной машины с Ubuntu 14.04 на Ubuntu 16.04.

Обнаружилась странная активность на сервере

PHP внезапно начал пытаться отправлять спам-письма. У него это не получалось, но сам факт этой активности вызывал беспокойство.

Поиск источника проблемы вел в Wordpress, на котором крутился данный блог.

Сам Wordpress при этом был нашпигован разными плагинами и обновлялся достаточно давно. Так что это более моя вина, чем проблема самого Wordpress.

Для решения первопричины данной проблемы было решено отказаться от локально установленного Wordpress-а. Рассматривались разные варианты, но в качестве решения был выбран Hugo.

Перевод блога на Hugo прошел как-то быстро и безболезненно. Единственная жертва, на которую пришлось пойти - комментарии к статьям. Меня, правда, это не сильно расстроило.

Обновление сервера с Ubuntu 14.04 на Ubuntu 16.04

Как только на хостинге появились виртуальные машины с поддержкой Ubuntu 16.04, я заказал второй виртуальный сервер и начал неторопливый перенос всех сервисов со старой виртуальной машины.

В процессе переноса из-за разницы в версии MySQL и PHP развалились все остальные сайты.

В результате было решено решить проблему на корню и переделать их с MODx на Hugo.

Переделка сайтов заняла некоторое время, но результат меня полностью устроил: визуально новые сайты остались такими же, а количество потенциальных уязвимостей сократилось на порядок.

Чем Hugo лучше чем CMS?

У любой CMS есть ряд принципиальных проблем:

  • CMS генерирует HTML в реальном времени, что сказывается не только на производительности, но и на защищенности сайта;
  • Любой установленный дополнительный плагин для CMS негативно сказывается на защищенности сайта. При этом за качество плагина никто поручиться не может;
  • Очень трудно отделить контент от оформления. Обе части CMS хранятся очень близко друг к другу внутри базы данных. Это так же крайне мешает разобраться в том, что именно произошло в случае компрометации сайта или порчи данных.

Hugo является не классической CMS, а генератором сайтов.

То есть на входе он получает директорию, в которой отдельно лежит контент (HTML или Markdown) и тема сайта. На выходе же он отдаёт статический контент, который необходимо просто положить в директорию для сайта на стороне WEB-сервера.

Минусы данного подхода:

  • Отсутствие динамического контента на сайте.

В качестве плюсов мы имеем:

  • Нет проблем с безопасностью, порождаемых динамической генерацией контента вообще и наличием PHP в частности;
  • Уже готовый контент отдаётся очень быстро;
  • Весь исходный код сайта можно спокойно положить в любую систему контроля версий и всегда знать, что, когда и кем поменялось;
  • Сайт можно генерировать на Jenkins и заливать результат через rsync.

Есть еще пара неочевидных бонусов:

  • Если выполнять rsync командой вида:

    rsync -rlvzc --delete-after public/ deploy@website:website/
    

    То для неизменённых файлов не меняется дата создания/модификации. Это позволяет эффективно использовать ETag на стороне Nginx: rsync не ломает ETag для неизменённых файлов.

  • На стороне nginx можно держать заранее сгенерированные gzip-файлы:

    # Не пытаемся сжимать данные налету
    gzip off;
    # Разрешаем отдавать предварительно сжатый файл с таким же именем и с расширением ".gz"
    gzip_static on;
    
comments powered by Disqus