Ar
Applications Azure

Artalk on Ubuntu 24.04 on Azure User Guide

| Product: Artalk on Ubuntu 24.04 LTS on Azure

Overview

Artalk is a lightweight, self hosted comment system: a privacy respecting alternative to hosted commenting services. A single self contained Go binary serves three things at once, an embeddable comment widget you drop into any page, a REST API for the comments themselves, and a full administration sidebar for moderating threads and managing sites. Comments live in an embedded SQLite database, so there is no separate database server to run. The cloudimg image runs Artalk as a dedicated non root service user bound to loopback, with nginx as the public listener on port 80, and generates a unique administrator login on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • Artalk 2.10.0 as a single self contained Go binary at /usr/local/bin/artalk, with the admin sidebar and the comment widget compiled into it
  • nginx on :80 as the sole public listener, reverse proxying to Artalk on 127.0.0.1:23366
  • An embedded SQLite database at /var/lib/artalk/data/artalk.db, owned by the artalk service user and not world readable
  • A per VM administrator account and JWT signing key generated at first boot, written to a root only file. The image ships with no database at all, so it contains no account to sign in as
  • artalk.service, artalk-firstboot.service and nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Key facts:

Item Value
Default SSH user azureuser
Public port 80/tcp (nginx)
Application port 127.0.0.1:23366 (loopback only)
Admin sidebar http://<vm-public-ip>/sidebar/
Configuration /etc/artalk/artalk.yml
Data directory /var/lib/artalk
Credentials file /root/artalk-credentials.txt

Prerequisites

  1. An active Azure subscription with permission to create virtual machines.
  2. An SSH key pair for the azureuser account.
  3. A virtual network and subnet in your target region.
  4. A network security group that allows 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks that will load your comment widget and reach the admin sidebar.

Recommended VM size: Standard_B2s (2 vCPU / 4 GiB RAM). Artalk is a single Go process with an embedded database and is comfortable at this size for a typical blog or documentation site.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Artalk by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create.

First boot initialisation, which generates the JWT signing key, resolves this VM's site URL and creates the administrator account, completes within about a minute of the VM starting. The public listener stays closed until it has finished, so a connection refused in the first minute simply means bootstrap is still running.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name artalk \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name artalk --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

If you need the address, az vm show --show-details --resource-group <your-rg> --name artalk --query publicIps -o tsv prints it.

Step 4 - Confirm the services are running

systemctl is-active artalk.service nginx.service
artalk --version
curl -s -o /dev/null -w 'instance config: HTTP %{http_code}\n' http://127.0.0.1/api/v2/conf
curl -s -o /dev/null -w 'admin sidebar: HTTP %{http_code}\n' -L http://127.0.0.1/sidebar/

Both units report active, artalk --version prints Artalk (v2.10.0), and both HTTP checks return 200. That confirms Artalk is serving and nginx is proxying to it.

Artalk service status, version and health checks

Step 5 - Retrieve your administrator login

Every VM generates its own administrator password on first boot and writes it to a root only file. Nothing is shared between deployments.

sudo cat /root/artalk-credentials.txt
sudo stat -c '%a %U:%G %n' /root/artalk-credentials.txt

The file lists the sidebar URL, the administrator name and email, and the password. It is mode 600 and owned by root, so only a user with sudo can read it.

The per VM administrator credentials written by artalk-firstboot.service

Step 6 - Sign in to the admin sidebar

Open http://<vm-public-ip>/sidebar/ in a browser. Enter the artalk.admin.email and artalk.admin.pass values from Step 5 and select Login.

The Artalk admin sidebar sign in page

Step 7 - Moderate comments

The Comment view is where every comment across every site you host lands. All, Pending and Personal tabs filter the queue, and each comment carries inline Reply, Collapse, Approve, Pin, Edit and Delete actions. Replies render nested under the comment they answer, so a thread reads the same way here as it does on your page.

The Artalk comment moderation view showing a live thread

Step 8 - Review your site

