Is
Applications AWS

Isso on AWS User Guide

| Product: Isso

Overview

This image runs Isso 0.14.0, the open source self-hosted commenting server by Martin Zimmermann, on Ubuntu 24.04 LTS. Isso gives any page on your website a comment thread that you own: you drop a single script tag into your template, and readers get threaded discussions, replies, Markdown, voting and email notifications, while every comment lives in a database on your own instance.

It is deliberately small. The server is a Python WSGI application and the entire data tier is one SQLite file. There is no separate database server, no cache tier, and no third-party service holding your readers' conversations or profiling them for advertising.

Isso comment widget showing a threaded discussion with replies, identicons and voting on the appliance's own demo page

Secure by default. Isso's own shipped configuration contains a published default admin password (please_choose_a_strong_password). This image never ships it. On the first boot of every instance, isso-firstboot.service generates values unique to that instance:

  • a 32-character admin password, which is the only credential for the moderation interface
  • a per-instance email hash salt, so commenter email hashes cannot be recovered with a rainbow table built against the salt every other Isso install shares

The image is captured with the admin password empty, which authenticates nobody: Isso's login only proceeds if data["password"] and data["password"] == password, so an empty submitted field is rejected before comparison and an empty configured password can never be matched. A fixed placeholder would be worse, because a placeholder published in a public image is itself a known credential.

Isso will refuse to start until first boot has generated real values, on two independent levers: isso.service declares a hard Requires dependency on the rotation, and a preflight check re-runs on every start and refuses an empty, default or short password, which also catches a hand-edited configuration rather than only a failed first boot.

The database is deliberately absent from the image, and that is a security control rather than housekeeping. Isso signs its admin session cookie with a session-key that it generates with os.urandom and stores inside the SQLite database, once, when the database is first created. An image that shipped a database would give every instance the same signing key, and anyone could forge an administrator session against any instance built from it. Because the image carries no database, Isso mints a fresh signing key on your instance's first start.

Architecture. Isso runs under gunicorn bound to 127.0.0.1:8080, behind nginx on port 80. The application has no public listener of its own, so nginx is the only front door.


Connecting to your instance

Connect over SSH on port 22 as the default login user for your operating-system variant.

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/your-key.pem ubuntu@<instance-public-ip>

The comment server itself is served on port 80 and is reached in a browser at http://<instance-public-ip>/. Never open port 8080 in your security group: gunicorn is bound to loopback and nginx is the only intended entry point.


Step 1 — Launch the instance

Launch the AMI from the AWS Marketplace listing, or with the AWS CLI. Isso is small; m5.large is the recommended type and is ample for a busy site. In your security group open 22 (SSH) and 80 (HTTP), plus 443 if you will terminate TLS on the instance.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name your-key \
  --security-group-ids sg-xxxxxxxx \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=isso}]'

Note the public IP the instance is assigned — it is used as <instance-public-ip> throughout this guide.


Step 2 — Confirm the services are running

SSH in as ubuntu and confirm all three units are active. isso-firstboot is a oneshot unit, so active here means it ran to completion and rotated this instance's secrets.

systemctl is-active isso nginx isso-firstboot

Expected output:

active
active
active

Confirm that Isso itself is bound only to loopback, and that nginx is the only public listener:

sudo ss -tlnp | grep -E ':80 |:8080 '

127.0.0.1:8080 for the Python application and 0.0.0.0:80 for nginx is the expected state. If gunicorn were listening on 0.0.0.0:8080, the application would be reachable around nginx.


Step 3 — Retrieve this instance's admin password

The admin password was generated on this instance's first boot and written to a root-owned file with mode 0600.

sudo ls -l /root/isso-credentials.txt
sudo cat /root/isso-credentials.txt

The file contains the site URL, the admin URL and ISSO_ADMIN_PASSWORD. There is no username — Isso's admin interface is authenticated by the password alone.

Store the password in your password manager. Nothing else on the instance will show it to you again in plain text, and the value is unique to this instance.


Step 4 — Verify the server is answering

Isso exposes its effective configuration at /config. This is the appliance's health endpoint:

curl -s http://<vm-ip>/config

Now confirm the endpoint the comment widget itself uses. Isso's comment-fetch endpoint is the site root with a uri query parameter naming the page whose thread you want, so this is the exact request your readers' browsers make:

curl -s 'http://<vm-ip>/?uri=%2F' | head -c 200

You should get JSON with a replies array, not HTML. Finally, prove that this instance's password actually authenticates. A 302 is a successful sign-in; Isso re-serves the login form with 200 when a password is wrong:

curl -s -o /dev/null -w "%{http_code}\n" -X POST -F "password=<isso-admin-password>" http://<vm-ip>/login/

Step 5 — Add your website to the whitelist

This is the step that makes Isso work on your own site, and skipping it is the most common reason a freshly deployed widget stays empty.

Isso only accepts comments from sites you explicitly list. This is a deliberate security boundary: it is what stops anyone else embedding your comment server on their pages. On first boot the image whitelists this instance's own addresses so that the built-in demo works immediately, but your site is not in that list yet.

Open the configuration:

sudo nano /etc/isso/isso.cfg

Find [general] host and add your site's URL, one per line, indented. Keep the existing entries. List a non-SSL URL first if you serve both, as some browsers suppress the referrer on plain HTTP requests:

[general]
host =
    http://<instance-public-ip>/
    https://blog.example.com/
    http://blog.example.com/

Restart Isso, then confirm it connected to a configured site. Isso HEAD-checks each host at start-up, so give it a few seconds before reading the log:

sudo systemctl restart isso
sleep 10
sudo journalctl -u isso -o cat -n 20 | grep -iE "connected to|unable to connect"

