Artalk
Overview
Artalk is a lightweight, self-hosted comment system and a privacy-respecting alternative to hosted commenting services. A single self-contained Go binary serves an embeddable comment widget, a REST API and an administration sidebar for moderating threads and managing sites. Comments live in an embedded SQLite database, so there is no separate database server to run.
This SecureAnyCloud image runs Artalk as a dedicated non-root service user bound to loopback, with nginx as the public listener on port 80. It generates a unique administrator login on the first boot of every VM.
What you get:
- 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
:80as the sole public listener, reverse proxying to Artalk on127.0.0.1:23366 - An embedded SQLite database at
/var/lib/artalk/data/artalk.db, owned by theartalkservice user and not world-readable - A per-VM administrator account and JWT signing key generated at first boot and written to a root-only file. The image ships with no database, so it contains no account to sign in as
artalk.service,artalk-firstboot.serviceandnginx.serviceas enabled, active systemd units- 24/7 SecureAnyCloud support
Key facts:
- 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
- An active Azure subscription with permission to create virtual machines
- An SSH key pair for the
azureuseraccount - A virtual network and subnet in your target region
- A network security group (NSG) that allows
22/tcpfrom your management network, and80/tcp(plus443/tcponce you enable HTTPS) from the networks that 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 this size is comfortable 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 SecureAnyCloud, and select Create.
On the Basics tab, 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 select Review + create and Create.
First-boot initialisation generates the JWT signing key, resolves this VM's site URL and creates the administrator account. It completes within about a minute of the VM starting. The public listener stays closed until it finishes, so a connection refused in the first minute means bootstrap is still running.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:artalk-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name artalk \
--image sac1647283583153:artalk-ubuntu-24-04:default:latest \
--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 1010Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>To look up the VM address, run az vm show --show-details --resource-group <your-rg> --name artalk --query publicIps -o tsv.
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. This confirms that Artalk is serving and nginx is proxying to it.
Step 5 - Retrieve your administrator login
Each VM generates its own administrator password on first boot and writes it to a root-only file. Nothing is shared between deployments. Read the file and check its permissions:
sudo cat /root/artalk-credentials.txt
sudo stat -c '%a %U:%G %n' /root/artalk-credentials.txtThe 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.
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.
Step 7 - Moderate comments
Open the Comment view to see every comment from every site you host. Use the All, Pending and Personal tabs to filter the queue.
Each comment has inline Reply, Collapse, Approve, Pin, Edit and Delete actions. Replies are nested under the comment they answer, so a thread reads the same way here as on your page.
Step 8 - Review your site
Open the Site view to see every site this instance serves comments for. On first boot the image creates one site called My Site and sets its URL to this VM's own address. Artalk uses that address as the CORS allow-list entry for the comment widget.
Select the + button to add another site, or select a site to edit its name or URL.
When you point a real domain at this VM, update the site URL here. Then add the same origin to trusted_domains in /etc/artalk/artalk.yml and restart the service:
sudo sed -i 's|^trusted_domains: .*|trusted_domains: ["https://<your-domain>"]|' /etc/artalk/artalk.yml
sudo systemctl restart artalk.serviceStep 9 - Embed the comment widget on your site
Add the following snippet to any page that should have comments. Set server to your Artalk VM, set site to the site name from Step 8, and set pageKey to the identifier of 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 directly from the Artalk binary, so there is no CDN dependency and no build step. Confirm that they load:
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.cssReaders see a comment box with a Markdown editor, live preview, emoticons and image attachment. The thread renders underneath with nested replies and voting.
Step 10 - Verify the administrator login through the API
Artalk exposes the same REST API that the sidebar uses. Exchange your per-VM credentials for a JWT, then call 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/nullThe 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.ymlArtalk listens on 127.0.0.1:23366 only, so the application is reachable solely through nginx on :80. The SQLite database is mode 640 and 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. admin_users is empty because the administrator lives in the database as a bcrypt hash, not in the configuration file as plain text.
Managing the service
systemctl status artalk.service --no-pager | head -n 6Use standard systemd commands to manage the service. Restart Artalk after any configuration change:
sudo systemctl restart artalk.service
sudo journalctl -u artalk.service -fApplication 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. The key settings and their shipped values are:
- host / port: 127.0.0.1 / 23366. Loopback only; nginx is the public listener.
- app_key: per VM, 64 hex characters. The 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. The CORS allow list for sites that embed 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 are all disabled, with empty secrets.
Enabling HTTPS
Browsers load the comment widget on your own pages, so serve Artalk over HTTPS. Point a DNS record at the VM, open 443/tcp in the network security group, then install a certificate:
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 and keeps the proxy buffer settings. Then update site_url and trusted_domains in /etc/artalk/artalk.yml to the https:// origin and restart Artalk. Finally, change the server value in your embed snippet to match.
Backup and maintenance
Your data is the SQLite database plus the configuration file. Back up both:
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.serviceArtalk also has a built-in exporter under Transfer in the sidebar. It produces a JSON dump that 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
- 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 that the sidebar shows.
- HTTP 401 when signing in. The password is wrong. Re-read /root/artalk-credentials.txt, because 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. Run sudo journalctl -u artalk.service -n 50 --no-pager.
- Signed out after a restart. This happens only if app_key was blanked. It is set per VM at first boot. Check that grep '^app_key:' /etc/artalk/artalk.yml is not empty.
Use these commands for further diagnostics:
systemctl is-active artalk-firstboot.service
sudo journalctl -u artalk-firstboot.service --no-pager | tail -n 12Security notes
- Restrict SSH. Limit
22/tcpin the network security group to your management network. - Enable HTTPS. Do this before you publish the widget, so reader comments are not sent in clear text.
- Keep the credentials file safe.
/root/artalk-credentials.txtis mode600. Change the administrator password from the sidebar, then delete the file once you have stored the password in your password manager. - Leave the captcha enabled.
captcha.enabledis Artalk's abuse control for anonymous commenting and image upload. If you prefer a hosted challenge, switchcaptcha.captcha_typetoturnstile,recaptchaorhcaptchaand add the corresponding keys. - Review image upload.
img_upload.enabledis on with a 5 MB cap so readers can attach images. Set it tofalseto disallow anonymous uploads. - Moderate before publishing. Set
moderator.pending_default: trueto hold every new comment for approval.
Support
SecureAnyCloud provides 24/7 support for this image. Contact sales@secureanycloud.com with your Azure subscription ID and the VM name. For questions about Artalk itself, see the upstream documentation at artalk.js.org.
Deploy on Azure
Launch Artalk on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com