Данный сайт использует распространенный вариант хостинга с использование Github - при каждом изменении с помощью github-actions генерируется статичный сайт со всеми страницами. Из-за этого нет возможности использовать динамический контент напрямую, например, комментарии к статьям. Есть возможность использовать Disqus, но в таком случае появляется зависимость от сторонних сервисов.
Лучшим вариантом я считаю хранить комментарии у себя в репозитории, которые будут появляться на сайте в момент генерации сайта. Сервисов для реализации такого функционала очень много - как бесплатных, так и платных. Я остановлюсь на бесплатном варианте - Staticman от Eduardo Bouças, как наиболее продвинутом и удобном.
Как это работает:
- Посетитель блога отправляет комментарий, используя форму отправки под любым постом.
- В форме есть javascript, который отправляет результат на специальную API-прокладку, запущенную в виде приложения на
HerokuRender. Если у пользователя отключен JS, то будет сформирован простой POST запрос. - В свою очередь приложение производит валидацию комментария и, в случае успешного результата, создает pull request в репозиторий сайта, содержащий файл .yml с комментарием и мета данными.
- После принятия мной PR github автоматически генерирует новый сайт и комментарий появляется на сайте.
Сейчас у Staticman есть три версии API и основная сложность его подключения заключается в деплое приложения API-прокладки и настройки его. Мы будем использовать вторую версию, которая не сильно отличается от третьей (в третьей появилась возможность использовать Gitlab).
Создание аккаунта бота
Для создания pull request’ов в нашу репу используется гитхабовский personal access token, поэтому необходимо создать отдельный аккаунт для этого токена, так как этот токен будет использован для приложения Heroku Render, а, следовательно, может быть скомпрометирован и кто-то может получить доступ к вашему основному аккаунту.
Кроме этого, использование второго аккаунта позволяет удобно разделить коммиты комментариев от ваших правок в репозитории сайта.
Аккаунт бота ничем не отличается от обычного аккаунта Github, поэтому запускаем вкладку в инкогнито режиме, чтобы не выходить из своего аккаунта и создаем новый аккаунт с именем, которое вам нравится, пусть для статьи это будет github-bot
. Можно сразу создать README.md в личной репе (название такое же как у аккаунта) и написать, что это бот:
После создания аккаунта нам необходимо сделать две вещи:
- Создать personal access token, для использования его в приложении.
- Выдать доступ к репозиторию сайта основного аккаунта.
Personal access token
Создание токена производится в настройках аккаунта в разделе Developer settings -> Personal access tokens. Там нажимаем Generate new token, вводим пароль для безопасности, придумываем название токена и выдаем разрешение к двум разделам - repo и user:
После этого нажимаем Generate token и сохраняем где-нибудь отображенный токен - далее Github не даст его подсмотреть в целях безопасности. Далее в статье этот токен я будут обозначать как github-token
. Подробнее прочитать, что такое токен и для чего он может быть использован можно в официальной документации Github.
Доступ к репозиторию
Чтобы бот мог коммитить напрямую в наш репозиторий ему необходимо выдать права к репозиторию. Сделаем мы это через добавление бота в коллабораторы репы. Для этого переходим в настройки репы, там Manage access, а далее жмем кнопку Invite collaborator. В окошке вводим имя бота и отправляем приглашение.
Все, боту придет письмо со кнопкой принятия приглашения - не нажимаем ее, так как принимать приглашение мы будем через наше приложение - это будет дополнительным этапом проверки правильности работы приложения.
Приложение API
UPD. 01.12.2022 Heroku с 28.11.2022 отключил бесплатные варианты использования хостинга, поэтому приложение переехало на Render
Старый вариант инструкции с Heroku
Теперь нужно подготовить приложение для API-прослойки, которое будет принимать комментарии и создавать PR в наш репозиторий. Делать я это буду на Heroku, так как там имеется возможность использовать бесплатный инстанс, который по расчетам хватит примерно на ~1100 комментариев в месяц для аккаунта без кредитной карты (550 бесплатных часов) или ~4000 комментариев, если добавить кредитную карту в аккаунт (2000 бесплатных часов). Расчет таков - при отправке комментария приложение на Heroku просыпается и засыпает через 30 минут, таким образом в первом случае это550/0.5
и 2000/0.5
во втором.Теперь нужно подготовить приложение для API-прослойки, которое будет принимать комментарии и создавать PR в наш репозиторий. Делать я это буду на Render, который позволяет запускать бесплтаные Web-сервисы, а ограничения в 720 часов в месяц хватит примерно ~2880 комментариев. Расчет таков - при отправке комментария приложение на Render просыпается и засыпает через 15 минут, таким образом в это 720/0.25
.
Деплой приложения в Heroku Render
UPD. 01.12.2022 Heroku с 28.11.2022 отключил бесплатные варианты использования хостинга, поэтому приложение переехало на Render
Старый вариант инструкции с Heroku
После регистрации в Heroku нам необходимо создать свое приложение, проще всего это сделать из репозитория Staticman, где в README.md есть прямая ссылка не деплой:
Второй вариант - использовать для деплоя прямую ссылку. Если сделали все правильно, то вместо стандартной формы создания приложения мы увидим создание приложения Staticman:
Вводим имя приложения (далее я его буду обозначать как app-name
). Дожидаемся окончания деплоя и сборки нашего приложения, открываем его по кнопке Open app и убеждаемся, что ничего не запустилось 😀. Все потому, что приложению не хватает обязательных переменных, поэтому переходим к его настройке.
После регистрации в Render нам необходимо создать свое приложение, проще всего это сделать из репозитория Staticman, для этого заходим дэшборд, выбираем New -> Web service:
Далее нам предложат подключить аккаунт Github для возможность выбрать приватный репозиторий, но нам нужен вариант с публичным репозиторием внизу страницы, вводим туда путь к репозиторию Staticman и жмем Continue:
https://github.com/eduardoboucas/staticman
Вводим имя приложения (далее я его буду обозначать как app-name
). Region выбираем любой (для России я выбрал Franfurkt), остальные значения оставляем как есть и прокручиваем до секции Advanced, нажимаем её. Здесь нас интересуют два раздела - Environment variables и Auto-deploy, к первому мы еще вернемся, а во втором нужно выключить, чтобы Render не обновлял приложение после каждого изменения в репозитории Staticman:
Прежде чем продолжить нужно позаботиться об обязательных переменных, поэтому создадим их в следующем разделе.
Генерация RSA ключа
Данный ключ нужен для шифрования секретных значений, которые выложены в публичный доступ, например, ваш секретный токен сервиса reCAPTCHA. Данные шифруются открытым ключом и попадают в публичный доступ, а API приложение расшифровывает их закрытым ключом. Если открыть логи приложения Staticman, то мы увидим, что отсутствие ключа как раз и мешает ему запуститься:
Для генерации нового ключа используется команда:
# ssh-keygen -m PEM -t rsa -b 4096 -C "staticmankey" -f ~/.ssh/staticman_key
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in staticman_key.
Your public key has been saved in staticman_key.pub.
The key fingerprint is:
SHA256:VSMjbe....................iwPb67BXU8 staticmankey
Я не использовал пароль, так как после загрузки закрытого ключа в приложение Heroku его можно смело удалить - он нам больше не понадобится.
Проверить, что сгенирирован правильный ключ можно, открыв его в любом редакторе, либо же выполнить команду:
# head -2 ~/.ssh/staticman_key
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAyBStHD4kR9GjI9XZDf4V+QfNyuCbJRXde66WTRD3rDiyzaXC
Строка BEGIN RSA PRIVATE KEY
означает, что все сделано правильно, любой другой вариант (например, OPENSSH PRIVATE KEY
) означает, что что-то пошло не так и этот вариант не заработает.
Настройка приложения
UPD. 01.12.2022 Heroku с 28.11.2022 отключил бесплатные варианты использования хостинга, поэтому приложение переехало на Render
Старый вариант инструкции с Heroku
После генерации ключа осталось настроить наше приложение, сделать это можно двумя путями - через web интерфейс, либо через командную строку.
В первом случае открываем дэшборд Heroku, выбираем наше приложение, далее Settings, там нас интересует раздел Config Vars. Жмем кнопку Reveal Config Vars и вводим две переменные:
RSA_PRIVATE_KEY
- наш приватный ключ, вносить его можно прямо из файла, можно удалять перенос строк, можно не удалять - разницы никакой, Staticman поймет его в любом случае.GITHUB_TOKEN
- наш personal access token ботаgithub-token
, который мы создали ранее
Если все правильно, то должно получится так:
Второй вариант добавления настроек - это через командную строку Heroku. Следуя инструкциям, нужно установить командную строку и выполнить вход, после этого станет доступен очень удобный вариант управления приложением. Для внесения наших переменных следует воспользоваться командами:
Обратите внимания, что вместо app-name
и github-token
следует использовать ваши значения. Проверить, что все правильно можно командой:
Теперь открываем наше приложение по ссылке https://app-name.herokuapp.com
и мы должны увидеть приветствие Staticman:
Если его нет, то значит в каком-то пункте вы ошиблись и стоит посмотреть логи Heroku. Теперь мы можем попробовать принять приглашение в репозиторий сайта, для этого нужно открыть ссылку в формате:
https://app-name.herokuapp.com/v2/connect/<main-user-account>/<site-repository>
В моем случае это
https://app-name.herokuapp.com/v2/connect/xbreaker/xbreaker.github.io
В ответ мы должны получить OK!
- это означает, что бот принял приглашение, а, следовательно, приложение мы настроили правильно. Если сайт отвечает Invitation not found
, то либо мы уже приняли приглашение ранее, либо забыли бота пригласить.
Еще один способ проверить правильность настроек - в настройках основного аккаунта в разделе Manage access, аккаунт бота перейдет в статус Collaborator:
После генерации ключа осталось настроить наше приложение, возвращаемся на страницу создания приложения в Render и жмем Add Environment Variable
, после чего вводим наши переменные:
RSA_PRIVATE_KEY
- наш приватный ключ, вносить его можно прямо из файла, можно удалять перенос строк, можно не удалять - разницы никакой, Staticman поймет его в любом случае.GITHUB_TOKEN
- наш personal access token ботаgithub-token
, который мы создали ранее
Если все правильно, то должно получится так:
Теперь нажимаем Create Web Service и ждем пока в логах запуска не отобразится Staticman API running on port 10000
, это значит, что наше приложение запущено:
Теперь открываем наше приложение по ссылке https://app-name.onrender.com
и мы должны увидеть приветствие Staticman:
Hello from Staticman version 3.0.0!
Если его нет, то значит в каком-то пункте вы ошиблись и стоит посмотреть логи Render. В дешборд открывает Теперь мы можем попробовать принять приглашение в репозиторий сайта, для этого нужно открыть ссылку в формате:
https://app-name.onrender.com/v2/connect/<main-user-account>/<site-repository>
В моем случае это
https://app-name.onrender.com/v2/connect/xbreaker/xbreaker.github.io
В ответ мы должны получить OK!
- это означает, что бот принял приглашение, а, следовательно, приложение мы настроили правильно. Если сайт отвечает Invitation not found
, то либо мы уже приняли приглашение ранее, либо забыли бота пригласить.
Еще один способ проверить правильность настроек - в настройках основного аккаунта в разделе Manage access, аккаунт бота перейдет в статус Collaborator:
Настройка сайта
Пора подготовить наш сайт к использованию комментариев, для этого нам нужно выполнить четыре вещи:
- Создать файл настроек для Staticman
- Внести в настройки сайта URL нашего API-приложения
- Создать шаблон комментариев, который будет использован для генерации комментариев к постам
- Настройка и включение reCAPTCHA
Настройка Staticman
Подробно настройка описана в официальной документации, нам нужно создать файл staticman.yml
, полный пример заполнения можно найти здесь. Я же приведу сокращенный вариант, который настроен для этого сайта:
Поля thread
, parentName
, parent
используются для вложенных комментариев. Так же обратите внимание на настройки reCAPTCHA, если планируете ее использовать.
Настройки в config.yml
Здесь нам необходимо внести настройки Staticman, которые будут использоваться при отправке комментария - ссылку на API, плюс вариативные настройки сервиса reCAPTCHA. Настройки вносятся в файл config.eml
, у меня они расположены в params.staticman:
|
|
Ссылка на API должна быть вида:
https://app-name.onrender.com/v2/entry/<ваш github user>/<ваш github репозиторий>/main/comments
Обратите внимание на бранч вашего репозитория, для старых репозиториев это master, для новых - main.
Шаблон комментариев
Самый объемный пункт, так как нам нужно подготовить шаблон для своей темы, не забыть про JS, а так же про стили оформления. На моём сайте используется тема PaperMod, поэтому шаблон я буду делать для этой темы. Если вы используете другую тему, то адаптировать мой вариант будет не сложно.
Я не стал особо фантазировать, а решил использовать что-нибудь простое, интересный вариант нашелся здесь. Он послужил основой нашего шаблона, который был доработан под нужды статичного сайта - добавлен аватар и удалена голосовалка, так как в условиях статики ее нам не реализовать. Сам шаблон состоит из нескольких файлов, первым будет comments.html
- целиком я его приводить не буду, так как он слишком большой, найти его можно 🧾 здесь, я же остановлюсь на паре моментов.
Склонение окончания числительных, перед комментариями выводится их количество и, в зависимости от числа комментариев, меняется окончание слова “комментарий”. В шаблоне сейчас это выглядит очень громоздко, если кто-то подскажет более изящный вариант - буду очень благодарен.
|
|
Второй момент - это выделение комментариев автора блога от остальных. Чтобы это работало необходимо в параметры сайта внести параметр emailhash
, который содержит md5 хэш вашего почтового адреса. Чтобы его получить, заходим, например, сюда, вводим свою электронную почту и получившийся результат вносим в параметры:
|
|
Файл comments.html
следует скопировать в каталог \layouts\partials\
.
Второй файл - это файл стилей comments.css
, чтобы он попал в общий файл CSS стилей, придется пойти на хитрость - создать каталог assets\css\common\
и скопировать файл в данный каталог. Исходный код файла можно найти 🧾 здесь.
Вместе с файлом стилей нам нужен файл javascript логики, который добавит интерактивности нашим комментариям и форме отправки - comments.js
. Я использовал чистый JS (vanilla), чтобы исключить зависимость от какого-либо фреймворка. Интересный вариант отправки формы я взял отсюда и отсюда. Сам файл можно скопировать в каталог assets\js\
, подключим мы его в следующем абзаце. Исходный код файла забираем 🧾 здесь.
Чтобы подключить наш JS файл нам следует создать специальный файл темы extend_head.html
он позволяет добавить в HEAD сайта свои инструкции, чем мы и воспользуемся - добавим загрузку и сжатие нашего comments.js
. Кроме того, я добавил в него опциональную загрузку файла reCAPTCHA, если она включена в настройках. Копируем 🧾 содержимое и копируем его в каталог \layouts\partials\
.
Все файлы сразу расположены в этом 💾 gist, я специально не стал давать ссылки на репозиторий этого сайта, а выложил их отдельно. Так как в будущем файлы сайта могут измениться (или некоторые вообще могут быть удалены) и перестанут соответствовать тому, что здесь написано. А gist останется актуальным и нетронутым.
Настройка и включение reCAPTCHA
Выходим на финишную прямую, нам осталось подключить и настроить сервис reCAPTCHA. Данный сервис добавляет на сайт простой вариант проверки при отправке комментария и позволяет сильно снизить количество спам комментариев.
Для начала следует сходить на официальный сайт и зарегистрироваться. Нам нужна reCAPTCHA v2 Checkbox
версия, выбираем ее при регистрации:
Получаем site key и secret key, которые будут использованы далее:
Если site key сразу можно внести в настройки сайта и Staticman, то secret key не предназначен, чтобы передавать его в открытом виде. Поэтому его нужно зашифровать, поможет нам в этом наше ранее созданное приложение API.
Вызываем его по урлу вида:
https://app-name.onrender.com/v2/encrypt/secretKey
И результат, который оно возвратит и есть наш secret key для настроек. Сохраните обязательно где-нибудь оригинальный secret key на будущее.
Вносим настройки в config.yml
и staticman.yml
. Вот и все, готово 👍! Можно приступать к тестированию комментариев.
Итого
В этом посте можно посмотреть результат реализации таких комментариев, создаваемые PR после отправки комментария можно найти в репозитории.
Если у вас есть что добавить или поправить в этой статье - можно вносить правки напрямую.
10 комментариев
автор •
Первый тестовый комментарий 👍
автор •
Первый тестовый ответ на первый тестовый комментарий 💪🏻🎉🎉🎉
Здравствуйте, подскажите пожалуйста где я мог ошибиться, сделал по инструкции, но после запуска приложения , всё равно пишет что rsa key не найден, сначала создал private open ssh, потом перечитал внимательнее , удалил и создал Private Rsa Key добавил заново и вот… И есть ещё вопрос, токен должен быть бота или от основного аккаунта где будет мой сайт?
автор •
Роман, привет. Токен создается в настройках бота, после чего мы выдаем ему доступ к нашему репозиторию. По поводу ключа - он правильно добавлен в настройки Render? Напиши мне в телеграм @xbreaker, сможем вместе посмотреть
Очень круто получилось, есть еще вот такой вариант - utterances 🔮 Его минус в том, что обязательна авторизация через гитхаб, но выглядит не хуже 😉
автор •
Спасибо, посмотрел - прикольно. И спасибо за тестирование markdown в комментариях, нашел пару ошибок оформления в CSS.
12345555555555555555555555555555 не работают коментарии
хм, круто
test number 3
Тест render