The Site view lists every site this instance serves comments for. The image creates one site called My Site on first boot and sets its URL to this VM's own address, which Artalk uses as the CORS allow list entry for the comment widget. Use the + button to add another site, and select a site to edit its name or URL.

The Artalk site management view

When you point a real domain at this VM, update the site URL here and add the same origin to trusted_domains in /etc/artalk/artalk.yml, then restart the service:

sudo sed -i 's|^trusted_domains: .*|trusted_domains: ["https://<your-domain>"]|' /etc/artalk/artalk.yml
sudo systemctl restart artalk.service

Step 9 - Embed the comment widget on your site

Add these three lines to any page you want comments on. server is your Artalk VM, site matches the site name from Step 8, and pageKey identifies the page the thread belongs to.

<link href="http://<vm-public-ip>/dist/Artalk.css" rel="stylesheet" />
<script src="http://<vm-public-ip>/dist/Artalk.js"></script>
<div id="artalk"></div>
<script>
  Artalk.init({
    el: '#artalk',
    server: 'http://<vm-public-ip>',
    site: 'My Site',
    pageKey: '/blog/hello-artalk/',
    pageTitle: 'Hello Artalk'
  })
</script>

Both widget assets are served straight from the Artalk binary, so there is no CDN to depend on and no build step:

curl -s -o /dev/null -w 'Artalk.js:  HTTP %{http_code}  %{content_type}\n' http://127.0.0.1/dist/Artalk.js
curl -s -o /dev/null -w 'Artalk.css: HTTP %{http_code}  %{content_type}\n' http://127.0.0.1/dist/Artalk.css

Readers get a comment box with a Markdown editor, live preview, emoticons and image attachment, and the thread renders underneath with nested replies and voting.

The Artalk comment widget embedded on a page, showing a live thread

Step 10 - Prove the administrator login through the API

Artalk exposes the same REST API the sidebar uses. This exchanges your per VM credentials for a JWT and then calls an administrator only endpoint with it.

