Deployment guide

Comentario 3.19.0

Overview

This guide shows how to launch and use the Comentario 3.19.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. The AMI is one software version of the SecureAnyCloud forums and social networks listing on AWS Marketplace. Select it as the software version when you subscribe and launch.

Comentario is a fast, privacy-focused open source comment server for web pages and a self-hosted alternative to hosted commenting services. You add a short HTML snippet to your site, and Comentario renders a comment thread on every page. Threads support local accounts, moderation, voting, Markdown, RSS feeds, live updates, page view statistics, outbound webhooks, an audit log and a full REST API. One Go service serves the embeddable widget, its API and an Administration UI, and keeps everything in PostgreSQL.

What you get:

  • No default login. Comentario makes the first account that signs up the instance superuser. On this image that account is created on your instance's first boot, before anything is served, with a password generated on the instance and written to /root/comentario-credentials.txt (readable by root only). Comentario generates its server signing key at the same time. There is no database password to leak or rotate: Comentario signs in to PostgreSQL over the local Unix socket as its own operating system user (peer authentication), and no PostgreSQL role has a password. The image ships an empty database and no known password.
  • Sign-up closed. Registration of new users in the Administration UI is switched off, and users who are not domain owners cannot add domains, so nobody who reaches the instance can create an account on it. You decide when to invite users or switch sign-up on. Commenter registration on your own sites is a per-domain setting you control.
  • HTTPS from the first boot. nginx serves Comentario on port 443 with a certificate generated on your instance, port 80 redirects to HTTPS, and requests for a host name the instance does not serve are dropped. Comentario itself listens on 127.0.0.1:8080 only.
  • Fail closed. Comentario and nginx start only after first boot has finished. If it cannot finish, nothing is served.
  • Hardened defaults. Comentario, nginx, PostgreSQL and the first-boot service are blocked from the instance metadata service (Comentario fetches page titles, avatars and spam checks from the internet). The AMI requires IMDSv2. Comentario receives the configured host name and the real client address from the connection, never values that a client sends. Comentario refuses state-changing requests from other origins, and nginx also refuses them from a plainhttp:// origin in front of the Administration UI.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Comentario 3.19.0 (the official package, checksum verified), nginx 1.24 and PostgreSQL 16 (from Ubuntu 24.04), cloud-init and the AWS Systems Manager agent.

Default user: ubuntu; Architecture: x86_64; Recommended instance type: m5.large

Prerequisites

  • An AWS account that is subscribed to the listing, an EC2 key pair, and a VPC subnet with a route to the internet (or a private route that you use for management).
  • A security group that allows TCP 22 (SSH) from your admin network, and TCP 443 (Comentario) and TCP 80 (redirects to HTTPS) from the internet, because the comment widget on your sites loads from this instance. Never open ports 5432 or 8080, because PostgreSQL and Comentario listen on the loopback address only.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select Comentario 3.19.0 on Ubuntu 24.04 as the software version, pick your Region, and choose Launch through EC2. Select m5.large as the instance type, then choose your key pair and the security group described in Prerequisites.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=comentario}]'

First boot takes well under a minute after the instance is running.

2

Connect to your instance

Version SSH user

Comentario 3.19.0 on Ubuntu 24.04 ubuntu

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

First boot sets the owner password, the signing key and the certificate, and creates the owner account. Then Comentario and nginx start:

systemctl is-active nginx comentario postgresql@16-main comentario-firstboot
sudo test -f /var/lib/sac/data/comentario-firstboot.done && echo FIRSTBOOT_DONE

Confirm that all four units are active and that the first-boot marker is present:

active active active active FIRSTBOOT_DONE

Only SSH and nginx listen on network ports. Comentario and PostgreSQL listen on the loopback address:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:5432 users:(("postgres")) 127.0.0.1:8080 users:(("comentario")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))
4

Get your URL and password

Read the credentials file to find your sign-in URL and the owner password:

sudo cat /root/comentario-credentials.txt

The file is readable by root only:

# Comentario 3.19.0 - generated on first boot by comentario-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. comentario.url=https://<public-ip>/ comentario.owner.email=admin@comentario.local comentario.owner.pass=<COMENTARIO_OWNER_PASSWORD> comentario.db.name=comentario comentario.db.user=comentario
# Sign in at https://<public-ip>/en/auth/login with the owner email and password above. The owner is the
# instance superuser. The certificate is self signed (minted on this instance): accept the browser warning
# once, or install your own. Port 80 redirects to https. Change the name Comentario is served as:
#
sudo comentario-set-hostname <your-dns-name>
# Sign-up in the Administration UI is OFF; turn it on under Administration > Configuration if you want it.
# PostgreSQL listens on 127.0.0.1:5432 only, and there is no database password: no PostgreSQL role has one,
# and Comentario signs in over the local socket /var/run/postgresql as the OS user comentario (peer authentication).
# User guide: https://secureanycloud.com/stacks/comentario-3-19-0/

The URL uses the instance's public IP address from the EC2 instance metadata. The certificate also names the public DNS name and the private IP address. If you stop and start the instance without an Elastic IP, the boot service picks up the new address, issues a new certificate for it and updates Comentario's base URL. Before you embed Comentario in a site, serve it under your own DNS name (see Step 7).

5

Sign in

Open the URL from the credentials file in your browser. Your browser warns once about the self-signed certificate. Accept the warning, or install your own certificate (Step 7). Sign in with the owner email admin@comentario.local and the password from the credentials file. The Sign up here link on the sign-in page leads to a Sign-up closed page until you switch registration on.

You land on the dashboard, which summarises users, page views and comments over the last 30 days. The navigation on the left gives you Domains, Users, the Audit log, Configuration and your account. Open your account (Instance Owner) to set your own email address and display name and to change the password.

6

Add your site and embed the comments

Choose Domains > New domain, enter the host of the website you want comments on (for example blog.example.com) and a name, and select Create. The domain page shows the snippet to paste into every page that should carry a comment thread:

<script defer src="https://<your-comentario-host>/comentario.js"></script> <comentario-comments></comentario-comments>

Comentario renders a thread per page URL. Under the domain you moderate Comments, see Pages and Statistics, manage Domain users (moderators) and decide which commenter registration methods are allowed (Edit settings > Authentication): anonymous comments, local accounts or single sign-on. Webhooks on the domain page post comment events to a URL you choose. By default, Comentario accepts only https:// targets on public addresses. Federated sign-in (GitHub, GitLab, Google and others) needs the provider's keys in /etc/comentario/secrets.yaml. No provider keys are configured on this image.

Administration > Configuration > Dynamic holds the instance settings. Enable registration of new users is off on this image; switch it on only if you want anyone to be able to create an account in the Administration UI.

The Audit log records sign-ins (including failed ones), domain and user changes and other administrative actions, with who did them and when; use Filter to narrow it down.

Set up outbound email (an smtpServer block in /etc/comentario/secrets.yaml, then sudo systemctl restart comentario) so that password resets and reply notifications reach your users.

7

Use your own DNS name and certificate

Point a DNS record at the instance (an Elastic IP keeps the address stable). Then set the name that Comentario is served as. This command creates a new self-signed certificate for the name, updates nginx and Comentario's base URL (used in the embed snippet, in links and for its origin checks), the URL in /root/comentario-credentials.txt, and keeps the name across reboots:

sudo comentario-set-hostname <your-domain>

Your sites load the widget from this name, so browsers must trust its certificate. Install a certificate from a public certificate authority (for example, one issued by Let's Encrypt for <your-domain>) over the generated pair and reload nginx (running comentario-set-hostname again replaces it with a self-signed one):

sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/comentario.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/comentario.key
sudo nginx -t && sudo systemctl reload nginx
8

Run the security checks

The bundled security check runs a complete round trip. It signs in as the owner over HTTPS with this instance's password, confirms that a wrong, blank and common password are each refused, and reads the signed-in user. It confirms that the Administration UI refuses a sign-up and that a sign-in from another site's origin is refused. It also checks PostgreSQL: no role has a password, the comentario operating system user signs in as the comentario database user over the local socket, any other operating system user is refused as comentario, and a sign-in over TCP is refused. Credentials are passed to curl and psql in root-only temporary files, never on a command line:

sudo bash /usr/local/sbin/comentario-cred-roundtrip.sh
OK per-instance owner signs in over HTTPS (200, superuser); wrong/blank/default passwords refused (401 invalid-credentials); GET /api/user; UI sign-up refused (403 signups-forbidden); cross-origin login refused (403 by the cross-origin check); PostgreSQL: no role has a password, comentario signs in over the local socket (peer), other OS users and TCP logins refused

No PostgreSQL role has a password, and Comentario's database sessions arrive over the local socket, not over TCP:

sudo -u postgres psql -tAc "SELECT count(*) FROM pg_authid WHERE rolpassword IS NOT NULL"
sudo -u postgres psql -tAc "SELECT DISTINCT usename, coalesce(host(client_addr), 'local socket') FROM pg_stat_activity WHERE usename = 'comentario'"
0 comentario|local socket

The running instance reports its version, its configured base URL and the closed sign-up settings:

curl -s -H 'Host: localhost' http://127.0.0.1:8080/api/config | jq -c '{version: .staticConfig.version, baseUrl: .staticConfig.baseUrl, signup: (.dynamicConfig | map(select(.key=="auth.signup.enabled" or .key=="operation.newOwner.enabled")) | sort_by(.key) | map({(.key): .value}) | add)}'
{"version":"3.19.0","baseUrl":"https://<public-ip>/","signup":{"auth.signup.enabled":"false","operation.newOwner.enabled":"false"}}

Every service is denied the instance metadata service (and Azure's equivalent address), so a URL that Comentario is asked to fetch can never reach your instance credentials:

for u in comentario nginx postgresql@16-main comentario-firstboot; do printf '%s: %s\n' "$u" "$(systemctl show -p IPAddressDeny --value $u.service | tr ' ' '\n' | sort | xargs)"; done
comentario: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 nginx: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 postgresql@16-main: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 comentario-firstboot: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

The block also holds inside the running service. The following command joins a shell to Comentario's control group and tries to reach the metadata service from there (000 means the connection was refused):

CG=$(systemctl show -p ControlGroup --value comentario.service)
sudo bash -c "echo \$\$ > /sys/fs/cgroup$CG/cgroup.procs; curl -s -m 5 -o /dev/null -w 'metadata from the comentario service: %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token; true"
metadata from the comentario service: 000

Comentario 3.19.0 checks every state-changing request against its own origin (https:// plus the configured host) and refuses requests from other sites. This replaced the cross-site request forgery library used in Comentario 3.17 and earlier (CVE-2025-47909). In front of it, nginx also refuses any state-changing request from a plain http:// or null origin before it reaches the Administration UI's API, and accepts WebSocket upgrades only on the embed live-update channel. The first request below comes from another site and is refused by Comentario. The second comes from the plain http:// form of the instance's own host and is refused by nginx:

H=$(sudo sed -n 's#^comentario.url=https://\([^/]*\)/#\1#p' /root/comentario-credentials.txt)
curl -sk --resolve "$H:443:127.0.0.1" -H 'Origin: https://other-site.example' -H 'Content-Type: application/json' -d '{}' "https://$H/api/auth/login" | jq -r .id
curl -sk --resolve "$H:443:127.0.0.1" -H "Origin: http://$H" -H 'Content-Type: application/json' -d '{}' "https://$H/api/auth/login"
xsrf-check-failed sac: state-changing request from a plain-http origin refused
9

Versions and the command line

dpkg-query -W -f='${Package} ${Version}\n' comentario nginx postgresql-16 id comentario cat /etc/sac/comentario-release.txt
comentario 3.19.0 nginx 1.24.0-2ubuntu7.18 postgresql-16 16.15-0ubuntu0.24.04.1 uid=997(comentario) gid=987(comentario) groups=987(comentario) sac: Comentario 3.19.0 (MIT) from gitlab.com/comentario/comentario (package registry), .deb sha256 455b501078da9207d3b8cfa7fae6d4159dc687c312431c9511ac35720e37f9ec; LICENSE sha256 ce3b8dc149745f4095607f25888dd7dd6cd1e585d8761208469bb88ec97cfed9.

Package versions change as Ubuntu publishes security updates. These files matter most:

  • /etc/comentario/comentario.conf: listen address (127.0.0.1:8080), BASE_URL (set by comentario-set-hostname) and other static settings; see the static configuration reference.
  • /etc/comentario/secrets.yaml (owner comentario, mode 0600): the server signing key (serverSigningKey), SMTP and identity provider keys, and the PostgreSQL block. Its password: line is a fixed marker, not a credential: Comentario requires the field, but the database never asks for it.
  • /etc/comentario/pg_service.conf: the PostgreSQL connection Comentario actually uses (the local socket /var/run/postgresql, database and user comentario), selected by PGSERVICEFILE and PGSERVICE in comentario.conf.
  • /etc/nginx/sites-available/sac-comentario and /etc/nginx/ssl/: the HTTPS front end and its certificate.
  • journalctl -u comentario shows Comentario's log; restart it with sudo systemctl restart comentario.
10

Changing passwords

Change the owner password in the Administration UI on your account page (Instance Owner), and give each person who manages domains their own account under Users.

There is no database password to change: Comentario signs in to PostgreSQL over the local socket as the operating system user comentario (peer authentication), so only processes running as that user can use its database role, and PostgreSQL refuses every sign-in over TCP because no role has a password. If you move the database to another server, give the role a password there and replace the PostgreSQL block in /etc/comentario/secrets.yaml (and remove the PGSERVICE lines from comentario.conf).

11

Backup and maintenance

All of Comentario's state (domains, pages, users, comments and settings) is in the comentario PostgreSQL database. Back it up regularly and copy the dump off the instance (for example to Amazon S3):

sudo -u postgres pg_dump -Fc comentario > <backup-dir>/comentario-$(date +%F).dump

Also keep a copy of /etc/comentario/secrets.yaml: the server signing key in it signs email-change confirmations. Ubuntu security updates install automatically. To upgrade Comentario, take a backup, install a newer release package from the Comentario releases, and restart the service. Database migrations run on start. The Administration UI shows a notice when a newer release is available.

12

Security recommendations

  • Serve Comentario under your own DNS name with a publicly trusted certificate before embedding it (Step 7), and keep the security group to 22 from your admin network plus 80 and 443.
  • Set your own email address on the owner account and configure outbound email, so password resets work.
  • Leave Enable registration of new users off unless you need open registration, and choose the commenter sign up methods per domain.
  • Take regular database backups and test a restore.

Support and licensing

Comentario is open source software released under the MIT License (copyright Dmitry Kann and Commento, Inc.); the licence text is installed at /usr/share/doc/comentario/LICENSE. SecureAnyCloud provides 24/7 technical support for this image by email and live chat: sales@secureanycloud.com. For Comentario itself, see the documentation.

Comentario is a trademark of its respective owner. SecureAnyCloud is not affiliated with or endorsed by the Comentario project. All other product names are trademarks of their respective owners.

Deploy on AWS

Launch Comentario 3.19.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS