Initial import of Hugo site to Forgejo

This commit is contained in:
Iman Alipour 2026-07-28 12:47:20 +00:00
commit cb1ba0317f
1259 changed files with 236349 additions and 0 deletions

View file

@ -0,0 +1,640 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Blog on AlipourIm journeys</title>
<link>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/categories/blog/</link>
<description>Recent content in Blog on AlipourIm journeys</description>
<generator>Hugo -- 0.146.0</generator>
<language>en</language>
<lastBuildDate>Thu, 23 Oct 2025 19:31:12 +0200</lastBuildDate>
<atom:link href="http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/categories/blog/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>New features for my blog! Adding Comments &#43; RSS to Hugo PaperMod (Giscus and Isso FTW)</title>
<link>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/comments-rss-papermod/</link>
<pubDate>Thu, 23 Oct 2025 19:31:12 +0200</pubDate>
<guid>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/comments-rss-papermod/</guid>
<description>A friendly, copy-pasteable guide to wiring up Giscus comments (GitHub Discussions) and Isso comments &#43; RSS in Hugo PaperMod.</description>
<content:encoded><![CDATA[<blockquote>
<p>Short story: I wanted comments and a proper RSS feed on my Hugo + PaperMod site.<br>
Longer story: I spent 30 minutes poking around, and now you dont have to. Heres exactly what I did.</p></blockquote>
<hr>
<p>I&rsquo;ve been wanting to add comment section to my blog for a while.
There are a few problems.</p>
<ul>
<li>I don&rsquo;t want to get attacked by bots or random people for no reason.</li>
<li>I don&rsquo;t want to allow weird things to happen.</li>
<li>I don&rsquo;t want to have a database for it.</li>
</ul>
<p>So&hellip; I decided to take a path which is not necesserially the best.
It requires a third party to act on your behalf, but it is not as scary as it sounds.
According to Github:</p>
<blockquote>
<p><strong>What the app can do</strong>
The apps rights are limited to the repo(s) where the site owner installed it and to the permissions it requested (basically: Discussions read/write + metadata). It cant touch a commenters private repos or do things outside those scopes. GitHubs docs also say a GitHub App can only do what both you and the app have permission to do.</p></blockquote>
<blockquote>
<p><strong>What “Act on your behalf” means</strong>
That scary wording is GitHubs. The giscus maintainer explains it means “post comments under your username,” and shows that the app requests Discussions read/write + metadata when installed.</p></blockquote>
<blockquote>
<p><strong>Do commenters have alternatives?</strong>
Yes. Anyone can open the linked GitHub Discussion and comment directly on GitHub, bypassing the apps OAuth popup. The README explicitly mentions this.</p></blockquote>
<blockquote>
<p><strong>Privacy &amp; storage</strong>
No tracking/ads; comments live in GitHub Discussions. giscus is open-source and has a published privacy policy. You can also revoke the app any time in your GitHub settings.</p></blockquote>
<p>With the notice out of the way let&rsquo;s dive right in!</p>
<hr>
<h2 id="why-i-chose-giscus-instead-of-disqus">Why I chose Giscus (instead of Disqus)</h2>
<ul>
<li><strong>No ads or trackers</strong> (my page weight thanks me).</li>
<li><strong>Uses GitHub Discussions</strong> (portable, transparent, easy to search).</li>
<li><strong>Readers log in with GitHub</strong> (no mystery auth popups).</li>
<li>In theory you can directly go to the repo&rsquo;s discussion section and comment there!</li>
</ul>
<hr>
<h2 id="what-you-need-for-your-site-not-per-user">What you need (for your site, not per user)</h2>
<ul>
<li>A Hugo site using <strong>PaperMod</strong></li>
<li>A GitHub account ✅</li>
<li>A <strong>public</strong> repository for the discussion threads (I called mine <code>blog-comments</code>) with <strong>Discussions</strong> enabled ✅</li>
<li>Giscus app installed on that repo ✅</li>
</ul>
<p>If you like to keep your main site repo clean, use a separate one, e.g. <code>github-username/blog-comments</code>.</p>
<hr>
<h2 id="1-turn-on-comments-with-giscus">1) Turn on comments with Giscus</h2>
<p>PaperMod renders a <code>comments.html</code> partial when <code>params.comments = true</code>.<br>
So we enable it in config and create the partial.</p>
<h3 id="11-enable-comments-globally">1.1 Enable comments globally</h3>
<p><code>hugo.toml</code> (snippet)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">params</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">comments</span> = <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>You can still opt out per post with <code>comments = false</code> in front matter.</p>
<h3 id="12-create-the-comments-partial">1.2 Create the comments partial</h3>
<p>Create this file <strong>in your site</strong> (not inside the theme):</p>
<pre tabindex="0"><code>layouts/partials/comments.html
</code></pre><p>Paste the Giscus embed (swap the placeholders with yours from giscus.app):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">section</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;comments&#34;</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;giscus&#34;</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">script</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://giscus.app/client.js&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-repo</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;yourname/blog-comments&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-repo-id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;YOUR_REPO_ID&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-category</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Comments&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-category-id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;YOUR_CATEGORY_ID&#34;</span> <span style="color:#960050;background-color:#1e0010">&lt;!</span><span style="color:#a6e22e">--</span> <span style="color:#a6e22e">Get</span> <span style="color:#a6e22e">them</span> <span style="color:#a6e22e">from</span> <span style="color:#a6e22e">Giscus</span><span style="color:#960050;background-color:#1e0010">&#39;</span><span style="color:#a6e22e">s</span> <span style="color:#a6e22e">page</span><span style="color:#960050;background-color:#1e0010">!</span> <span style="color:#a6e22e">--</span>&gt;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">mapping</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;pathname&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">strict</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;0&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">reactions</span><span style="color:#f92672">-</span><span style="color:#a6e22e">enabled</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;1&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">emit</span><span style="color:#f92672">-</span><span style="color:#a6e22e">metadata</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;0&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">input</span><span style="color:#f92672">-</span><span style="color:#a6e22e">position</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;bottom&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">theme</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;preferred_color_scheme&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">lang</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;en&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data</span><span style="color:#f92672">-</span><span style="color:#a6e22e">loading</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;lazy&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">crossorigin</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anonymous&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">async</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span> &lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">noscript</span>&gt;Enable JavaScript to view comments powered by Giscus.&lt;/<span style="color:#f92672">noscript</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">section</span>&gt;
</span></span></code></pre></div><p><strong>Notes</strong></p>
<ul>
<li>Youll get <code>repo-id</code> and <code>category-id</code> from <strong>giscus.app</strong> after picking your repo + category.</li>
<li><code>data-mapping=&quot;pathname&quot;</code> works great for static sites.</li>
<li>Prefer a <strong>public</strong> repo so visitors can read discussions without friction.</li>
<li>Want a different language? Change <code>data-lang</code> (e.g., <code>de</code>, <code>fr</code>).</li>
</ul>
<hr>
<h2 id="2-enable-rss-home--sections">2) Enable RSS (home + sections)</h2>
<p>Hugo already knows how to generate feeds; we just tell it where.</p>
<p><code>hugo.toml</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#a6e22e">baseURL</span> = <span style="color:#e6db74">&#34;https://example.com/&#34;</span> <span style="color:#75715e"># set your production URL</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">outputs</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">home</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>, <span style="color:#e6db74">&#34;JSON&#34;</span>] <span style="color:#75715e"># JSON is optional (e.g., for on-site search)</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">section</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">taxonomy</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">term</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">services</span>.<span style="color:#a6e22e">rss</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">limit</span> = <span style="color:#ae81ff">-1</span> <span style="color:#75715e"># -1 = no cap; or set e.g. 20</span>
</span></span></code></pre></div><p><strong>Feed URLs</strong></p>
<ul>
<li>Home feed: <code>/index.xml</code><code>https://example.com/index.xml</code></li>
<li>Section feeds: <code>/posts/index.xml</code>, <code>/notes/index.xml</code>, etc. (folders are lowercase)</li>
</ul>
<blockquote>
<p>If youre using a <code>.onion</code> address or staging domain, just set that in <code>baseURL</code>.<br>
Locally, Hugo serves feeds at <code>http://localhost:1313/index.xml</code>.</p></blockquote>
<hr>
<h2 id="3-show-an-rss-button-on-the-home-page">3) Show an RSS button on the home page</h2>
<p>PaperMod shows a nice RSS icon on <strong>section/taxonomy</strong> lists by default (when enabled), but not on the home page. Two options:</p>
<h3 id="option-a--use-the-home-social-icons-row">Option A — Use the home “social icons” row</h3>
<p>This appears if you enable <strong>Home-Info</strong> or <strong>Profile</strong> mode:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">params</span>.<span style="color:#a6e22e">homeInfoParams</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Title</span> = <span style="color:#e6db74">&#34;Hello, internet!&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Content</span> = <span style="color:#e6db74">&#34;Notes, experiments, and occasional rabbit holes.&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[[<span style="color:#a6e22e">params</span>.<span style="color:#a6e22e">socialIcons</span>]]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">name</span> = <span style="color:#e6db74">&#34;rss&#34;</span> <span style="color:#75715e"># lowercase matters</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">url</span> = <span style="color:#e6db74">&#34;/index.xml&#34;</span>
</span></span></code></pre></div><h3 id="option-b--add-an-icon-in-the-footer-theme-safe">Option B — Add an icon in the footer (theme-safe)</h3>
<p>Create:</p>
<pre tabindex="0"><code>layouts/partials/extend_footer.html
</code></pre><p>Paste:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/index.xml&#34;</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;alternate&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;application/rss+xml&#34;</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;RSS&#34;</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;rss-link&#34;</span>&gt;
</span></span><span style="display:flex;"><span> {{ partial &#34;svg.html&#34; (dict &#34;name&#34; &#34;rss&#34;) }}
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">span</span>&gt;RSS&lt;/<span style="color:#f92672">span</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">a</span>&gt;
</span></span></code></pre></div><p>Make it a sensible size:</p>
<p>Create:</p>
<pre tabindex="0"><code>assets/css/extended/rss.css
</code></pre><p>Paste:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#75715e">/* Small &amp; aligned RSS icon in the footer */</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">rss-link</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">inline-flex</span>; <span style="color:#66d9ef">align-items</span>: <span style="color:#66d9ef">center</span>; <span style="color:#66d9ef">gap</span>: <span style="color:#ae81ff">.35</span><span style="color:#66d9ef">rem</span>; }
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">rss-link</span> <span style="color:#f92672">svg</span> { <span style="color:#66d9ef">margin-left</span>: <span style="color:#ae81ff">10</span><span style="color:#66d9ef">px</span>; <span style="color:#66d9ef">width</span>: <span style="color:#ae81ff">18</span><span style="color:#66d9ef">px</span>; <span style="color:#66d9ef">height</span>: <span style="color:#ae81ff">18</span><span style="color:#66d9ef">px</span>; } <span style="color:#75715e">/* a bit of left margin for good measure!*/</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">rss-link</span> <span style="color:#f92672">span</span> { <span style="color:#66d9ef">font-size</span>: <span style="color:#ae81ff">.95</span><span style="color:#66d9ef">rem</span>; }
</span></span></code></pre></div><p>PaperMod auto-bundles anything under <code>assets/css/extended/</code>, so no extra imports needed.</p>
<hr>
<h2 id="4-verify-everything">4) Verify everything</h2>
<p>Build or run dev:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hugo <span style="color:#75715e"># outputs to ./public</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># or</span>
</span></span><span style="display:flex;"><span>hugo server <span style="color:#75715e"># serves at http://localhost:1313</span>
</span></span></code></pre></div><p>Check feeds:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Home feed:</span>
</span></span><span style="display:flex;"><span>curl -s http://localhost:1313/index.xml | head
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># A section feed (adjust path to your section name):</span>
</span></span><span style="display:flex;"><span>curl -s http://localhost:1313/posts/index.xml | head
</span></span></code></pre></div><p>Check comments:</p>
<ol>
<li>Open any post locally.</li>
<li>Scroll to the bottom — Giscus should appear.</li>
<li>Try a reaction or comment (youll be prompted to sign in with GitHub).</li>
</ol>
<hr>
<h2 id="5-per-post-controls-handy-later">5) Per-post controls (handy later)</h2>
<p>Turn comments off for a single post:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#75715e"># in that posts front matter</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">comments</span> = <span style="color:#66d9ef">false</span>
</span></span></code></pre></div><p>Full content in RSS (global):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">params</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">ShowFullTextinRSS</span> = <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>Show RSS buttons on section/taxonomy lists:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">params</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">ShowRssButtonInSectionTermList</span> = <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><hr>
<h2 id="6-troubleshooting-aka-what-i-bumped-into">6) Troubleshooting (aka “what I bumped into”)</h2>
<ul>
<li>
<p><strong>Home page has no RSS icon</strong><br>
Thats expected; either enable Home-Info/Profile mode + <code>socialIcons</code>, or use the footer partial.</p>
</li>
<li>
<p><strong>Section feed 404</strong><br>
Folder names are lowercase (<code>content/posts/</code>, not <code>content/Posts/</code>).<br>
The URL mirrors that: <code>/posts/index.xml</code>.</p>
</li>
<li>
<p><strong>Giscus doesnt create a discussion</strong><br>
Double-check the four attributes: <code>data-repo</code>, <code>data-repo-id</code>, <code>data-category</code>, <code>data-category-id</code>.<br>
Make sure Discussions is enabled and the Giscus app is installed for the repo.</p>
</li>
<li>
<p><strong>Icon is comically large</strong><br>
Keep the CSS above; 1620px usually looks right.</p>
</li>
</ul>
<hr>
<h2 id="7-bonus-fast-setup-via-github-cli-optional-i-didnt-use-it-but-i-shouldve-perhaps">7) Bonus: fast setup via GitHub CLI (optional, I didn&rsquo;t use it, but I should&rsquo;ve perhaps)</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Create the public comments repo (adjust names)</span>
</span></span><span style="display:flex;"><span>gh repo create yourname/blog-comments --public -d <span style="color:#e6db74">&#34;Blog comment threads&#34;</span> --confirm
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Enable Discussions for it</span>
</span></span><span style="display:flex;"><span>gh repo edit yourname/blog-comments --enable-discussions
</span></span></code></pre></div><p>Then visit <strong>giscus.app</strong>, select the repo + category (e.g. “Comments”), and copy the generated IDs into <code>layouts/partials/comments.html</code>.</p>
<hr>
<h3 id="final-config-snapshot-condensed">Final config snapshot (condensed)</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#a6e22e">baseURL</span> = <span style="color:#e6db74">&#34;https://example.com/&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">theme</span> = <span style="color:#e6db74">&#34;PaperMod&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">outputs</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">home</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>, <span style="color:#e6db74">&#34;JSON&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">section</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">taxonomy</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">term</span> = [<span style="color:#e6db74">&#34;HTML&#34;</span>, <span style="color:#e6db74">&#34;RSS&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">services</span>.<span style="color:#a6e22e">rss</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">limit</span> = <span style="color:#ae81ff">-1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">params</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">comments</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">ShowRssButtonInSectionTermList</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">ShowFullTextinRSS</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Optional if using Home-Info/Profile mode:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># [[params.socialIcons]]</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># name = &#34;rss&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># url = &#34;/index.xml&#34;</span>
</span></span></code></pre></div><hr>
<h1 id="appendix--why-i-added-isso-how-i-wired-it-and-what-i-fixed">Appendix — Why I added Isso, how I wired it, and what I fixed</h1>
<h2 id="the-story-why-isso--why-i-still-keep-giscus">The story (why Isso + why I still keep Giscus)</h2>
<p>I wanted comments that:</p>
<ul>
<li>allow <strong>anonymous</strong> replies (no GitHub account required),</li>
<li>are <strong>lightweight</strong> and <strong>self-hosted</strong>, and</li>
<li>can work on my <strong>Tor <code>.onion</code> mirror</strong>.</li>
</ul>
<p><strong>Isso</strong> checks those boxes: its a tiny Python app with SQLite storage, no trackers, and a simple embed. At the same time, I like the developer-friendly workflow of <strong>Giscus</strong> (comments are GitHub Discussions), so I kept both and added a little switcher UI: <strong>“Anonymous (Isso)”</strong> or <strong>“GitHub (Giscus)”</strong>.</p>
<p>Result: readers can pick privacy/anon (Isso) or identity/notifications (Giscus).</p>
<h2 id="how-i-run-it-high-level">How I run it (high-level)</h2>
<ul>
<li><strong>Site:</strong> Hugo + PaperMod</li>
<li><strong>Isso:</strong> listening on <code>127.0.0.1:8080</code>, stored locally (SQLite)</li>
<li><strong>Nginx:</strong> reverse-proxies <strong><code>/isso/</code></strong> to Isso on both the clearnet and the <code>.onion</code> vhost</li>
<li><strong>Hugo partial:</strong> renders the two panels (Isso &amp; Giscus) and a switcher; Giscus is <strong>lazy-loaded</strong> and <strong>auto-rethemed</strong> with the site theme</li>
</ul>
<blockquote>
<p>Im deliberately keeping Issos own config tiny in this appendix; the important part for my setup is the <strong>Nginx proxying</strong> and the <strong>Hugo partial</strong>.</p></blockquote>
<h2 id="hugo-partial-switcher--embeds">Hugo partial: switcher + embeds</h2>
<p>Save as <code>layouts/partials/comments.html</code> and include it in your single layout (e.g. <code>layouts/_default/single.html</code>) with <code>{{ partial &quot;comments.html&quot; . }}</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- comments.html --&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;comments-switch&#34;</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;display:flex;gap:.5rem;margin:.5rem 0 1rem;&#34;</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;btn-isso&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;button&#34;</span> <span style="color:#a6e22e">aria-pressed</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;true&#34;</span>&gt;Anonymous (Isso)&lt;/<span style="color:#f92672">button</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;btn-giscus&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;button&#34;</span> <span style="color:#a6e22e">aria-pressed</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;false&#34;</span>&gt;GitHub (Giscus)&lt;/<span style="color:#f92672">button</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://github.com/AlipourIm/blog-comments/discussions/categories/comments&#34;</span> <span style="color:#a6e22e">target</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;_blank&#34;</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;noopener&#34;</span>&gt;Open on GitHub ↗&lt;/<span style="color:#f92672">a</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- Isso panel (default) --&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;panel-isso&#34;</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">section</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;isso-thread&#34;</span>&gt;&lt;/<span style="color:#f92672">section</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">script</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/isso/js/embed.min.js&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-isso</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/isso&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-isso-css</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;true&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-isso-lang</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;en&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-isso-max-comments-nested</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;5&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">data-isso-sorting</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;newest&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">async</span>&gt;
</span></span><span style="display:flex;"><span> &lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">small</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;isso-powered&#34;</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;display:block;margin:.5rem 0;color:var(--secondary,#888)&#34;</span>&gt;
</span></span><span style="display:flex;"><span> Comments powered by &lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://isso-comments.de&#34;</span> <span style="color:#a6e22e">target</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;_blank&#34;</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;noopener&#34;</span>&gt;Isso&lt;/<span style="color:#f92672">a</span>&gt;
</span></span><span style="display:flex;"><span> &lt;/<span style="color:#f92672">small</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- Giscus panel (lazy-loaded on click) --&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;panel-giscus&#34;</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;display:none&#34;</span>&gt;
</span></span><span style="display:flex;"><span> &lt;<span style="color:#f92672">section</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;giscus-thread&#34;</span>&gt;&lt;/<span style="color:#f92672">section</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>(<span style="color:#66d9ef">function</span> () {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">panelIsso</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;panel-isso&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">panelGisc</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;panel-giscus&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">issoBtn</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;btn-isso&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">giscBtn</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;btn-giscus&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#a6e22e">gLoaded</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">isDark</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 1) explicit PaperMod preference
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">pref</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">localStorage</span>.<span style="color:#a6e22e">getItem</span>(<span style="color:#e6db74">&#39;pref-theme&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">pref</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;dark&#39;</span>) <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">pref</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;light&#39;</span>) <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 2) page state (classes / data-theme)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">H</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">documentElement</span>, <span style="color:#a6e22e">B</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">body</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">hasDark</span> <span style="color:#f92672">=</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">H</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">contains</span>(<span style="color:#e6db74">&#39;dark&#39;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">B</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">contains</span>(<span style="color:#e6db74">&#39;dark&#39;</span>) <span style="color:#f92672">||</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">H</span>.<span style="color:#a6e22e">dataset</span>.<span style="color:#a6e22e">theme</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;dark&#39;</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">B</span>.<span style="color:#a6e22e">dataset</span>.<span style="color:#a6e22e">theme</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;dark&#39;</span> <span style="color:#f92672">||</span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">H</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">contains</span>(<span style="color:#e6db74">&#39;theme-dark&#39;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">B</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">contains</span>(<span style="color:#e6db74">&#39;theme-dark&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">hasDark</span>) <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 3) OS preference
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">return</span> window.<span style="color:#a6e22e">matchMedia</span> <span style="color:#f92672">&amp;&amp;</span> window.<span style="color:#a6e22e">matchMedia</span>(<span style="color:#e6db74">&#39;(prefers-color-scheme: dark)&#39;</span>).<span style="color:#a6e22e">matches</span>;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">gTheme</span> <span style="color:#f92672">=</span> () =&gt; (<span style="color:#a6e22e">isDark</span>() <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;dark_dimmed&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;noborder_light&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">loadGiscus</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">gLoaded</span>) <span style="color:#66d9ef">return</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">s</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">createElement</span>(<span style="color:#e6db74">&#39;script&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">src</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;https://giscus.app/client.js&#39;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#66d9ef">async</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">crossOrigin</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;anonymous&#39;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-repo&#39;</span>,<span style="color:#e6db74">&#39;AlipourIm/blog-comments&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-repo-id&#39;</span>,<span style="color:#e6db74">&#39;R_kgDOQGARyA&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-category&#39;</span>,<span style="color:#e6db74">&#39;Comments&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-category-id&#39;</span>,<span style="color:#e6db74">&#39;DIC_kwDOQGARyM4Cw3x-&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-mapping&#39;</span>,<span style="color:#e6db74">&#39;pathname&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-strict&#39;</span>,<span style="color:#e6db74">&#39;0&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-reactions-enabled&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-emit-metadata&#39;</span>,<span style="color:#e6db74">&#39;0&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-input-position&#39;</span>,<span style="color:#e6db74">&#39;bottom&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-lang&#39;</span>,<span style="color:#e6db74">&#39;en&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;data-theme&#39;</span>, <span style="color:#a6e22e">gTheme</span>()); <span style="color:#75715e">// initial theme
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;giscus-thread&#39;</span>).<span style="color:#a6e22e">appendChild</span>(<span style="color:#a6e22e">s</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Retheme once iframe exists
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">reTheme</span> <span style="color:#f92672">=</span> () =&gt; {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">iframe</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">querySelector</span>(<span style="color:#e6db74">&#39;iframe.giscus-frame&#39;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">iframe</span>) <span style="color:#66d9ef">return</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">iframe</span>.<span style="color:#a6e22e">contentWindow</span><span style="color:#f92672">?</span>.<span style="color:#a6e22e">postMessage</span>(
</span></span><span style="display:flex;"><span> { <span style="color:#a6e22e">giscus</span><span style="color:#f92672">:</span> { <span style="color:#a6e22e">setConfig</span><span style="color:#f92672">:</span> { <span style="color:#a6e22e">theme</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">gTheme</span>() } } },
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;https://giscus.app&#39;</span>
</span></span><span style="display:flex;"><span> );
</span></span><span style="display:flex;"><span> };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// PaperMod toggle button
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;theme-toggle&#39;</span>)<span style="color:#f92672">?</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;click&#39;</span>, () =&gt;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">setTimeout</span>(<span style="color:#a6e22e">reTheme</span>, <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span> );
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Also react to attribute changes
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">mo</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">MutationObserver</span>(<span style="color:#a6e22e">reTheme</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">mo</span>.<span style="color:#a6e22e">observe</span>(document.<span style="color:#a6e22e">documentElement</span>, { <span style="color:#a6e22e">attributes</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>, <span style="color:#a6e22e">attributeFilter</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;class&#39;</span>,<span style="color:#e6db74">&#39;data-theme&#39;</span>] });
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">mo</span>.<span style="color:#a6e22e">observe</span>(document.<span style="color:#a6e22e">body</span>, { <span style="color:#a6e22e">attributes</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>, <span style="color:#a6e22e">attributeFilter</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;class&#39;</span>,<span style="color:#e6db74">&#39;data-theme&#39;</span>] });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">gLoaded</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">show</span>(<span style="color:#a6e22e">which</span>) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">showIsso</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">which</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;isso&#39;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">panelIsso</span>.<span style="color:#a6e22e">style</span>.<span style="color:#a6e22e">display</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">showIsso</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;block&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;none&#39;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">panelGisc</span>.<span style="color:#a6e22e">style</span>.<span style="color:#a6e22e">display</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">showIsso</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;none&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;block&#39;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">issoBtn</span><span style="color:#f92672">?</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;aria-pressed&#39;</span>, <span style="color:#a6e22e">showIsso</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">giscBtn</span><span style="color:#f92672">?</span>.<span style="color:#a6e22e">setAttribute</span>(<span style="color:#e6db74">&#39;aria-pressed&#39;</span>, <span style="color:#f92672">!</span><span style="color:#a6e22e">showIsso</span>);
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">showIsso</span>) <span style="color:#a6e22e">loadGiscus</span>();
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">issoBtn</span><span style="color:#f92672">?</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;click&#39;</span>, <span style="color:#a6e22e">e</span> =&gt; { <span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">preventDefault</span>(); <span style="color:#a6e22e">show</span>(<span style="color:#e6db74">&#39;isso&#39;</span>); });
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">giscBtn</span><span style="color:#f92672">?</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;click&#39;</span>, <span style="color:#a6e22e">e</span> =&gt; { <span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">preventDefault</span>(); <span style="color:#a6e22e">show</span>(<span style="color:#e6db74">&#39;giscus&#39;</span>); });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// default
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">show</span>(<span style="color:#e6db74">&#39;isso&#39;</span>);
</span></span><span style="display:flex;"><span>})();
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">script</span>&gt;
</span></span></code></pre></div><h2 id="nginx-proxy-isso-on-both-sites-and-avoid-the-404-onion-trap">Nginx: proxy Isso on <strong>both</strong> sites (and avoid the 404-onion trap)</h2>
<p>The bug I hit: my <code>.onion</code> server had a regex static block that <strong>won over</strong> the plain <code>/isso/</code> location, so <code>/isso/js/embed.min.js</code> returned <strong>404</strong>.</p>
<p><strong>Fix:</strong> make <code>/isso/</code> a <code>^~</code> prefix location so it beats regex, and place it <strong>above</strong> the static block.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#75715e"># /etc/nginx/sites-enabled/onion-blog (same idea for the clearnet vhost)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">listen</span> 127.0.0.1:<span style="color:#ae81ff">3301</span> <span style="color:#e6db74">default_server</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">server_name</span> <span style="color:#e6db74">fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion</span> 127.0.0.1 <span style="color:#e6db74">localhost</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">add_header</span> <span style="color:#e6db74">Referrer-Policy</span> <span style="color:#e6db74">no-referrer</span> <span style="color:#e6db74">always</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">add_header</span> <span style="color:#e6db74">X-Content-Type-Options</span> <span style="color:#e6db74">nosniff</span> <span style="color:#e6db74">always</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">add_header</span> <span style="color:#e6db74">X-Frame-Options</span> <span style="color:#e6db74">SAMEORIGIN</span> <span style="color:#e6db74">always</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">root</span> <span style="color:#e6db74">/srv/hugo/mysite/public-onion</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">index</span> <span style="color:#e6db74">index.html</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> { <span style="color:#f92672">try_files</span> $uri $uri/ <span style="color:#e6db74">/index.html</span>; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># /isso -&gt; /isso/
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#f92672">location</span> = <span style="color:#e6db74">/isso</span> { <span style="color:#f92672">return</span> <span style="color:#ae81ff">301</span> <span style="color:#e6db74">/isso/</span>; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># IMPORTANT: this must beat regex locations below
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#f92672">location</span> <span style="color:#e6db74">^~</span> <span style="color:#e6db74">/isso/</span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_pass</span> <span style="color:#e6db74">http://127.0.0.1:8080/</span>; <span style="color:#75715e"># Isso container/port
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#f92672">proxy_http_version</span> <span style="color:#ae81ff">1</span><span style="color:#e6db74">.1</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Host</span> $host;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Host</span> $host;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Proto</span> $scheme;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-For</span> $proxy_add_x_forwarded_for;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_redirect</span> <span style="color:#66d9ef">off</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">proxy_read_timeout</span> <span style="color:#e6db74">60s</span>;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># static
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#f92672">location</span> ~<span style="color:#e6db74">*</span> <span style="color:#e6db74">\\.(css|js|ico|png|jpg|jpeg|gif|svg|webp|txt|xml)</span>$ {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">access_log</span> <span style="color:#66d9ef">off</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">add_header</span> <span style="color:#e6db74">Cache-Control</span> <span style="color:#e6db74">&#34;public,</span> <span style="color:#e6db74">max-age=31536000,</span> <span style="color:#e6db74">immutable&#34;</span>;
</span></span><span style="display:flex;"><span> <span style="color:#f92672">try_files</span> $uri =<span style="color:#ae81ff">404</span>;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Reload and smoke test:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nginx -t <span style="color:#f92672">&amp;&amp;</span> sudo systemctl reload nginx
</span></span><span style="display:flex;"><span>curl -I http://&lt;your-onion-host&gt;/isso/js/embed.min.js <span style="color:#75715e"># expect 200</span>
</span></span></code></pre></div><blockquote>
<p>If you ever point <code>data-isso</code> to a <strong>different origin</strong>, add CORS headers on that vhost. For same-origin (<code>data-isso=&quot;/isso&quot;</code>), you dont need CORS.</p></blockquote>
<h2 id="small-css-tweaks-one-color-across-lightdark--spacing">Small CSS tweaks (one color across light/dark + spacing)</h2>
<p>I wanted the same blue for <strong>reply / edit / delete</strong> links and for <strong>Submit / Preview</strong> buttons, in both themes, and a little spacing:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#75715e">/* put this in your site CSS */</span>
</span></span><span style="display:flex;"><span>:<span style="color:#a6e22e">root</span> { --btn-blue: <span style="color:#ae81ff">#2563eb</span>; } <span style="color:#75715e">/* adjust to taste */</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/* Isso form buttons */</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-post-action</span> <span style="color:#f92672">input</span><span style="color:#f92672">[</span><span style="color:#f92672">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;submit&#34;</span><span style="color:#f92672">],</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-post-action</span> <span style="color:#f92672">input</span><span style="color:#f92672">[</span><span style="color:#f92672">name</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;preview&#34;</span><span style="color:#f92672">]</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">background</span>: <span style="color:#a6e22e">var</span>(<span style="color:#f92672">--</span>btn<span style="color:#f92672">-</span><span style="color:#66d9ef">blue</span>) <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">color</span>: <span style="color:#ae81ff">#fff</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">border</span>: <span style="color:#66d9ef">none</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">padding</span>: <span style="color:#ae81ff">.5</span><span style="color:#66d9ef">rem</span> <span style="color:#ae81ff">.75</span><span style="color:#66d9ef">rem</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">border-radius</span>: <span style="color:#ae81ff">.4</span><span style="color:#66d9ef">rem</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">cursor</span>: <span style="color:#66d9ef">pointer</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/* link actions under comments */</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-comment-footer</span> <span style="color:#f92672">a</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">color</span>: <span style="color:#a6e22e">var</span>(<span style="color:#f92672">--</span>btn<span style="color:#f92672">-</span><span style="color:#66d9ef">blue</span>) <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">margin-right</span>: <span style="color:#ae81ff">.5</span><span style="color:#66d9ef">rem</span>; <span style="color:#75715e">/* gives &#34;edit&#34; and &#34;delete&#34; some breathing room */</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">text-decoration</span>: <span style="color:#66d9ef">none</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-comment-footer</span> <span style="color:#f92672">a</span>:<span style="color:#a6e22e">hover</span> { <span style="color:#66d9ef">text-decoration</span>: <span style="color:#66d9ef">underline</span>; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/* keep name/email/website stacked, slightly larger */</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-auth-section</span> .<span style="color:#a6e22e">isso-input-wrapper</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">block</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">margin</span>: <span style="color:#ae81ff">.35</span><span style="color:#66d9ef">rem</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-auth-section</span> <span style="color:#f92672">label</span> { <span style="color:#66d9ef">font-size</span>: <span style="color:#ae81ff">.95</span><span style="color:#66d9ef">rem</span>; }
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-auth-section</span> <span style="color:#f92672">input</span><span style="color:#f92672">[</span><span style="color:#f92672">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text&#34;</span><span style="color:#f92672">],</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-auth-section</span> <span style="color:#f92672">input</span><span style="color:#f92672">[</span><span style="color:#f92672">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;email&#34;</span><span style="color:#f92672">],</span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">isso-auth-section</span> <span style="color:#f92672">input</span><span style="color:#f92672">[</span><span style="color:#f92672">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;url&#34;</span><span style="color:#f92672">]</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">width</span>: <span style="color:#ae81ff">100</span><span style="color:#66d9ef">%</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">font-size</span>: <span style="color:#ae81ff">1</span><span style="color:#66d9ef">rem</span>;
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">padding</span>: <span style="color:#ae81ff">.5</span><span style="color:#66d9ef">rem</span> <span style="color:#ae81ff">.6</span><span style="color:#66d9ef">rem</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="what-changed-the-fixes-i-actually-made">What changed (the fixes I actually made)</h2>
<ol>
<li>
<p><strong>Theme correctness for Giscus.</strong><br>
PaperMod doesnt add <code>.light</code>—it only toggles <code>.dark</code> and stores <code>pref-theme</code>. I now:</p>
<ul>
<li>read <code>localStorage.pref-theme</code> first,</li>
<li>fall back to class/data-theme, then</li>
<li>fall back to OS preference.<br>
I also re-theme the Giscus iframe on every toggle via <code>postMessage</code>.</li>
</ul>
</li>
<li>
<p><strong>Isso over Tor.</strong><br>
On the <code>.onion</code> vhost, I moved the proxy to a <code>^~ /isso/</code> block so it beats the static regex. That fixed the <code>404</code> on <code>/isso/js/embed.min.js</code>.</p>
</li>
<li>
<p><strong>UI polish.</strong></p>
<ul>
<li>Unified button/link color across themes,</li>
<li>ensured “edit”/“delete” arent touching,</li>
<li>kept the author/email/website inputs <strong>stacked</strong>, and</li>
<li>left <strong>Submit</strong>/<strong>Preview</strong> styled and grouped.</li>
</ul>
</li>
</ol>
<h2 id="sanity-check">Sanity check</h2>
<ul>
<li>Toggle the theme: Giscus switches between <code>noborder_light</code> and <code>dark_dimmed</code> without reload.</li>
<li>Open DevTools → Network on onion: <code>/isso/js/embed.min.js</code> loads with <strong>200</strong>.</li>
<li>Switcher buttons swap panels instantly; Giscus only loads when clicked.</li>
</ul>
<h2 id="8-final-notes">8) Final notes!</h2>
<p>I could not fully fix the style of Isso.
CSS is not easy&hellip; drat!</p>
<p>I don&rsquo;t think anyone actually reads the blog, let alone comment on it.
But it felt cool to have a comment section and also RSS for it.
I had a lot of not so fun debugging experience, and will probably work on the styling to make it look right, but for now I&rsquo;m happy with it! ^^</p>
<h1 id="admin-note--delete-all-isso-comments-for-a-single-post">Admin note — Delete all <strong>Isso</strong> comments for a single post</h1>
<p>This note is for future me: how to remove every comment tied to one post in <strong>Isso</strong>.<br>
Tested with SQLite-backed Isso (default). Works whether you serve via clearnet or <code>.onion</code> — because this operates directly on the database.</p>
<hr>
<h2 id="tldr-host-with-sqlite">TL;DR (host with SQLite)</h2>
<blockquote>
<p>Replace the placeholders for <code>DB</code> and <code>POST_URI</code> first.</p></blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># 0) Variables — edit these two lines for your setup</span>
</span></span><span style="display:flex;"><span>DB<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/var/lib/isso/comments.db&#34;</span> <span style="color:#75715e"># path to your Isso SQLite DB (check isso.conf: [general] dbpath)</span>
</span></span><span style="display:flex;"><span>POST_URI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/posts/skin_routine/&#34;</span> <span style="color:#75715e"># the post&#39;s URI as stored by Isso (often just the path)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 1) Backup (always do this!)</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;.backup &#39;</span><span style="color:#66d9ef">$(</span>dirname <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">/comments.</span><span style="color:#66d9ef">$(</span>date +%F-%H%M%S<span style="color:#66d9ef">)</span><span style="color:#e6db74">.backup.sqlite3&#39;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Inspect: find the thread row and preview the comments</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">.headers on
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">.mode column
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">SELECT id, uri FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">SELECT id, tid, created, author, text
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">FROM comments
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">WHERE tid IN (SELECT id FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">ORDER BY created DESC
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">LIMIT 25;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Delete all comments for that post (thread)</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">DELETE FROM comments
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">WHERE tid IN (SELECT id FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;);
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) (Optional) Remove the now-empty thread row too</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">DELETE FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">VACUUM;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 5) Done. Isso usually picks this up automatically.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># If you&#39;re containerized and want to be safe:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># docker restart &lt;isso_container_name&gt;</span>
</span></span></code></pre></div><hr>
<h2 id="if-running-isso-in-docker">If running Isso in Docker</h2>
<p>Open a shell in the container, then run the same steps:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker exec -it &lt;isso_container_name&gt; /bin/sh
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Inside the container:</span>
</span></span><span style="display:flex;"><span>DB<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/db/comments.db&#34;</span> <span style="color:#75715e"># or /data/comments.db, check your image/volume mapping</span>
</span></span><span style="display:flex;"><span>POST_URI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/posts/skin_routine/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;.backup &#39;/db/comments.</span><span style="color:#66d9ef">$(</span>date +%F-%H%M%S<span style="color:#66d9ef">)</span><span style="color:#e6db74">.backup.sqlite3&#39;&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;SELECT id, uri FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;;&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;DELETE FROM comments WHERE tid IN (SELECT id FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;);&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;DELETE FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;; VACUUM;&#34;</span>
</span></span><span style="display:flex;"><span>exit
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Optionally restart the container:</span>
</span></span><span style="display:flex;"><span>docker restart &lt;isso_container_name&gt;
</span></span></code></pre></div><hr>
<h2 id="notes--gotchas">Notes &amp; gotchas</h2>
<ul>
<li><strong>Find the real DB path</strong>: In <code>isso.conf</code> (often <code>/etc/isso/isso.conf</code> or within your container at <code>/config/isso.conf</code>), look for:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#66d9ef">[general]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">dbpath</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">/var/lib/isso/comments.db</span>
</span></span></code></pre></div></li>
<li><strong>What goes in <code>POST_URI</code>?</strong> Isso stores a <code>uri</code> string per thread. With the default embed config, it&rsquo;s usually the <strong>path</strong> (<code>/posts/&lt;slug&gt;/</code>). If youre unsure, list recent threads:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;.headers on&#34;</span> <span style="color:#e6db74">&#34;.mode column&#34;</span> <span style="color:#e6db74">&#34;SELECT id, uri FROM threads ORDER BY id DESC LIMIT 50;&#34;</span>
</span></span></code></pre></div></li>
<li><strong>Clearnet vs <code>.onion</code></strong>: If you load the same post under multiple origins <em>and</em> your embed setup stores full origins, you may have <strong>multiple thread rows</strong>. The <code>LIKE</code> query above deliberately matches any uri containing your <code>POST_URI</code> to catch those.</li>
<li><strong>Rollback</strong>: To undo, stop Isso (optional), replace the DB with your backup (<code>comments.YYYY-MM-DD-HHMMSS.backup.sqlite3</code>), and start Isso again.</li>
<li><strong>HTTP API option</strong>: Isso supports <code>DELETE /&lt;comment_id&gt;</code> if admin endpoints/auth are enabled. For bulk removal its simpler and safer to use SQLite directly.</li>
<li><strong>Safety</strong>: Always run a backup first, and <strong>preview with the SELECT</strong> before you run the DELETE.</li>
</ul>
<hr>
<h2 id="one-liners-for-the-impatient">One-liners for the impatient</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>DB<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/var/lib/isso/comments.db&#34;</span>; POST_URI<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/posts/skin_routine/&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;.backup &#39;</span><span style="color:#66d9ef">$(</span>dirname <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">/comments.</span><span style="color:#66d9ef">$(</span>date +%F-%H%M%S<span style="color:#66d9ef">)</span><span style="color:#e6db74">.backup.sqlite3&#39;&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;DELETE FROM comments WHERE tid IN (SELECT id FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;);&#34;</span>
</span></span><span style="display:flex;"><span>sqlite3 <span style="color:#e6db74">&#34;</span>$DB<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;DELETE FROM threads WHERE uri LIKE &#39;%&#39; || &#39;</span>$POST_URI<span style="color:#e6db74">&#39; || &#39;%&#39;; VACUUM;&#34;</span>
</span></span></code></pre></div><hr>
<p><strong>Isso container: quick checks &amp; fixes for future me! (thank past me later ^^)</strong></p>
<p><strong>Find the container</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker ps -a --format <span style="color:#e6db74">&#39;table {{.ID}} {{.Names}} {{.Status}} {{.Ports}}&#39;</span> | grep -i isso
</span></span></code></pre></div><p><strong>Inspect basic state</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker inspect -f <span style="color:#e6db74">&#39;Name={{.Name}} Running={{.State.Running}} Status={{.State.Status}} StartedAt={{.State.StartedAt}} FinishedAt={{.State.FinishedAt}}&#39;</span> isso
</span></span></code></pre></div><p><strong>Logs</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker logs --tail<span style="color:#f92672">=</span><span style="color:#ae81ff">200</span> isso
</span></span><span style="display:flex;"><span>docker logs -f isso
</span></span></code></pre></div><p><strong>Ports &amp; reachability</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker port isso
</span></span><span style="display:flex;"><span>sudo ss -ltnp | grep <span style="color:#e6db74">&#39;:8080 &#39;</span>
</span></span><span style="display:flex;"><span>curl -i http://127.0.0.1:8080/
</span></span></code></pre></div><p><strong>Restart policy (keep it running)</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker inspect -f <span style="color:#e6db74">&#39;{{.HostConfig.RestartPolicy.Name}}&#39;</span> isso
</span></span><span style="display:flex;"><span>docker update --restart unless-stopped isso
</span></span></code></pre></div><p><strong>Start/stop the container</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker start isso
</span></span><span style="display:flex;"><span>docker stop isso
</span></span></code></pre></div><p><strong>Who/what stopped it (events)</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker events --since 24h --filter container<span style="color:#f92672">=</span>isso
</span></span></code></pre></div><p><strong>Common config issue: duplicate options/sections</strong>
If logs show DuplicateOptionError or DuplicateSectionError, fix <code>/config/isso.cfg</code> (remove duplicate <code>[server]</code> blocks or duplicate <code>public-endpoint</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>nl -ba /config/isso.cfg | sed -n <span style="color:#e6db74">&#39;1,120p&#39;</span>
</span></span><span style="display:flex;"><span>grep -n <span style="color:#e6db74">&#39;^\[server\]&#39;</span> /config/isso.cfg
</span></span><span style="display:flex;"><span>grep -n <span style="color:#e6db74">&#39;^public-endpoint&#39;</span> /config/isso.cfg
</span></span></code></pre></div><p><strong>Using Docker Compose</strong> <em>(run these in the directory with your compose file)</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose ps
</span></span><span style="display:flex;"><span>docker compose logs --tail<span style="color:#f92672">=</span><span style="color:#ae81ff">200</span> isso
</span></span><span style="display:flex;"><span>docker compose up -d isso
</span></span></code></pre></div><p><strong>If the container doesnt exist (create/recreate)</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker image ls | grep -i isso
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>docker run -d --name isso -p 8080:8080 -v /srv/isso/config:/config -v /srv/isso/db:/db --restart unless-stopped ghcr.io/posativ/isso:latest
</span></span></code></pre></div><p><strong>Optional: exclude from auto-updaters (like Watchtower)</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker update --label-add com.centurylinklabs.watchtower.enable<span style="color:#f92672">=</span>false isso
</span></span></code></pre></div><p><em>This note is intentionally self-contained so I can paste it at the end of the blog post as a maintainer-only appendix.</em></p>
<hr>
<div class="signature-block" style="margin-top:1rem">
<p><strong>Downloads:</strong>
<a href="/sources/posts/new_features.md">Markdown</a> ·
<a href="/sources/posts/new_features.md.asc">Signature (.asc)</a>
</p><details class="signature">
<summary>View OpenPGP signature</summary>
<pre style="font-size:0.85em; overflow-x:auto; padding:0.75rem;">-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEVaKl3oR5K6zGyu4/tYgoUOBMjSoFAmpkbuMACgkQtYgoUOBM
jSr2VxAAgdHpf&#43;4EIx2ASmSB&#43;MeAHp7s1&#43;2EPhmn96QuhiQO9Dr1e9250LbF/R8S
A0zcN8mmyOtKv2rediU6HsGy6ddwdTAtpQDRvMw2Xuk2pBUZaG5LuvlNgSse9zVB
dcG3GVLuMSRgNmyolhFoSWn46aa&#43;3wZGrzYZQVUt8op&#43;2fVp36agq2YoB4zeGKSm
Ri43rO/kTingD0bclOA&#43;SMbHpKQOcLyHwDlVrqIjVXcJ/kKLcm1G3Z5owo&#43;gB6jY
EMjxYiqyf5Zcbt4q/WzojbHLffjXoMzOgZ1sDOIObVQni9atgV49X4oIZ3&#43;xSXSH
W7ZbH6sg9LlrU8djddBXUKB0i72IVZ/4F5icVFUcK&#43;szOmASy8fFP7gCOcCRATtb
eNIFtiAlRXI0CqJdeq5fE9b&#43;LX8lRpNnX229tg7GFgddzYUmFkKAsoJ9EUzUvUHm
Xzqlm9DKy9LG/CeOxo473fIo4YCT2fcmMnt9nCZW4iDKOVl1nCupkTn5qsfNdpQM
KycaNwsLBHPZWV&#43;jDon8NEzYQk07n1Q9rlEWdL0egvn2S&#43;pYnvLZbfi5dRhe&#43;ciC
qcEW/I1NZZRdU7MUEzhWvhbWsZtTkm6OevXjnqACv91DIQv7tNrKwZuASnpFeDRa
GE0QYRrsaI3vCLR3cUmBAFsvZdwgzH0RQLb8w21XBW/BoFvixbA=
=9k&#43;S
-----END PGP SIGNATURE-----
</pre>
</details><p><em>Verify locally:</em></p>
<pre style="font-size:0.85em; overflow-x:auto; padding:0.75rem;">torsocks curl -fSLO http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/sources/posts/new_features.md
torsocks curl -fSLO http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/sources/posts/new_features.md.asc
gpg --verify new_features.md.asc new_features.md
</pre>
</div>
]]></content:encoded>
</item>
</channel>
</rss>