TOKEN=$(curl -s -H 'Content-Type: application/json' \
  -d '{"name":"<ARTALK_ADMIN_NAME>","email":"<ARTALK_ADMIN_EMAIL>","password":"<ARTALK_ADMIN_PASSWORD>"}' \
  http://127.0.0.1/api/v2/user/access_token | python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])')
echo "token length: ${#TOKEN}"
curl -s -o /dev/null -w 'admin sites API with token:    HTTP %{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" http://127.0.0.1/api/v2/sites
curl -s -o /dev/null -w 'admin sites API anonymously:   HTTP %{http_code}\n' \
  http://127.0.0.1/api/v2/sites 2>/dev/null

The token is roughly 144 characters, the authenticated call returns 200, and the anonymous call does not. Use the same bearer token for any other administrator endpoint; the full API is documented at http://<vm-public-ip>/swagger/index.html.

Step 11 - Confirm the runtime and security posture

ss -tln | grep -E ':(80|23366) '
ls -l /var/lib/artalk/data/artalk.db
sudo apt-mark showhold
echo "pending package upgrades: $(sudo apt-get -s -o APT::Get::Always-Include-Phased-Updates=true dist-upgrade 2>/dev/null | grep -c '^Inst ')"
grep -E '^(site_url|trusted_domains|admin_users):' /etc/artalk/artalk.yml

Artalk listens on 127.0.0.1:23366 only, so the application is reachable exclusively through nginx on :80. The SQLite database is mode 640 owned by artalk, because it holds bcrypt password hashes. There are no held packages and no pending upgrades. site_url and trusted_domains carry this VM's own address rather than a baked in placeholder, and admin_users is empty because the administrator lives in the database as a bcrypt hash, not in the configuration file as plain text.

Listening ports, file modes, patch state and the account inventory

Managing the service

systemctl status artalk.service --no-pager | head -n 6

Standard systemd verbs apply. Restart Artalk after any configuration change:

sudo systemctl restart artalk.service
sudo journalctl -u artalk.service -f

Application logs are also written to /var/lib/artalk/data/artalk.log.

Configuration reference

/etc/artalk/artalk.yml is the single configuration file. The full upstream reference, with every option annotated, ships at /usr/share/doc/artalk/artalk.reference.yml. Values worth knowing:

Key Shipped value Notes
host / port 127.0.0.1 / 23366 Loopback only. nginx is the public listener
app_key per VM 64 hex JWT signing key generated at first boot
site_default / site_url My Site / this VM The default site and its URL
trusted_domains this VM CORS allow list for sites embedding the widget
db.type / db.file sqlite / ./data/artalk.db Relative to /var/lib/artalk
captcha.enabled true Image captcha after action_limit actions
img_upload.enabled true Image attachments, 5 MB cap
email.enabled false Set your own SMTP relay to enable notifications
auth.enabled false Social sign in providers, all disabled with empty secrets

Enabling HTTPS

Comment widgets are loaded by browsers on your own pages, so serving Artalk over HTTPS is strongly recommended. Point a DNS record at the VM, open 443/tcp in the network security group, then:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

Certbot rewrites the nginx vhost at /etc/nginx/sites-available/artalk in place, keeping the proxy buffer settings. Afterwards update site_url and trusted_domains in /etc/artalk/artalk.yml to the https:// origin and restart Artalk, then change the server value in your embed snippet to match.

Backup and maintenance

Everything that matters is the SQLite database plus the configuration file:

sudo systemctl stop artalk.service
sudo tar czf artalk-backup-$(date +%F).tar.gz /var/lib/artalk/data /etc/artalk/artalk.yml
sudo systemctl start artalk.service

Artalk also has a built in exporter under Transfer in the sidebar, which produces a JSON dump you can re import into another instance.

Operating system security updates are applied automatically by unattended-upgrades. To move to a newer Artalk release, replace /usr/local/bin/artalk with the new release binary and restart the service; the database schema migrates automatically on start.

Troubleshooting

Symptom Cause and fix
Connection refused on :80 in the first minute First boot bootstrap has not finished. artalk.service and nginx.service deliberately do not start until artalk-firstboot.service has created the administrator. Check with systemctl status artalk-firstboot.service
HTTP 403 with need_captcha when signing in Artalk's action limiter allows captcha.action_limit (3) actions per client IP inside captcha.action_reset (60 s), then requires a captcha. This is the built in abuse control for anonymous commenting. Wait a minute, or complete the captcha the sidebar shows
HTTP 401 signing in Wrong password. Re read /root/artalk-credentials.txt; the password is unique to this VM
Comments do not appear on your own page The page origin is not in the site URL or trusted_domains, so the browser blocks the cross origin request. Add it in the Site view and in /etc/artalk/artalk.yml, then restart
502 Bad Gateway from nginx Artalk is not running. sudo journalctl -u artalk.service -n 50 --no-pager
Signed out after a restart Only happens if app_key was blanked. It is set per VM at first boot; check grep '^app_key:' /etc/artalk/artalk.yml is not empty

Useful diagnostics:

systemctl is-active artalk-firstboot.service
sudo journalctl -u artalk-firstboot.service --no-pager | tail -n 12

Security recommendations

  1. Restrict SSH. Limit 22/tcp in the network security group to your management network.
  2. Enable HTTPS before publishing the widget, so reader comments are not sent in clear text.
  3. Keep the credentials file safe. /root/artalk-credentials.txt is mode 600; change the administrator password from the sidebar and delete the file once you have stored it in your password manager.
  4. Leave the captcha enabled. captcha.enabled is Artalk's abuse control for anonymous commenting and image upload. If you prefer a hosted challenge, switch captcha.captcha_type to turnstile, recaptcha or hcaptcha and add the corresponding keys.
  5. Review image upload. img_upload.enabled is on with a 5 MB cap so readers can attach images. Set it to false if you do not want anonymous uploads.
  6. Moderate before publishing by setting moderator.pending_default: true, which holds every new comment for approval.

Support

cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with your Azure subscription ID and the VM name. For questions about Artalk itself, the upstream documentation is at artalk.js.org.