Privacy-First
Self-hosted solution keeps your comment data under your control, with no third-party tracking or data collection.
Artalk is an intuitive yet feature-rich self-hosted comment system designed for blogs, websites, and web applications. Built with a lightweight ~40KB Vanilla JS client and a high-performance Golang backend, Artalk offers a privacy-first alternative to third-party comment platforms like Disqus. With multi-site management, social login integration, email notifications, and comprehensive moderation tools, Artalk provides everything you need to foster engaging discussions on your website.
Whether you’re running a personal blog, documentation site, or multi-author publication, Artalk delivers a seamless commenting experience while keeping your data under your control. This guide walks you through deploying Artalk on Klutch.sh using Docker.
Privacy-First
Self-hosted solution keeps your comment data under your control, with no third-party tracking or data collection.
Lightweight Client
~40KB client built with pure Vanilla JS, framework-agnostic and blazing fast to load.
Multi-Site Support
Manage comments for multiple websites from a single Artalk instance with isolated data per site.
Rich Features
Email notifications, social login, captcha, spam moderation, Markdown support, emoji packs, and more.
Before deploying Artalk on Klutch.sh, ensure you have the following:
Artalk offers a comprehensive set of features for comment management:
Create a Dockerfile in your project root that uses the official Artalk Docker image:
FROM artalk/artalk-go:latest
# Set environment variablesENV ATK_HOST=0.0.0.0ENV ATK_PORT=23366ENV TZ=UTCENV ATK_LOCALE=en
# Data directory for persistent storageVOLUME ["/data"]
# Expose the default Artalk portEXPOSE 23366
# The base image handles startupCMD ["artalk", "server"]Artalk supports extensive configuration through environment variables prefixed with ATK_. Configure these in the Klutch.sh dashboard:
| Variable | Description | Default |
|---|---|---|
ATK_APP_KEY | Secret key for JWT token generation (required for security) | None |
ATK_LOCALE | Language code (en, zh-CN, zh-TW, ja, fr, ko, ru) | en |
ATK_TIMEZONE | IANA timezone (e.g., America/New_York) | Asia/Shanghai |
ATK_SITE_DEFAULT | Default site name | Default Site |
ATK_SITE_URL | Default site URL | None |
TZ | Container timezone | UTC |
| Variable | Description | Default |
|---|---|---|
ATK_HOST | Listen host address | 0.0.0.0 |
ATK_PORT | Listen port | 23366 |
ATK_DEBUG | Enable debug mode | false |
ATK_TRUSTED_DOMAINS | Allowed domains (space-separated) | None |
ATK_LOGIN_TIMEOUT | Login session timeout (seconds) | 259200 |
| Variable | Description | Default |
|---|---|---|
ATK_DB_TYPE | Database type (sqlite, mysql, pgsql, mssql) | sqlite |
ATK_DB_FILE | SQLite database file path | ./data/artalk.db |
ATK_DB_HOST | Database host (MySQL/PostgreSQL) | localhost |
ATK_DB_PORT | Database port | 3306 |
ATK_DB_NAME | Database name | artalk |
ATK_DB_USER | Database username | root |
ATK_DB_PASSWORD | Database password | None |
ATK_DB_CHARSET | Database character set | utf8mb4 |
ATK_DB_TABLE_PREFIX | Table name prefix | None |
| Variable | Description | Example |
|---|---|---|
ATK_ADMIN_USERS_0_NAME | Admin username | admin |
ATK_ADMIN_USERS_0_EMAIL | Admin email | admin@example.com |
ATK_ADMIN_USERS_0_PASSWORD | Admin password (bcrypt hash) | (bcrypt)$2y$10$... |
ATK_ADMIN_USERS_0_BADGE_NAME | Admin badge text | Administrator |
ATK_ADMIN_USERS_0_BADGE_COLOR | Admin badge color | #0083FF |
| Variable | Description | Default |
|---|---|---|
ATK_EMAIL_ENABLED | Enable email notifications | false |
ATK_EMAIL_SEND_TYPE | Send method (smtp, ali_dm, sendmail) | smtp |
ATK_EMAIL_SEND_ADDR | Sender email address | None |
ATK_EMAIL_SEND_NAME | Sender display name | None |
ATK_EMAIL_SMTP_HOST | SMTP server host | None |
ATK_EMAIL_SMTP_PORT | SMTP server port | 587 |
ATK_EMAIL_SMTP_USERNAME | SMTP username | None |
ATK_EMAIL_SMTP_PASSWORD | SMTP password | None |
| Variable | Description | Default |
|---|---|---|
ATK_CAPTCHA_ENABLED | Enable captcha | true |
ATK_CAPTCHA_CAPTCHA_TYPE | Type (image, turnstile, recaptcha, hcaptcha, geetest) | image |
ATK_CAPTCHA_ACTION_LIMIT | Actions before captcha required | 3 |
ATK_CAPTCHA_TURNSTILE_SITE_KEY | Cloudflare Turnstile site key | None |
ATK_CAPTCHA_TURNSTILE_SECRET_KEY | Cloudflare Turnstile secret key | None |
| Variable | Description | Default |
|---|---|---|
ATK_CACHE_ENABLED | Enable caching | false |
ATK_CACHE_TYPE | Cache type (builtin, redis, memcache) | builtin |
ATK_CACHE_EXPIRES | Cache expiration (minutes) | 30 |
ATK_CACHE_SERVER | Cache server address | None |
A typical Artalk deployment repository looks like this:
artalk-deploy/├── Dockerfile├── data/│ └── .gitkeep└── README.mdFor a production-ready deployment with custom configuration:
FROM artalk/artalk-go:latest
# Core configurationENV ATK_HOST=0.0.0.0ENV ATK_PORT=23366ENV TZ=UTCENV ATK_LOCALE=enENV ATK_TIMEZONE=America/New_York
# Database configuration (SQLite for simplicity)ENV ATK_DB_TYPE=sqliteENV ATK_DB_FILE=/data/artalk.db
# Image upload configurationENV ATK_IMG_UPLOAD_ENABLED=trueENV ATK_IMG_UPLOAD_PATH=/data/artalk-img/ENV ATK_IMG_UPLOAD_MAX_SIZE=5
# Logging configurationENV ATK_LOG_ENABLED=trueENV ATK_LOG_FILENAME=/data/artalk.log
# Create data directoryRUN mkdir -p /data/artalk-img
# Volume for persistent dataVOLUME ["/data"]
# Expose the Artalk portEXPOSE 23366
CMD ["artalk", "server"]Create a GitHub repository
Create a new repository containing your Dockerfile:
mkdir artalk-deploycd artalk-deploygit initAdd the Dockerfile
Create the Dockerfile with your configuration:
touch Dockerfile# Add the Dockerfile content from abovePush to GitHub
Commit and push your repository:
git add .git commit -m "Initial Artalk deployment configuration"git branch -M maingit remote add origin https://github.com/yourusername/artalk-deploy.gitgit push -u origin mainConnect to Klutch.sh
Navigate to klutch.sh/app and sign in with your GitHub account. Click New Project to begin the deployment process.
Select your repository
Choose the GitHub repository containing your Artalk Dockerfile. Klutch.sh will automatically detect the Dockerfile in your project root.
Configure environment variables
Add the required environment variables in the Klutch.sh dashboard:
ATK_APP_KEY - Generate a random secret string for JWT securityATK_SITE_DEFAULT - Your site name (e.g., “My Blog”)ATK_SITE_URL - Your site URL (e.g., “https://myblog.com”)ATK_TRUSTED_DOMAINS - Your site domains (space-separated)TZ - Your timezone (e.g., “America/New_York”)Optional but recommended:
ATK_ADMIN_USERS_0_NAME - Admin usernameATK_ADMIN_USERS_0_EMAIL - Admin emailATK_EMAIL_ENABLED - Set to true for email notificationsSet the internal port
Configure the internal port to 23366 (Artalk’s default port).
Add persistent storage
Artalk requires persistent storage for the database, uploaded images, and logs. Add a persistent volume:
| Mount Path | Size |
|---|---|
/data | 2 GB+ |
Deploy your application
Click Deploy to start the deployment process. Once complete, your Artalk server will be accessible at https://example-app.klutch.sh.
After deploying Artalk, you need to create an administrator account. You can do this through environment variables (recommended) or via the initial setup.
Using Environment Variables (Recommended):
Add these environment variables in the Klutch.sh dashboard:
ATK_ADMIN_USERS_0_NAME=adminATK_ADMIN_USERS_0_EMAIL=admin@yourdomain.comATK_ADMIN_USERS_0_PASSWORD=(bcrypt)$2y$10$your-bcrypt-hash-hereATK_ADMIN_USERS_0_BADGE_NAME=AdministratorATK_ADMIN_USERS_0_BADGE_COLOR=#0083FFFirst-Time Access:
If you didn’t configure admin users via environment variables:
Once logged in as an admin, you can access the Dashboard by:
Add Artalk to your webpage using CDN resources:
<!DOCTYPE html><html><head> <!-- Artalk CSS --> <link href="https://example-app.klutch.sh/dist/Artalk.css" rel="stylesheet" /></head><body> <!-- Comment Container --> <div id="Comments"></div>
<!-- Artalk JS --> <script src="https://example-app.klutch.sh/dist/Artalk.js"></script> <script> Artalk.init({ el: '#Comments', // Container selector pageKey: '/post/hello-world', // Unique page identifier pageTitle: 'Hello World', // Page title server: 'https://example-app.klutch.sh', // Artalk server URL site: 'My Blog', // Site name }) </script></body></html>Install Artalk via npm:
npm install artalkImport and initialize in your JavaScript:
import 'artalk/Artalk.css'import Artalk from 'artalk'
const artalk = Artalk.init({ el: document.querySelector('#Comments'), pageKey: window.location.pathname, pageTitle: document.title, server: 'https://example-app.klutch.sh', site: 'My Blog',})import { useEffect, useRef } from 'react'import 'artalk/Artalk.css'import Artalk from 'artalk'
function Comments() { const containerRef = useRef(null) const artalkRef = useRef(null)
useEffect(() => { artalkRef.current = Artalk.init({ el: containerRef.current, pageKey: window.location.pathname, pageTitle: document.title, server: 'https://example-app.klutch.sh', site: 'My Blog', })
return () => { artalkRef.current?.destroy() } }, [])
return <div ref={containerRef} />}
export default Comments<template> <div ref="artalkContainer"></div></template>
<script setup>import { ref, onMounted, onUnmounted } from 'vue'import 'artalk/Artalk.css'import Artalk from 'artalk'
const artalkContainer = ref(null)let artalk = null
onMounted(() => { artalk = Artalk.init({ el: artalkContainer.value, pageKey: window.location.pathname, pageTitle: document.title, server: 'https://example-app.klutch.sh', site: 'My Blog', })})
onUnmounted(() => { artalk?.destroy()})</script><div id="Comments"></div>
<link rel="stylesheet" href="https://example-app.klutch.sh/dist/Artalk.css" /><script is:inline src="https://example-app.klutch.sh/dist/Artalk.js"></script><script is:inline> Artalk.init({ el: '#Comments', pageKey: window.location.pathname, pageTitle: document.title, server: 'https://example-app.klutch.sh', site: 'My Blog', })</script>Customize the Artalk client behavior:
Artalk.init({ // Required el: '#Comments', server: 'https://example-app.klutch.sh', site: 'My Blog',
// Page identification pageKey: '/post/hello-world', pageTitle: 'Hello World',
// UI Settings darkMode: 'auto', // 'auto', 'light', 'dark' locale: 'en', // Language placeholder: 'Leave a comment...', // Input placeholder
// Features emoticons: 'https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json', gravatar: { mirror: 'https://www.gravatar.com/avatar/', params: 'sha256=1&d=mp&s=240', },
// Comment display nestMax: 2, // Max nesting depth nestSort: 'DATE_ASC', // Nested sort order flatMode: false, // Flat or nested view pagination: { pageSize: 20, // Comments per page readMore: true, // Load more button autoLoad: true, // Auto-load on scroll },
// Features toggles vote: true, // Enable voting voteDown: false, // Enable downvotes preview: true, // Real-time preview editorTravel: true, // Movable editor imgLazyLoad: true, // Lazy load images})SQLite is perfect for small to medium sites and requires no external database:
ATK_DB_TYPE=sqliteATK_DB_FILE=/data/artalk.dbFor larger deployments, configure an external PostgreSQL database:
ATK_DB_TYPE=pgsqlATK_DB_HOST=your-postgres-host.example.comATK_DB_PORT=5432ATK_DB_NAME=artalkATK_DB_USER=artalkATK_DB_PASSWORD=your-secure-passwordFor MySQL/MariaDB databases:
ATK_DB_TYPE=mysqlATK_DB_HOST=your-mysql-host.example.comATK_DB_PORT=3306ATK_DB_NAME=artalkATK_DB_USER=artalkATK_DB_PASSWORD=your-secure-passwordATK_DB_CHARSET=utf8mb4Enable email notifications to alert users when they receive replies:
ATK_EMAIL_ENABLED=trueATK_EMAIL_SEND_TYPE=smtpATK_EMAIL_SEND_NAME=Artalk NotificationsATK_EMAIL_SEND_ADDR=noreply@yourdomain.comATK_EMAIL_SMTP_HOST=smtp.yourdomain.comATK_EMAIL_SMTP_PORT=587ATK_EMAIL_SMTP_USERNAME=noreply@yourdomain.comATK_EMAIL_SMTP_PASSWORD=your-smtp-passwordAllow users to sign in with their social accounts:
ATK_AUTH_ENABLED=trueATK_AUTH_CALLBACK=https://example-app.klutch.sh/api/v2/auth/{provider}/callback
# GitHub OAuthATK_AUTH_GITHUB_ENABLED=trueATK_AUTH_GITHUB_CLIENT_ID=your-github-client-idATK_AUTH_GITHUB_CLIENT_SECRET=your-github-client-secret
# Google OAuthATK_AUTH_GOOGLE_ENABLED=trueATK_AUTH_GOOGLE_CLIENT_ID=your-google-client-idATK_AUTH_GOOGLE_CLIENT_SECRET=your-google-client-secretTo use a custom domain with your Artalk deployment:
Add your domain in Klutch.sh
Navigate to your project settings and add your custom domain (e.g., comments.yourdomain.com).
Configure DNS records
Add a CNAME record pointing to your Klutch.sh deployment:
| Type | Name | Value |
|---|---|---|
| CNAME | comments | example-app.klutch.sh |
Update trusted domains
Add your custom domain to the trusted domains environment variable:
ATK_TRUSTED_DOMAINS=https://yourdomain.com https://comments.yourdomain.comUpdate client configuration
Update the server URL in your Artalk client initialization:
Artalk.init({ server: 'https://comments.yourdomain.com', // ... other options})For local development and testing:
services: artalk: container_name: artalk image: artalk/artalk-go restart: unless-stopped ports: - "8080:23366" volumes: - ./data:/data environment: - TZ=America/New_York - ATK_LOCALE=en - ATK_SITE_DEFAULT=My Blog - ATK_SITE_URL=http://localhost:8080 - ATK_APP_KEY=your-secret-key-here - ATK_TRUSTED_DOMAINS=http://localhost:3000 http://localhost:8080Start the local environment:
docker compose up -dAccess Artalk at http://localhost:8080.
Artalk supports importing comments from other platforms:
Access the migration tools from the Artalk Dashboard under the “Transfer” section.
If you see CORS errors in the browser console:
ATK_TRUSTED_DOMAINSIf Artalk fails to connect to the database:
If the comment widget shows but doesn’t load comments:
server URL in Artalk.init() is correctsite matches the configured site nameIf email notifications aren’t working:
ATK_EMAIL_ENABLED=true/data/artalk.logAfter deploying Artalk, consider: