Лисаков и макромир

Комментарии для статического сайта. Установка Isso.

В этой записи дан краткий обзор доступным системам комментариев, затем описана установка комментариев Isso на свой сервер с Ubuntu 16.04 и Nginx. Стараюсь поддерживать запись в актуальном состоянии, последнее обновление в июле 2018 года.

Системы комментирования

Сторонние системы

Примеры:

  • Just Comments,
  • Remarkbox,
  • GraphComments,
  • cackle,
  • cenchat,
  • comment system from widgetpack.com
  • HyperComments,
  • IntenseDebate,
  • Livefyre,
  • Disqus,
  • а также комментарии от социальных сетей (vk, facebook, google+, …)

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

Минусы: комментарии принадлежат не тебе и не комментаторам; комментарии хранятся не у тебя; информация о пользователях (IP, e-mail) уходит к третьим лицам и может использоваться в коммерческих целях; обычно не open-source — внешний вид не изменить и функций не добавить; зачастую медленная загрузка. Disqus, например, известен своей грязной политикой по сбору данных и отслеживанию пользователей — при этом посетителю достаточно зайти на страницу, не обязательно оставлять комментарий. Подгружает несколько сотен килобайт мусора для отслеживания пользователей, посетивших страницу. Подробнее про это можно почитать, например, на donw.io.

Веб-приложения

Приложения, которые можно установить на своём сервере (иногда есть сервисы, которые будут хостить комментарии за вас. Тогда по сути получается такая же «сторонняя система», как в предыдущем пункте. Однако, ниже перечислены Open-source проекты, авторы которых, как правило, не пытаются на них заработать. А если и пытаются, то делают это с умом. Это значит, что данные ваших посетителей не собираются продавать, а самих посетителей — отслеживать и забрасывать мегабайтами хлама).

Примеры (активность в разработке указана на июль 2018 года. Имеется в виду частота обновлений кода, количество issues & PR в основном репозитории и скорость реакции. Разделил субъективно активность на 4 категории: высокая, средняя, низкая, заброшено. Отсортировал по количеству звёзд на github на июль 2018. На этот период в стадии активной разработки находится только Remark42):

  • 3277★ Isso (github, демо): python & SQLite, низкая активность;
  • 2691★ Commento (gitlab, github, демо): Go & SQLite, сайт может быть недоступен из России в связи с блокировками в 2018, средняя активность. Также см. форк, переписано на php: php-commento;
  • 1233★ schnack (github, демо): Node & SQLite, надо войти через twitter/github/google, низкая активность;
  • 1028★ Juvia (github, демо (логин discard@phusion.nl, пароль 123456)): ruby & MySQL, заброшено с весны 2015 года;
  • 955★ coralproject talk (github): Node & MongoDB, Redis;
  • 561★ Remark42 (github, демо): Go & boltdb, высокая активность;
  • 487★ Valine (github, демо): Node?, средняя активность;
  • 417★ mouthful (github, демо): Go, preact & MySQL/Sqlite/Postgres/dynamodb, средняя активность;
  • 202★ Hashover 2 (github), PHP & XML файлы;
  • 160★ Hashover 1 (github, демо), PHP & XML файлы;
  • 195★ Talkatv (github): python, заброшено с зимы 2012;
  • 117★ Wildfire (github, демо): real-time databases (Firebase and Wilddog);
  • 85★ External Comments (github): ruby & Redis/Sqlite, последняя активность зима 2018 года);
  • 53★ Realtime Commenting (github, демо): PHP & Pusher;
  • 41★ comments app (github, демо): Node? & protostuffdb, последняя активность осень 2017;
  • 35★ Master Comments System (github): PHP & MySQL, заброшено в 2013;
  • 33★ jskomment (github, демо): AJAX & js, заброшено;
  • 24★ Squabble (github, демо): Lumen (PHP) & SQLite, последняя активность в начале 2017. Разработано для сайта, на который ссылается демо;
  • 21★ Diskuto (github): Vibe.d (D) & MongoDB, выглядит неплохо, низкая активность;
  • 9★ comment-sidecar (github): PHP & MySQL, низкая активность;
  • 0★ JP-Comment (github): PHP, только китайская документация.

Более полную и акутальную информацию по open-source системам комментариев смотри на open-source-comments. Просьба сообщать о нерабочих ссылках (особенно на демо) и отсутствующих системах комментирования.

Плюсы: Всё перечисленное — open-source; комментарии хранятся у себя. Почти за три года использования isso не получил ни одного спам-комментария (никакой защиты от спама в isso нет). Думаю, что и у остальных перечисленных систем такой проблемы нет в связи с их относительно небольшой популярностью.

Минусы: Нужна установка; нужен сервер, на котором будут установлены эти приложения. Можно найти бесплатные варианты. Например, есть было описание, как установить Juvia на бесплатный облачный хостинг OpenShift.

Для Isso во второй половине 2018 появился бесплатный сервис comment.sh. Создан одним энтузиастом, так что про стабильность работы пока ничего сказать нельзя. Для Commento есть аналогичный сервис, на момент написания готовящийся к запуску. В случае использования этих сервисов вы перестаёте владеть комментариями (они хранятся у третьих лиц), однако это будет значительно легче, быстрее и порядочнее, чем disqus.

Главное отличие между Isso и Juvia (именно эти системы мне понравились больше всего): у Juvia есть полноценная админка, где в браузере можно просматривать, править и удалять все комментарии. У Isso каждый новый комментарий можно удалять/активировать (при включённой модерации) по ссылке из e-mail; в 2018 добавили простую админку, можно работать с комментариями (удалить, отредактировать), но не с тредами. Чтобы удалять треды (все комментарии со страницы), надо будет лезть в файл базы данных SQLite3. Эти операции будут описаны ниже.

Github issues

Есть реализации комментариев через систему github issues. Пользователь должен иметь github-аккаунт.

Статические комментарии

Так или иначе, автоматизированно или не слишком, комментарии могут быть вставлены прямо в html код страницы. То есть при просмотре кода страницы по Ctrl+U комментарии будут видны в теле страницы. В случае веб-приложений это, разумеется, не так.

Примеры:

Плюсы: Комментарии у хранятся у себя; комментарии встраиваются в статическую страницу — мгновенная загрузка; для последних двух пунктов сервер не нужен.

Минусы: Некоторые пункты подойдут только для пользователей Jekyll; комментарии появятся на сайте только после того, как он будет собран с помощью Jekyll и залит на сайт.

Jekyll::StaticComments — плагин для генератора статических сайтов Jekyll. Добавляется форма в код страницы. При отправке комментария срабатывает php-скрипт, посылающий e-mail админу с комментарием, отформатированным в YAML. Этот же скрипт помещает текст комментария в специальную папку. При следующей сборке сайта Jekyll вставит комментарий в нужное место на странице. Страница с комментариями загружается как обычная статическая html-страница. Пользователи с выключенным javascript смогут всё прочитать.

Идея для Even more static comments for Jekyll — идея для упрощения плагина Jekyll::StaticComments. Не нужен php скрипт, e-mail отсылается через mailto:. Что произойдёт при клике на такую ссылку, зависит от настроек браузера. Можете проверить: пример mailto: ссылки.

Staticman — довольно интересная штука. Сервер не нужен; сайт, размещённый на github, пересоберётся самостоятельно. Не нужно быть зарегистрированным на github, чтобы оставить комментарий.

Наверняка есть ещё что-то похожее, но я пока не встречал. Дайте знать.

Форумы

Многофункциональные «форумы», которые при желании можно приспособить для комментариев. Иногда попадаются готовые решения. Вряд ли это имеет смысл в общем случае, так как эти приложения тяжелее и требовательнее, чем перечисленные выше.

  • 25477★ Discourse (github). Не совсем комментарии. Больше похоже на форум, но некоторые используют, как комментарии. Open-source.

  • 3370★ symphony: комментарии на Java (не javascript). Основная документация на китайском.

  • 810★ Spirit (github): Django (python) & PostgreSQL/MySQL/SQLite3/Oracle, демо

  • 110★ Talkyard (github-1, github-2) — первоначально Debiki, переименован в EffectiveDiscussions, затем в Talkyard. Open-source. React.js у клиента; Scala и Play Framework 2 на сервере. Базы данных PostgreSQL и ElasticSearch. Можно использовать как форум (демо). Есть пост от автора, где эта система используется как комментарии к блогу, а не как форум. Похоже на Discourse.

Другое

  • Появляются проекты с использованием AWS Lambda. Например, chatter (не путать с другим chatter!).

  • Смотри также https://commentpara.de/.

  • Не было времени разобраться и определить подходящую категорию:

  • Наконец, см. альтернативы Дискусу на alternativeto.net.

Таблица сравнения комментариев

И на закуску — табличка с фокусом на Open-source. Чтобы узнать больше о том, почему значок оранжевый, наведите на него мышь, появится объяснение.

Таблица немного устарела, надо бы добавить Commento.

Удалить/править свой коммент. Русский язык Nested comments Уведом-ление по email Можно коммен-тировать, не вводя email Open-source Нужен сервер Можно ставить аватар Админка Где хранятся комменты
Disqus × × нет У них
SV Kament × нет У них
Juvia × × × Ruby У себя, MySQL
Isso Python × У себя, SQLite3
Tildehash × × PHP У себя, текстовые XML-файлы
Static comments for Jekyll × × × PHP × × У себя, текстовые YAML-файлы
Even more static comments for Jekyll × × × × нет × × У себя, текстовые YAML-файлы

Комментарии Isso

Почему Isso?

Я пользовался Disqus. Особенно меня раздражала медленность загрузки: заходишь на страницу, пролистываешь немного, через пару секунд подгружаются комментарии, в результате страница меняет свою высоту и экран рывком перемещается на другую позицию. Узнав про манеры Disqus (отсылка о факте посещения страницы десяткам адресатов), озаботился поиском альтернатив, чтобы быстрее избавиться от этой помойки.

Система комментирования Isso мне сразу понравилась, так как соответствовала моим основным требованиям:

  • Подгружается быстро;
  • Позволяет комментировать абсолютно анонимно, можно даже имя не вводить.

Isso хранит комментарии в SQLite3 базе данных, а не неведомо где; не отправляет личные данные посетителей моего сайта третьим лицам; поддерживает импорт из Wordpress и Disqus; позволяет пользователям редактировать комментарии в течение задаваемого времени; отправляет e-mail уведомление о новом комментарии на сайте (к сожалению, пока только владельцу, но не комментаторам); Isso — это Open source (можно копаться в исходниках на здоровье); поддерживает язык разметки Markdown. Документация по установке хорошая, но местами приходилось вносить какие-то коррективы и что-то выискивать. В итоге, как всегда, с настройкой помог hombit. Скупо выражаю ему благодарность.

Однако, когда я устанавливал isso, мне не было известно про commento. Сейчас, вполне возможно, я выбрал бы commento, так как эта штука ещё легче и ещё быстрее работает. Таблица согласно автору commento:

Parameter Commento Isso Schnack
Latency (50% percentile)   17 ms    169 ms    236 ms
Latency (99% percentile)   132 ms    664 ms    313 ms
Requests per second    21,764 RPS   692 RPS   3,392 RPS
Memory usage    240 kB    2.2 MB    2.4 MB
Payload    15.9 kB    173 kB    40 kB

То есть commento подгружает в 11 раз меньший js и ещё меньше нагружает сервер.

Итак, устанавливаем систему комментариев Isso на Ubuntu 16.04 и запускаем настраиваем её для работы с веб-сервером Nginx. Поехали.

Установка

Установка из исходного кода довольно простая и гарантирует наличие последних обновлений. В последней версии, которую можно поставить через pip на текущий момент, нет предпросмотра комментариев и админки, которые уже есть при установке из исходников. Официальная документация по установке здесь, на всякий случай очень сжато продублирую для Ubuntu/Debian систем.

Устанавливаем зависимости и node.js с npm.

root #
root #
root #
root #
root #
root #
root #
apt-get update
apt-get install python-setuptools python-virtualenv python-dev build-essential sqlite3
apt-get install nodejs
apt-get install npm
npm install -g bower
npm install -g requirejs uglify-js jade
ln -s /usr/bin/nodejs /usr/bin/node
user $
user $
user $
user $
git clone https://github.com/posativ/isso.git
cd isso/
virtualenv .
source ./bin/activate
(isso) user $
(isso) user $
(isso) user $
python setup.py develop
make init
make js

Теперь создадим конфигурационные файлы.

/etc/isso.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[general]
dbpath = /home/user/isso/comments.db
host =
http://localhost:4000
http://127.0.0.1:4000
https://yoursite.com
https://YOURSUBDOMAIN.yoursite.com
max-age = 57d
notify = smtp
admin_password = YOURPASSWORD

[moderation]
enabled = false
purge-after = 91d

[smtp]
username = your@email.com
password = YOURPASSWORD
host = smtp.yandex.ru
port = 465
security = ssl
to = where-to-send-your-notifications@com
from = "Тема сообщения" <comments@yoursite.com>

[server]
listen = http://localhost:8057
reload = off
profile = off

[guard]
enabled = true
reply-to-self = true

# limit to N new comments per minute.
ratelimit = 3

Чтобы в дальнейшем выйти из virtualenv, надо выполнить команду deactivate. Проверьте, всё ли правильно настроено (замените user):

user $
/home/user/isso/bin/isso -c /etc/isso.cfg run

Настройка для запуска сервиса

Чтобы запускать isso как сервис в systemd, создайте файлы /home/user/isso/isso.sh и /etc/systemd/system/isso.service. Внимательно проверьте параметры (особенно пути!) и замените на своё.

/home/user/isso/isso.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/sh
### BEGIN INIT INFO
# Provides: isso
# Required-Start: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: lightweight Disqus alternative
### END INIT INFO

EXEC=/home/user/isso/bin/isso
EXEC_OPTS="-c /etc/isso.cfg run"

RUNAS=isso
PIDFILE=/home/user/isso/isso.pid

start() {
echo 'Starting service...' >&2
start-stop-daemon --start --user "$RUNAS" --background --make-pidfile --pidfile $PIDFILE \
--exec $EXEC -- $EXEC_OPTS
}

stop() {
echo 'Stopping service...' >&2
start-stop-daemon --stop --user "$RUNAS" --pidfile $PIDFILE --exec $EXEC
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac

Скрипт /home/user/isso/isso.sh должен быть исполняемым:

user $
chmod +x /home/user/isso/isso.sh
/etc/systemd/system/isso.service
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=start-stop isso

[Service]

Type=oneshot
ExecStart=/home/slisakov/isso/isso.sh start
ExecStop=/home/slisakov/isso/isso.sh stop
RemainAfterExit=yes

[Install]

WantedBy=multi-user.target

Перезагрузите daemons:

root #
systemctl daemon-reload

Запустите сервис и проверьте статус:

root #
root #
systemctl restart isso.service
systemctl status isso.service

Последняя команда должна возвращать active. Если всё в порядке, то добавьте в автозагрузку:

root #
systemctl enable isso.service

Теперь isso автоматически запустится после перезагрузки.

Настройка веб-сервера Nginx

Создаём файл /etc/nginx/sites-available/comments:

/etc/nginx/sites-available/comments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream app_server {
server 127.0.0.1:8057 fail_timeout=0;
}

server {
server_name comments.yoursite.com;

location / {
proxy_set_header 'Access-Control-Allow-Origin' 'http://yoursite.com';
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}

}

Поменяйте yoursite.com на ваше доменное имя. Теперь создаём ссылку:

root #
ln -s /etc/nginx/sites-available/comments /etc/nginx/sites-enabled/

Проверьте настройки и перезапустите веб-сервер, если всё хорошо.

root #
root #
nginx -t
systemctl reload nginx

Настройка DNS

Чтобы поддомен comments.yoursite.com заработал, надо настроить DNS (при попытке зайти на этот адрес будет выдана ошибка Bad Request missing uri query, так и должно быть). Я делал это на Яндексе, т.к. пользуюсь его услугами DNS. Я отправился на pdd.yandex.ru → редактор DNS → добавить запись (Хост: comments, Тип: А, Значение записи: IP адрес Вашего сервера).

Запуск Isso

Пора проверить, работает ли всё, как положено: создайте тестовый файл isso.html, например, в корне сайта:

1
2
3
4
5
<script data-isso="//comments.yoursite.com/"
src="//comments.yoursite.com/js/embed.min.js">
</script>


<section id="isso-thread"></section>

Если при открытии в браузере что-то не работает, то откройте консоль (Ctrl+Shift+I или F12), выберите Console и поглядите, какие ошибки возникают.

Если на yoursite.com/isso.html всё работает, поглядите, какие переменные можно добавить. Скорее всего, Вам пригодится data-isso-lang="ru". Итоговый код, который я вставлял на все страницы, выглядит так:

1
2
3
4
5
6
<script data-isso="//comments.yoursite.com/"
data-isso-lang="ru"
src="//comments.yoursite.com/js/embed.min.js">
</script>


<section id="isso-thread"></section>

Экспорт из Дискуса/Wordpress

user $
user $
gunzip disqus-or-wordpress.xml.gz
/home/user/isso/bin/isso -c /etc/isso.cfg import disqus-or-wordpress.xml

Изменения пойдут в определённый в /etc/isso.cfg параметр dbpath.

Будет предупреждение о том, что файл уже существует. Введите y для продолжения. База будет добавлена к существующим комментариям. Например, если выполнить команду 2 раза, то все экспортированные комментарии будут двоиться. Isso подцепит дату и имя, одинаковым именам поставит одинаковый аватар.

Запускаем Isso через uWSGI (опционально)

Итак, если всё получилось, то можно теперь сделать ещё круче, а именно — запустить Isso с помощью gunicorn, gevent, uWSGI и тому подобных утилит для организации взаимодействия Python-приложения с веб-сервером (Nginx, Apache и т.д.). Выше мы запускали Isso с помощью /etc/init.d/isso, пользуясь встроенным в Isso веб-сервером, но у этого варианта есть недостатки.

Как написано на официальном сайте Isso:

Isso поставляется со встроенным web-server’ом, который хорош для начальной настройки и может использоваться на не очень загруженных сайтах — до 20 запросов в секунду. «Настоящий» WSGI-сервер поддерживает такие замечательные вещи как UNIX domain sockets, демонизация, надёжный HTTP обработчик и в то же время является более стабильным и безопасным, чем встроенный веб-сервер.

Не смотря на то что 20 запросов в секунду моему сайту не светит, я решил-таки запустить Isso с помощью uWSGI (другие варианты см. на официальном сайте сайте (англ)).

Для начала установим uWSGI.

root #
root #
mkdir /opt/uwsgi
chown -R user:user /opt/uwsgi
user $
user $
virtualenv /opt/uwsgi
source /opt/uwsgi/bin/activate
(uwsgi) user $
pip install uwsgi

Создайте директорию (если выберете другой адрес, то указывать в uwsgi.ini надо будет его):

user $
mkdir ~/mail

Создайте файл ~/uwsgi.ini с такими настройками (введите правильный адрес для spooler):

~/uwsgi.ini
1
2
3
4
5
6
7
8
9
10
11
12
[uwsgi]
http = :8057
master = true
; set to `nproc`
processes = 4
cache2 = name=hash,items=1024,blocksize=32
; you may change this
spooler = /home/<ИМЯ ПОЛЬЗОВАТЕЛЯ>/mail
module = isso.run
; if you use a virtual environment
virtualenv = /opt/isso
env = ISSO_SETTINGS=/etc/isso.cfg

Обратите внимание, порт (здесь 8057) должен быть такой же, как и в /etc/isso.cfg.

Чтобы uWSGI запускался и запускал Isso после перезагрузки, создайте файл /etc/init/uwsgi.conf:

1
2
3
4
5
description "uWSGI for Isso"
start on runlevel [2345]
stop on runlevel [06]
respawn
exec uwsgi /home/user/uwsgi.ini

Обратите внимание, не init.d, а именно init. Осталось удалить из загрузок при старте системы наш старый скрипт /etc/init.d/isso:

root #
systemctl disable isso.service

API

Чтобы получить комментарий в json формате со страницы, например, с этой страницы, можно выполнить в терминале:

GET http://comments.lisakov.com/?uri=%2Fen/blog/astrophoto-iris%2F

или зайти в браузере по этому адресу. При этом все русские буквы будут заменены на юникодовские символы типа \u0430. Именно поэтому я дал ссылку на страницу с единственным английским комментарием на моём сайте.

По API можно и оставлять, удалять и править комментарии, см. подробнее (англ.).

Обратите внимание, что если комментариев на странице нет, то будет возвращена ошибка 404 (Document not found).

Работаем с базой данных

Этот раздел понадобится, если нужно поправить или удалить threadы или комментарии. Thread — это все комментарии со страницы.

Удалять комментарии по мере поступления в нормальном режиме удобно прямо из почты, по одной штуке. В письме с извещением о новом комментарии на сайте находится ссылка на комментарий и ссылка для его удаления; ещё ссылка на одобрение комментария, если включена премодерация. Покопаться в базе данных будет полезно, чтобы удалить или изменить ненужные более threads (например, изменился адрес страницы).

По умолчанию dbpath = /var/lib/isso/comments.db, это и есть файл базы данных со всеми комментариями. Сохраним две копии на всякий пожарный, с одной будем работать и потом отправим её на замену старой, вторая для страховки.

user $
user $
cp /var/lib/isso/comments.db ~/very_original_comments.db
cp /var/lib/isso/comments.db ~/

Теперь войдите в SQLite, введя sqlite3, и выполните:

user $
user $
ATTACH '/home/user/comments.db' AS isso;
.tables
isso.comments     isso.preferences      isso.threads

А эти команды напечатают соответственно все колонки для таблиц комментариев, тредов и настроек:

sqlite> 
sqlite>
sqlite>
SELECT * FROM isso.comments;
SELECT * FROM isso.threads;
SELECT * FROM isso.preferences;

Чтобы удалить thread под номером 1, надо выполнить:

sqlite> 
DELETE FROM isso.threads WHERE ID = 1;

То же самое можно сделать и с isso.comments, только там ID находится во 2 колонке. Операторы > и < тоже можно использовать.

А что, если хочется изменить комментарий, когда отведённые на это 15 (по умолчанию) минут истекли? Вообще, согласно файлу db/comments.py, у комментария в таблице есть следующие колонки:

1
2
3
fields = ['tid', 'id', 'parent', 'created', 'modified', 'mode', 
'remote_addr', 'text', 'author', 'email', 'website',
'likes', 'dislikes', 'voters', 'notification']

Где tid — номер треда. У треда isso.threads в таблице всего 3 колонки:

1
fields = ['id', 'uri', 'title']

Как уже сказано, команда sqlite> SELECT * FROM isso.comments; покажет всё из таблицы комментариев. Чтобы увидеть, например, только id и text, выполните:

sqlite> 
SELECT id, text FROM isso.comments;

Чтобы найти «Гондурас» в комментарии, выполните (поиск чувствителен к регистру):

sqlite> 
SELECT id, text FROM isso.comments WHERE text like '%Гондурас%'

Больше про регулярные выражения в SQLite см. тут.

Узнав id комментария (например, 57), можно заменить текст для найденного комментария и проверить, что получилось:

sqlite> 
sqlite>
UPDATE isso.comments SET text='Новый текст комментария' WHERE id=57;
SELECT id, text from isso.comments WHERE id=57;

Осталось заменить текущий файл базы данных:

user $
cp ~/comments.db /var/lib/isso/

Заключение

Обязательно задавайте вопросы, если что-то не получилось или не работает. PS. Если выпадающие списки от Bootstrap исчезают после одного раскрытия: см. сюда.