RSS

Add comments to Static blog like Hugo, Jekyll with Isso

How to add comments in Hugo with Isso commenting server? The setup should work with other static blog system like Jekyll, next.js, Gatsby, Nuxt, Hexo, Slate, Docusaurus, VuePress, Docsify, MkDocs etc. in similar way. Get to know more depth about Isso API and database schema.

Isso Introduction

Isso is a Disqus alternative commenting server for static web sites. It is a lightweight commenting server written in Python and JavaScript. It aims to be a drop-in replacement for Disqus.

The benefits of Isso compare to Disqus:

  • Smaller, javascript is 64kb compressed. faster loading speed compare to Disqus.
  • You own your data. comments stored in your server sqlite3 database.
  • No 3rd party code run on your site. 3rd party comment system can run whatever code on your site.

Features

  • Add/Reply/Like/Dislike comments.
  • Comments written in Markdown
  • Users can edit or delete own comments (within 15 minutes by default).
  • Comments in moderation queue are not publicly visible before activation.
  • anonymous comments
  • privacy, not log exact IP
  • Disqus & WordPress Import. You can migrate your Disqus/WordPress comments without any hassle.
  • SQLite backend.
  • Embed a single JS file, 65kB (20kB gzipped) and you are done.
  • Supports Firefox, Safari, Chrome and IE10.

Isso Setup

To setup Isso, you need following:

  • A server. If your site traffic is low, a very small server is enough.
  • A domain name for Isso server.

The first step is downloading the latest Isso source:

git clone https://github.com/posativ/isso.git

The easy way is use docker to run Isso. Build docker image by docker build:

$ docker build . -t isso
$ docker images
REPOSITORY   TAG               IMAGE ID       CREATED         SIZE
isso         latest            1234b841c0ac   4 hours ago     139MB

Then we need config Isso.

The Isso configuration file is an INI-style textfile. It reads integers, booleans, strings and lists.

The default isso configuration: isso.conf

Here is my config:

[general]
; database location, check permissions,
; automatically created if it does not exist
dbpath = /db/isso_comments.db

; your website or blog (not the location of Isso!)
host = https://yourdomain.tld/

[admin]
; admin interface in /admin
enabled = true
password = abc123

[guard]
; basic spam protection
enabled = true

; limit to N new comments per minute.
ratelimit = 5

; how many comments directly to the thread
direct-reply = 3

; allow commenters to reply to their own comments when they could still edit the comment.
reply-to-self = false
require-author = false
require-email = false

Hints:

  • dbpath and host is mandatory.
  • dbpath is the full path of sqlite3 database.
  • host is your site URL (include http:// or https://). It can have multiple values. config it correctly to avoid cross domain attack (CORS).
  • Enable admin to manage comment through web interface.
  • Enable guard to avoid spam.

Create config and db directory to store config and database.

mkdir -p config db

Put config file to config/isso.cfg then run Isso in docker:

docker run -d --rm --name isso -p 127.0.0.1:8080:8080 -v `pwd`/config:/config -v `pwd`/db:/db isso

Note: Do not run Isso on a public interface.

Next step is config nginx to proxy traffic to Isso.

Add a nginx virtual server config /etc/nginx/sites-enabled/isso.conf like following:

#
# /etc/nginx/sites-enabled/isso.conf
#
server {
    server_name comments.yourdomain.tld;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Then restart nginx:

sudo systemctl restart nginx

To test server is running by curl /admin, you should see HTTP 200 response:

$ curl -I https://comments.yourdomain.tld/admin
HTTP/2 200

Add comments to hugo

Inside hugo content.html page, add following code at end of article to load isso.

<div style="max-width: 80%;">
<h3>Comments</h3>
<script data-isso="//comments.yourdomain.tld/" src="//comments.yourdomain.tld/js/embed.min.js"></script>
<section id="comments"></section>
</div>

By default, isso make the comment center align, if you want to it left align, you can override its css like following:

<div style="max-width: 80%;">
<h3>Comments</h3>
<script data-isso="//comments.yourdomain.tld/" src="//comments.yourdomain.tld/js/embed.min.js"></script>
<style>
    .isso-postbox {
    margin: 0 !important;
    max-width: none !important;
    }

    #isso-root .isso-comment {
    max-width: none !important;
    margin: 0 !important;
    }
</style>
<section id="comments"></section>
</div>

That’s it. Hugo have a comment system powered by Isso.

Isso Internal

API

Isso provide JSON API:

  • GET /?uri= fetch comments for uri.
  • POST /preview Preview post.
  • POST /new Create new comment.
  • GET /id/<id> Get comment by id.
  • PUT /id/<id> Delete comment by id.
  • DELETE /id/<id> Delete comment by id.
  • POST /id/<id>/like Like.
  • POST /id/<id>/dislike Dislike.

Database

Isso use sqlite3 as database. There are three tables in database:

  • comments
  • preferences
  • threads

Table schema:

sqlite> .schema comments
CREATE TABLE comments (
    tid REFERENCES threads(id),
    id INTEGER PRIMARY KEY,
    parent INTEGER,
    created FLOAT NOT NULL,
    modified FLOAT,
    mode INTEGER,
    remote_addr VARCHAR,
    text VARCHAR,
    author VARCHAR,
    email VARCHAR,
    website VARCHAR,
    likes INTEGER DEFAULT 0,
    dislikes INTEGER DEFAULT 0,
    voters BLOB NOT NULL,
    notification INTEGER DEFAULT 0
);
CREATE TRIGGER remove_stale_threads
    AFTER DELETE ON comments
    BEGIN
        DELETE FROM threads
            WHERE id NOT IN (SELECT tid FROM comments);
    END;

sqlite> .schema threads
CREATE TABLE threads (
    id INTEGER PRIMARY KEY,
    uri VARCHAR(256) UNIQUE,
    title VARCHAR(256)
);

sqlite> .schema preferences
CREATE TABLE preferences (
    key VARCHAR PRIMARY KEY,
    value VARCHAR
);

Sample data in database:

sqlite> .head on
sqlite> select * from comments;
tid|id|parent|created|modified|mode|remote_addr|text|author|email|website|likes|dislikes|voters|notification
1|1||1613999513.18983||1|5a01:21f3:c311:0000:0000:0000:0000:0000|First comment.||||0|0||0

sqlite> select * from threads;
id|uri|title
1|/blog/fun/|

sqlite> select * from preferences;
key|value
session-key|123456789012345678901234567890123456789056781234

References

DNS Firewall for iOS

Encrypted your DNS to protect your privacy and firewall to block phishing, malicious domains, block ads in all browsers and apps

Ad