connected to ... is the healthy state. unable to connect to your website means Isso could not reach any URL in the list from the instance — check DNS and that the site is reachable from this network.

Why one of the listed URLs is this instance's private address. An EC2 instance cannot reach its own public IP: traffic to the public address is translated at the internet gateway and is not routed back to the instance. Isso HEAD-checks each configured host at start-up and warns if none answer, so the image lists the private address as well, which the instance can always reach. It also lets you serve readers over the VPC without a public IP at all.


Step 6 — Embed the widget in your site

Add these two lines to your page template, wherever you want the thread to appear. This is the whole integration.

<script src="http://<instance-public-ip>/js/embed.min.js" data-isso="http://<instance-public-ip>/"></script>
<section id="isso-thread" data-title="My first post"></section>

data-isso tells the widget where the comment server lives. data-title names the thread.

Set data-title. If you omit it, Isso creates the thread by fetching your page to read its <title>, which means your site must be reachable from the instance at that moment. Supplying the title avoids the fetch entirely and is the more robust choice.

Each page gets its own thread automatically, keyed by its URL path. To show a comment count on an index page without loading the whole widget, use the separate counter script and link to the thread anchor:

<script src="http://<instance-public-ip>/js/count.min.js"></script>
<a href="/my-post/#isso-thread">Comments</a>

This instance serves a live demo of the widget on its own front page at http://<instance-public-ip>/, with your embed snippet shown alongside it.

The appliance landing page showing the embed snippet and a live Isso thread with a comment being composed


Step 7 — Moderate your comments

Browse to http://<instance-public-ip>/admin/ and sign in with the password from Step 3.

The Isso admin sign-in page, secured by the per-instance password

The dashboard lists every comment with its thread, author and timestamp, and gives you Edit and Delete on each one. The filter bar switches between Valid, Pending and Staled, and you can order by date, likes or dislikes, group by thread, or search by URL.

The Isso moderation dashboard signed in, showing valid comments with their threads, authors, timestamps and edit and delete controls

The dashboard opens on the Pending filter, which is empty until you enable the moderation queue below. Click Valid to see published comments.

Enable the moderation queue

By default a new comment is published immediately. To hold every new comment until you approve it, set enabled = true in the [moderation] section of /etc/isso/isso.cfg and restart Isso. New comments then appear under Pending and stay invisible to readers until you activate them.

This only affects comments posted after the change; existing comments stay published.


Step 8 — Back up your comments

The entire data tier is one SQLite file, so a backup is one command:

sudo sqlite3 /var/lib/isso/comments.db ".backup '/tmp/isso-backup.db'"
ls -lh /tmp/isso-backup.db

Copy that file off the instance with scp and you have everything: every thread, every comment, and the admin session signing key. Restore by stopping Isso, putting the file back at /var/lib/isso/comments.db with isso:isso ownership, and starting Isso again.

Use .backup rather than copying the file directly — it takes a consistent snapshot of a live database.


Step 9 — Serve comments over HTTPS

If your site is HTTPS, browsers will block requests to a plain-HTTP comment server as mixed content, so put a certificate in front of Isso. Point a DNS record at the instance, then:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d comments.example.com

Then add the HTTPS URL to [general] host, update data-isso in your template to the https:// address, and restart Isso. Isso automatically switches its session cookie to SameSite=None; Secure when it is served over HTTPS, which is what allows the widget to work when your site and your comment server are on different domains.


Troubleshooting

The widget shows nothing on my site. Almost always Step 5: your site's URL is not in [general] host. Check your browser's console for a CORS error, add the URL, and restart Isso.

Isso will not start. Run sudo systemctl status isso and sudo journalctl -u isso -n 30. The preflight refuses to start on an empty, default or short admin password, on an empty [general] host, and on upstream's published default salt. The message names which one. Isso itself also exits if [general] host is empty.

"unable to connect to your website" in the log. Isso HEAD-checks each configured host at start-up. It is a warning, not a failure, and commenting still works — but it means none of the listed URLs answered from the instance. Note that the instance cannot reach its own public IP by design (see Step 5).

A comment fails with "URI is not accessible and no title was provided". The thread did not exist yet and Isso could not fetch the page to read its title. Add data-title to your <section id="isso-thread"> (Step 6).

I lost the admin password. Set a new one in [admin] password in /etc/isso/isso.cfg and restart Isso. Use at least 20 characters; the preflight rejects anything shorter.

Comments are being rejected as spam. [guard] rate-limits to 2 new comments per minute per client subnet and 3 top-level comments per thread. Raise ratelimit and direct-reply if that is too strict for your traffic.


What is installed

Component Detail
Isso 0.14.0, MIT licence, in a virtualenv at /opt/isso
Application server gunicorn, bound to 127.0.0.1:8080
Web server nginx on port 80, the only public listener
Database SQLite at /var/lib/isso/comments.db
Configuration /etc/isso/isso.cfg, mode 0640 root:isso
Credentials /root/isso-credentials.txt, mode 0600 root:root
Firstboot isso-firstboot.service, rotates the admin password and salt per instance
Preflight /usr/local/sbin/isso-preflight.sh, runs on every start of isso.service

The configuration file holds the admin password in plain text, because Isso compares it as a plain string and has no hashed form. It is readable only by root and the isso service account, and it is not reachable over HTTP.


Support

This image is packaged and maintained by cloudimg. Isso itself is free software under the MIT licence, developed by Martin Zimmermann and the Isso contributors — cloudimg is not affiliated with the Isso project.

For image-specific questions, contact cloudimg support through the AWS Marketplace listing. For questions about Isso itself, see the Isso documentation.