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

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

В этой записи будет дан краткий обзор доступным системам комментариев. Затем будет подробно описана установка комментариев Isso на свой сервер с Ubuntu 14.04 и Nginx.

Isso — это веб-приложение, написанное на python. Для установки Isso вам понадобится сервер с python и SQLite (при желании можно найти бесплатные варианты). Устанавливается Isso довольно просто, а вот заставить его работать немного сложнее.

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

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

Примеры:

  • БесплатныеHyperComments, Disqus, IntenseDebate, Livefyre, комментарии от социальных сетей (vkontakte, facebook, google+, github…);
  • ПлатныеSV Kament (от 300 р/месяц; раньше был бесплатным; довольно глючный, но функциональный. Выглядит, как российский клон Дискуса, смысла платить за него нет никакого), cackle (от 200 р/месяц, функционал и внешний вид отличные, есть дополнения для интернет-магазинов).

Плюсы: для установки надо просто вставить javascript код на страницу. Всё.

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

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

Приложения, которые надо установить на своём (или облачном) сервере.

Примеры: Juvia (ruby & MySQL), Isso (python & SQLite3), Tildehash (PHP & XML файлы), Master Comments System (PHP & MySQL), Realtime Commenting (PHP & Pusher).

Плюсы: Всё перечисленное — open-source; комментарии хранятся у себя.

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

Демо: Juvia (логин discard@phusion.nl, пароль 123456), Isso, Tildehash, Master Comments System (скриншот внизу по ссылке), Realtime Commenting.

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

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

Примеры: Static comments plugin for Jekyll, Even more static comments for Jekyll.

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

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

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

Второй — модифицированная версия этого плагина. Не нужен php скрипт, e-mail отсылается через mailto:. Вот это я понимаю — статические комментарии! Что произойдёт при клике на такую ссылку, зависит от настроек пользователя. Можете проверить: пример mailto: ссылки.

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

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

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

Удалить/править свой коммент. Русский язык 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-файлы

Ещё системы комментариев:

  • Debiki (переименован в EffectiveDiscussions), на момент написания записи разрабатывается. Можно оставить тестовый комментарий, но установить, предупреждает автор, наверное, не получится. Open-source. React.js у клиента; Scala и Play Framework 2 на сервере. Базы данных PostgreSQL и ElasticSearch.

  • Discourse. Не совсем комментарии. Больше похоже на форум, но некоторые используют, как комментарии. Ищите подробности в интернете. Open-source.

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


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

Почему Isso?

Я пользовался Disqus, но был недоволен по 2 причинам:

  • медленно грузится,
  • нельзя комментировать, не оставляя e-mail.

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

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

  • Подгружается быстро, а не несколько секунд, как Дискус.
  • Позволяет комментировать абсолютно анонимно, можно даже имя не вводить. Мне кажется, что если человек хочет оставить комментарий, то необходимость вводить e-mail в большом проценте случаев отобьёт у него желание продолжать.

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

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

Установка

Ставим на свой сервер необходимые пакеты (в моём случае это сервер, на котором лежит мой сайт. Удалённая машина с Ubuntu 14.04):

root #
apt-get install python-setuptools python-virtualenv python-dev sqlite3 build-essential

Установим pip:

user $
user $
wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py

Первая команда просто скачивает файл из интернета. Если ссылка не работает (изменится, например), то ищите этот файл тут. Вторая команда выполняет установку pip, могут потребоваться права root. Теперь установим Isso, наконец.

Создадим директорию и отдадим её во владение пользователю (вместо user впишите своё имя пользователя):

root #
root #
mkdir /opt/isso
chown -R user:user /opt/isso

Войдём в виртуальное окружение virtualenv, чтобы устанавливать isso туда, а не глобально:

user $
user $
virtualenv /opt/isso
source /opt/isso/bin/activate

Virutalenv активирован, можно устанавливать isso:

(isso) user $
pip install isso

Чтобы в дальнейшем выйти из virtualenv, надо выполнить команду deactivate.

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

user $
ln -s /opt/isso/bin/isso /usr/local/bin/isso

Для работы сервиса isso нужно создать одноимённого пользователя:

user $
useradd isso

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

Нам нужно запускать isso как сервис, для этого создаём файл /etc/init.d/isso:

/etc/init.d/issoСкачать
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=/opt/isso/bin/isso
EXEC_OPTS="-c /etc/isso.cfg run"

RUNAS=isso
PIDFILE=/var/run/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

Надо сделать скрипт исполняемым:

root #
chmod +x /etc/init.d/isso

Конфигурационный файл

Теперь создадим конфигурационный файл /etc/isso.cfg. Вот стандартные настройки: https://github.com/posativ/isso/blob/master/share/isso.conf.

У меня настройки выглядят так:

/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
[general]
dbpath = /var/lib/isso/comments.db
host =
http://lisakov.com
http://subdomain.lisakov.com
http://localhost:4000

notify = smtp

[smtp]
username = sergey@lisakov.com
password = MYPASSWORD
host = smtp.yandex.ru
port = 465
security = ssl
to = sergey@lisakov.com
from = comments@lisakov.com

[moderation]
enabled = false

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

Чтобы комментарии работали на поддомене, надо перечислить его в host, при этом в Nginx его указывать не надо. Также у меня указано localhost:4000, чтобы смотреть сайт на локальной машине с комментариями, когда я собираю сайт для просмотра локально с помощью команды hexo server генератора hexo.io.

Для начала всю секцию smtp и notify=smtp можете удалить, потом настроите.

Настройка веб-сервера 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/

Настройка DNS

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

DNS

Запуск 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>

Не забудьте перезапустить Nginx:

root #
service nginx restart

Если получено сообщение [fail], значит, перезапуска не произошло — причины ищите в логе (по умолчанию — /var/log/nginx/error.log). Теперь осталось запустить сервис Isso. Для этого:

root #
service isso start

Если получено сообщение Starting service..., то всё, вероятно, в порядке. Можно проверить, запустился ли сервис:

user $
ps aux | grep isso

Если же сервис не запустился, можно попробовать запустить его вручную:

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

Лично у меня sudo service isso start работает, а sudo service isso stop не работает. Isso нужно перезагрузить, чтобы изменения в настройках вступили в силу, можно это сделать только остановив и запустив Isso заново. Чтобы остановить Isso, мне приходится делать

root #
killall isso

Если всё в порядке, то отправляйтесь тестировать yoursite.com/isso.html. Всё должно работать. Если нет, то откройте консоль (Ctrl+Shift+I или F12), выберите Console и поглядите, какие ошибки возникают.

Автозапуск после перезагрузки

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

root #
update-rc.d isso defaults

Если на 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>

Русификация

Сначала у меня были кракозябры вместо русских букв после добавления data-isso-lang="ru", но после перезагрузки сервиса Isso и Nginx всё стало пристойно. Однако, Isso русифицирован не полностью и с ошибками (автор уже сделал merge для моего pull request на Github, так что скоро эта часть не понадобится). Чтобы это исправить, надо подкорректировать все 4 файла в директории /usr/local/lib/python2.7/dist-packages/isso/js.

ru.jsСкачать
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
define('app/i18n/ru',{
"postbox-text": "Оставить комментарий (минимум 3 символа)",
"postbox-author": "Имя (необязательно)",
"postbox-email": "Email (необязательно)",
"postbox-website": "Сайт (необязательно)",
"postbox-submit": "Отправить",
"num-comments": "{{ n }} комментарий\n{{ n }} комментария\n{{ n }} комментариев",
"no-comments": "Пока нет комментариев",
"comment-reply": "Ответить",
"comment-edit": "Правка",
"comment-save": "Сохранить",
"comment-delete": "Удалить",
"comment-confirm": "Подтвердить удаление",
"comment-close": "Закрыть",
"comment-cancel": "Отменить",
"comment-deleted": "Комментарий удалён",
"comment-queued": "Комментарий будет проверен модератором",
"comment-anonymous": "Аноним",
"comment-hidden": "Скрыт {{ n }} комментарий\nСкрыто {{ n }} комментария\nСкрыто {{ n }} комментариев",
"date-now": "Только что",
"date-minute": "{{ n }} минуту назад\n{{ n }} минуты назад\n{{ n }} минут назад",
"date-hour": "{{ n }} час назад\n{{ n }} часа назад\n{{ n }} часов назад",
"date-day": "{{ n }} день назад\n{{ n }} дня назад\n{{ n }} дней назад",
"date-week": "{{ n }} неделю назад\n{{ n }} недели назад\n{{ n }} недель назад",
"date-month": "{{ n }} месяц назад\n{{ n }} месяца назад\n{{ n }} месяцев назад",
"date-year": "{{ n }} год назад\n{{ n }} года назад\n{{ n }} лет назад"
});

Самое крутое, что Isso будет правильно склонять слово «комментарий». 1, 21, 31, 41 комментарий, но 11 комментариев; 2, 3, 4 комментария; 0, 5, 6, 7, 8,… комментариев. Теперь остаётся пользоваться функционалом Isso: писать комментарии, используя простой язык разметки Markdown; включать/отключать премодерацию; вставлять счётчик комментариев (например, около названия записи в списке); вкл/откл «аватар» и настроить его цвета, отправлять уведомление о комментариях на указанный в /etc/isso.cfg адрес.

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

Заходите в админку на yourname.disqus.com, вкладка Discussions → вкладка Export → Export comments. Через некоторое время на почту придёт ссылка на XML-файл. В моём случае он был заархивирован в filename.xml.gz, поэтому я сначала его распаковал:

user $
gunzip disqus-or-wordpress.xml.gz

а потом конвертировал:

user $
isso -c /etc/isso.cfg import disqus-or-wordpress.xml

Изменения пойдут в определённый в /etc/isso.cfg параметр dbpath, по умолчанию /var/lib/isso/comments.db.

Будет предупреждение о том, что файл уже существует. Введите 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 #
update-rc.d isso disable

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
fields = ['tid', 'id', 'parent', 'created', 'modified', 'mode', 'remote_addr',
'text', 'author', 'email', 'website', 'likes', 'dislikes', 'voters']

Где tid — номер треда. Как уже сказано, команда 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 исчезают после одного раскрытия. Решается так (только файлы с этим кодом у них располагаются по другому адресу и называются иначе).