Congratulations!

[Valid Atom 1.0] This is a valid Atom 1.0 feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://blogs.bwerp.net/feeds/atom.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  3.  <title>Annika Backstrom - sixohthree.com</title>
  4.  <subtitle>The personal blog of Annika Backstrom</subtitle>
  5.  <link href="https://sixohthree.com/feeds/atom.xml" rel="self" />
  6.  <link href="https://sixohthree.com/" />
  7.  <updated>2025-10-18T00:00:00Z</updated>
  8.  <id>https://sixohthree.com/</id>
  9.  <author>
  10.    <name>Annika Backstrom</name>
  11.  </author>
  12.  <entry>
  13.    <title>Fediverse Rules of Engagement</title>
  14.    <link href="https://sixohthree.com/blog/2025/fediverse-rules-of-engagement/" />
  15.    <updated>2025-10-18T00:00:00Z</updated>
  16.    <id>https://sixohthree.com/blog/2025/fediverse-rules-of-engagement/</id>
  17.    <content type="html">&lt;p&gt;These are my &amp;quot;rules&amp;quot; for how I interact on the Fediverse (Mastodon, GoToSocial,
  18. and other ActivityPub friends). I don&#39;t claim that they&#39;re perfect or correct or
  19. appropriate for anyone other than me.&lt;/p&gt;
  20. &lt;p&gt;&lt;strong&gt;Follow and unfollow liberally.&lt;/strong&gt; Don&#39;t be afraid to follow someone new, even
  21. if I&#39;m happy with my feed. Follow folks boosted into my feed, follow folks who
  22. interact with me, follow from the federated timeline. Unfollow if I want to, but
  23. consider using private notes, hiding boosts, and filters as &amp;quot;strikes.&amp;quot;&lt;/p&gt;
  24. &lt;p&gt;&lt;strong&gt;Check remote replies before sending my own reply.&lt;/strong&gt; Every server has a partial
  25. window of the Fediverse. Is my reply redundant? Is the person already drowning
  26. in replies?&lt;/p&gt;
  27. &lt;p&gt;&lt;strong&gt;Do not meta.&lt;/strong&gt; &lt;a href=&quot;https://xoxo.zone/@annika/113548210141988451&quot;&gt;Meta is the mind killer&lt;/a&gt;. Meta is the little death that
  28. brings total obliteration.&lt;/p&gt;
  29. &lt;p&gt;&lt;strong&gt;Don&#39;t overload posts with disclaimers.&lt;/strong&gt; They clutter up the post and deprive
  30. me of the opportunity to block jerks.&lt;/p&gt;
  31. &lt;p&gt;&lt;strong&gt;Always post alt text.&lt;/strong&gt; Do not boost anything without alt text, but don&#39;t
  32. harass individuals for not writing alt text.&lt;/p&gt;
  33. &lt;p&gt;&lt;strong&gt;Treat unverified accounts of &amp;quot;famous&amp;quot; people as illegitimate.&lt;/strong&gt; Misinfo is too
  34. rampant to risk engaging with impersonators.&lt;/p&gt;
  35. &lt;p&gt;&lt;strong&gt;Don&#39;t boost news that lacks a clear citation.&lt;/strong&gt; Be wary of screenshots of text
  36. that appear to be from legit sources, or are from unidentifiable sources.&lt;/p&gt;
  37. &lt;p&gt;&lt;strong&gt;No GenAI.&lt;/strong&gt; Don&#39;t boost, don&#39;t interact, consider muting or blocking the
  38. poster depending on severity. Be extremely wary of &amp;quot;activists&amp;quot; posting GenAI
  39. slop.&lt;/p&gt;
  40. </content>
  41.  </entry>
  42.  <entry>
  43.    <title>Eleventy Migration Notes</title>
  44.    <link href="https://sixohthree.com/blog/2025/eleventy-migration-notes/" />
  45.    <updated>2025-10-13T00:00:00Z</updated>
  46.    <id>https://sixohthree.com/blog/2025/eleventy-migration-notes/</id>
  47.    <content type="html">&lt;p&gt;In lieu of a retrospective of my weekend-long mad dash to convert this site from
  48. &lt;a href=&quot;https://getpelican.com/&quot;&gt;Pelican&lt;/a&gt; to &lt;a href=&quot;https://11ty.dev&quot;&gt;Eleventy&lt;/a&gt; (11ty), here
  49. are a few pages I found helpful and some things I learned along the way.&lt;/p&gt;
  50. &lt;p&gt;Neovim &lt;a href=&quot;https://kezhenxu94.me/blog/lazyvim-project-specific-settings&quot;&gt;supports a &lt;code&gt;.lazy.lua&lt;/code&gt;&lt;/a&gt; file for project- or directory-specific
  51. settings.&lt;/p&gt;
  52. &lt;p&gt;Working with &lt;a href=&quot;https://cfjedimaster.github.io/eleventy-blog-guide/guide.html#:~:text=Category%20Pages,-Alright&quot;&gt;custom taxonomies in Eleventy&lt;/a&gt; means jumping through a
  53. couple hoops but it&#39;s not impossible. Once you get a handle of the Collections
  54. API, it&#39;s alright.&lt;/p&gt;
  55. &lt;p&gt;It&#39;s helpful to have a script for manipulating &lt;a href=&quot;https://www.11ty.dev/docs/data-frontmatter/&quot;&gt;front matter&lt;/a&gt;.
  56. &lt;a href=&quot;https://sixohthree.com/media/2025/10/front-matter.js&quot;&gt;Here&#39;s mine&lt;/a&gt;.&lt;/p&gt;
  57. </content>
  58.  </entry>
  59.  <entry>
  60.    <title>Links (16 July 2025)</title>
  61.    <link href="https://sixohthree.com/blog/2025/links-16-july-2025/" />
  62.    <updated>2025-07-16T00:00:00Z</updated>
  63.    <id>https://sixohthree.com/blog/2025/links-16-july-2025/</id>
  64.    <content type="html">&lt;ul&gt;
  65. &lt;li&gt;&lt;a href=&quot;https://chaos.social/@VoltPaperScissors/114388324275114780&quot;&gt;DIY Book Lamp&lt;/a&gt;&lt;/li&gt;
  66. &lt;li&gt;&lt;a href=&quot;https://pikvm.org/&quot;&gt;PiKVM&lt;/a&gt;&lt;/li&gt;
  67. &lt;li&gt;&lt;a href=&quot;https://www.experimental-history.com/p/28-slightly-rude-notes-on-writing&quot;&gt;28 slightly rude notes on writing&lt;/a&gt;&lt;/li&gt;
  68. &lt;li&gt;&lt;a href=&quot;https://json-structure.org/&quot;&gt;JSON Structure&lt;/a&gt; -- JSON Structure is a data
  69. structure definition language that enforces strict typing, modularity, and
  70. determinism.&lt;/li&gt;
  71. &lt;li&gt;&lt;a href=&quot;https://fedify.dev/&quot;&gt;Fedify&lt;/a&gt; -- A TypeScript library for building federated
  72. server apps powered by ActivityPub and other standards, so-called fediverse&lt;/li&gt;
  73. &lt;li&gt;&lt;a href=&quot;https://www.aaihs.org/the-sinners-movie-syllabus/&quot;&gt;The ‘Sinners’ Movie Syllabus&lt;/a&gt;
  74. via &lt;a href=&quot;https://todon.eu/@jalcine&quot;&gt;@jalcine@todon.eu&lt;/a&gt;&lt;/li&gt;
  75. &lt;li&gt;&lt;a href=&quot;https://sli.dev/&quot;&gt;Slidev&lt;/a&gt; -- Presentation slides for developers&lt;/li&gt;
  76. &lt;li&gt;&lt;a href=&quot;https://charm.sh/&quot;&gt;Charm&lt;/a&gt; -- Various commands and helpers for pretty
  77. interactions in your CLI&lt;/li&gt;
  78. &lt;li&gt;&lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/#summary&quot;&gt;Conventional Commits&lt;/a&gt;
  79. -- A specification for adding human and machine readable meaning to commit
  80. messages&lt;/li&gt;
  81. &lt;li&gt;&lt;a href=&quot;https://corrode.dev/blog/flattening-rusts-learning-curve/&quot;&gt;Flattening Rust&#39;s Learning Curve&lt;/a&gt;&lt;/li&gt;
  82. &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/PechaKucha&quot;&gt;PechaKucha&lt;/a&gt; -- &amp;quot;a storytelling
  83. format in which a presenter shows 20 slides for 20 seconds per slide&amp;quot;&lt;/li&gt;
  84. &lt;li&gt;&lt;a href=&quot;https://www.saysomethingin.com/&quot;&gt;SaySomethingin&lt;/a&gt; language learning&lt;/li&gt;
  85. &lt;li&gt;&lt;a href=&quot;https://24hourtime.info/&quot;&gt;24hourtime.info&lt;/a&gt;
  86. &lt;ul&gt;
  87. &lt;li&gt;&lt;a href=&quot;https://sunclock.net/&quot;&gt;sunclock.net&lt;/a&gt;&lt;/li&gt;
  88. &lt;/ul&gt;
  89. &lt;/li&gt;
  90. &lt;li&gt;&lt;a href=&quot;https://github.com/open-cli-tools/concurrently#readme&quot;&gt;Concurrently&lt;/a&gt; -- Run
  91. multiple commands concurrently&lt;/li&gt;
  92. &lt;li&gt;&lt;a href=&quot;https://rioterm.com/&quot;&gt;Rio&lt;/a&gt; -- A modern terminal for the 21st century&lt;/li&gt;
  93. &lt;li&gt;&lt;a href=&quot;https://www.ibm.com/able/toolkit/tools/&quot;&gt;IBM Equal Access Toolkit&lt;/a&gt; --
  94. accessibility tools from IBM&lt;/li&gt;
  95. &lt;/ul&gt;
  96. </content>
  97.  </entry>
  98.  <entry>
  99.    <title>Links (22 April 2025)</title>
  100.    <link href="https://sixohthree.com/blog/2025/links-22-april-2025/" />
  101.    <updated>2025-04-22T00:00:00Z</updated>
  102.    <id>https://sixohthree.com/blog/2025/links-22-april-2025/</id>
  103.    <content type="html">&lt;ul&gt;
  104. &lt;li&gt;&lt;a href=&quot;https://bylandandsea.ie/&quot;&gt;bylandandsea.ie&lt;/a&gt; – Travel to and from Ireland without flying&lt;/li&gt;
  105. &lt;li&gt;&lt;a href=&quot;https://garagehq.deuxfleurs.fr/&quot;&gt;Garage&lt;/a&gt; — An open-source distributed object storage service tailored for
  106. self-hosting, supporting the S3 API&lt;/li&gt;
  107. &lt;li&gt;Human chains feel like a metaphor in these dark times
  108. &lt;ul&gt;
  109. &lt;li&gt;&lt;a href=&quot;https://www.nbcnews.com/news/us-news/ice-tries-detain-man-tennessee-home-neighbors-form-human-chain-n1032791&quot;&gt;ICE came for their neighbor, so these Tennesseans formed a human chain to
  110. protect him&lt;/a&gt;&lt;/li&gt;
  111. &lt;li&gt;&lt;a href=&quot;https://www.theguardian.com/us-news/2025/apr/17/book-brigade-us-town-forms-human-chain-to-move-9100-books-one-by-one&quot;&gt;‘Book brigade’: US town forms human chain to move 9,100 books
  112. one-by-one&lt;/a&gt;&lt;/li&gt;
  113. &lt;/ul&gt;
  114. &lt;/li&gt;
  115. &lt;li&gt;&lt;code&gt;stty -ixon&lt;/code&gt; to stop ^S from freezing your terminal via
  116. &lt;a href=&quot;https://social.jvns.ca/@b0rk/114354742870242559&quot;&gt;@b0rk@social.jvns.ca&lt;/a&gt;&lt;/li&gt;
  117. &lt;li&gt;&lt;a href=&quot;https://www.chiark.greenend.org.uk/~ianmdlvl/rust-polyglot/&quot;&gt;Rust for the Polyglot Programmer&lt;/a&gt; via
  118. &lt;a href=&quot;https://infosec.exchange/@raptor/114363710652153874&quot;&gt;@raptor@infosec.exchange&lt;/a&gt;&lt;/li&gt;
  119. &lt;li&gt;&lt;a href=&quot;https://www.seriouseats.com/chai-recipe-8364307&quot;&gt;How to Make Chai&lt;/a&gt;&lt;/li&gt;
  120. &lt;li&gt;&lt;a href=&quot;https://fxrant.blogspot.com/2025/04/the-movie-mistake-mystery-from-revenge.html?m=1&quot;&gt;The Movie Mistake Mystery from &amp;quot;Revenge of the Sith&amp;quot;&lt;/a&gt;&lt;/li&gt;
  121. &lt;li&gt;&lt;a href=&quot;https://typst.app/&quot;&gt;Typst&lt;/a&gt; – A more productive workflow for science.&lt;/li&gt;
  122. &lt;li&gt;&lt;a href=&quot;https://twinery.org/cookbook/&quot;&gt;Twine Cookbook&lt;/a&gt; – &amp;quot;This Cookbook contains documentation, tips, and
  123. examples for using the non-linear story creation tool &lt;a href=&quot;https://twinery.org/&quot;&gt;Twine&lt;/a&gt;&amp;quot;&lt;/li&gt;
  124. &lt;/ul&gt;
  125. </content>
  126.  </entry>
  127.  <entry>
  128.    <title>Webhooks as a (Systemd) Service</title>
  129.    <link href="https://sixohthree.com/blog/2025/webhooks-as-systemd-service/" />
  130.    <updated>2025-04-12T00:00:00Z</updated>
  131.    <id>https://sixohthree.com/blog/2025/webhooks-as-systemd-service/</id>
  132.    <content type="html">&lt;p&gt;The &lt;a href=&quot;https://xoxo.zone/docs/&quot;&gt;&amp;quot;docs&amp;quot; microsite&lt;/a&gt; for &lt;a href=&quot;https://xoxo.zone/&quot;&gt;xoxo.zone&lt;/a&gt; is a static page built with
  133. Eleventy. I explicitly didn&#39;t want to overcomplicate the site&#39;s setup with a
  134. cloud build process triggered by commit actions: the static site is compiled
  135. locally and committed alongside the content changes. A cron on the server runs
  136. &lt;code&gt;git pull&lt;/code&gt; on the repo every 5 minutes. The web server can directly serve the
  137. site without any additional build.&lt;/p&gt;
  138. &lt;p&gt;The site is updated a couple times a month on average. Of the 8,640 average
  139. monthly cron git pulls, 8,638 will do nothing. The net impact of this is
  140. probably negligible, but it did annoy me. Besides, Codeberg (my forge of choice
  141. for xoxo) gets the occasional DDoS and I&#39;m sure is getting hammered by &amp;quot;AI&amp;quot;
  142. scrapers that never sleep. Why send them more traffic than necessary?&lt;/p&gt;
  143. &lt;p&gt;I wanted to update the site when I pushed to the repo, without a complex
  144. configuration that would be difficult for someone else to pick up. Maybe I could
  145. write a lightweight web server that listened for a request and perform an
  146. action?&lt;/p&gt;
  147. &lt;h2&gt;Stop giving things generic names&lt;/h2&gt;
  148. &lt;p&gt;The obvious choice for triggering an action on push is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Webhook&quot;&gt;Webhook&lt;/a&gt;, which
  149. Codeberg supports natively. Expose an endpoint, verify incoming requests, run a
  150. command.&lt;/p&gt;
  151. &lt;p&gt;Doing some preliminary searches, I stumbled across the extremely
  152. generically-named &lt;a href=&quot;https://github.com/adnanh/webhook/&quot;&gt;webhook&lt;/a&gt;, a Go web server for triggering commands based
  153. on webhook requests. It&#39;s apt-installable on Ubuntu, has a simple configuration
  154. file syntax in JSON or YAML, and doesn&#39;t mind being proxied behind nginx. From a
  155. maintenance perspective, that&#39;s better than rolling my own server.&lt;/p&gt;
  156. &lt;h2&gt;Webhook configuration&lt;/h2&gt;
  157. &lt;p&gt;After &lt;code&gt;apt install webhook&lt;/code&gt;, I customised some of the launch parameters with
  158. &lt;code&gt;systemctl edit webhook&lt;/code&gt;[ref]Technically these are in an &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt; playbook,
  159. but I&#39;m simplifying so the code examples are more self-contained.[/ref]:&lt;/p&gt;
  160. &lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
  161. &lt;span class=&quot;token key attr-name&quot;&gt;ConditionPathExists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;
  162. &lt;span class=&quot;token key attr-name&quot;&gt;ConditionPathExists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;/etc/webhook.yaml&lt;/span&gt;
  163.  
  164. &lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
  165. &lt;span class=&quot;token key attr-name&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;
  166. &lt;span class=&quot;token key attr-name&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;/usr/bin/webhook -nopanic -hooks /etc/webhook.yaml -ip 127.0.0.1 -port 9899 -urlprefix my-webhook-prefix&lt;/span&gt;
  167. &lt;span class=&quot;token key attr-name&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;www-data&lt;/span&gt;
  168. &lt;span class=&quot;token key attr-name&quot;&gt;Group&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;www-data&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  169. &lt;p&gt;I configured my hook in &lt;code&gt;/etc/webhook.yaml&lt;/code&gt;. &lt;code&gt;webhook&lt;/code&gt; has an awkward syntax for
  170. passing arguments to commands, so I made a small bin script to wrap &lt;code&gt;cd&lt;/code&gt; and
  171. &lt;code&gt;git pull ...&lt;/code&gt;. &lt;code&gt;webhook&lt;/code&gt; also includes &amp;quot;matchers&amp;quot; to further customise the hook
  172. based on incoming parameters. This config performs request signature
  173. verification based on a shared secret, and filters for push events.&lt;/p&gt;
  174. &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deploy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;docs
  175.  &lt;span class=&quot;token key atrule&quot;&gt;execute-command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /usr/local/bin/xoxo&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;docs&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pull
  176.  &lt;span class=&quot;token key atrule&quot;&gt;response-message&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ok
  177.  &lt;span class=&quot;token key atrule&quot;&gt;trigger-rule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  178.      &lt;span class=&quot;token key atrule&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  179.          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  180.                &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;hmac&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sha256
  181.                &lt;span class=&quot;token key atrule&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; my_secret
  182.                &lt;span class=&quot;token key atrule&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  183.                    &lt;span class=&quot;token key atrule&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; header
  184.                    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; X&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Forgejo&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Signature
  185.          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  186.                &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; value
  187.                &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; push
  188.                &lt;span class=&quot;token key atrule&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  189.                    &lt;span class=&quot;token key atrule&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; header
  190.                    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; X&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Forgejo&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Event&lt;/code&gt;&lt;/pre&gt;
  191. &lt;p&gt;Then I proxied the requests through Nginx:&lt;/p&gt;
  192. &lt;pre class=&quot;language-nginx&quot;&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;upstream&lt;/span&gt; webhooks&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  193.    &lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;server&lt;/span&gt; 127.0.0.1:9899 fail_timeout=5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  194. &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  195.  
  196. &lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;server&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  197.    &lt;span class=&quot;token comment&quot;&gt;# the rest of the server config...&lt;/span&gt;
  198.  
  199.    &lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;location&lt;/span&gt; ~ ^/my-webhook-prefix/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  200.       &lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;proxy_pass&lt;/span&gt; http://webhooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  201.    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  202. &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  203. &lt;p&gt;That&#39;s enough to get a working webhook. No more cron needed!&lt;/p&gt;
  204. &lt;h2&gt;The future&lt;/h2&gt;
  205. &lt;p&gt;Mastodon itself supports webhooks, and I&#39;d love to improve our admin hooks in
  206. the future. Today we get a Discord message when a report is created, but it&#39;s
  207. not very readable and there&#39;s no ability to update the initial message when the
  208. report is actioned. &lt;code&gt;webhook&lt;/code&gt; feels like a good starting place to improve that
  209. experience.&lt;/p&gt;
  210. </content>
  211.  </entry>
  212.  <entry>
  213.    <title>Migrating xoxo.zone to OVHcloud</title>
  214.    <link href="https://sixohthree.com/blog/2025/migrating-xoxo-zone-to-ovhcloud/" />
  215.    <updated>2025-04-10T00:00:00Z</updated>
  216.    <id>https://sixohthree.com/blog/2025/migrating-xoxo-zone-to-ovhcloud/</id>
  217.    <content type="html">&lt;p&gt;Mastodon hosted on &lt;a href=&quot;https://xoxo.zone/&quot;&gt;xoxo.zone&lt;/a&gt; is now living on its new server at OVHcloud.
  218. We were hosted at Hetzner for &lt;a href=&quot;https://xoxo.zone/docs/&quot;&gt;just about 2 years&lt;/a&gt;, but draconian terms of
  219. service and &lt;a href=&quot;https://tenforward.blog/hetzner-considered-hostile-a-psa/&quot;&gt;some scary experiences&lt;/a&gt; for other communities made the move
  220. inevitable. I evaluated a few EU-based hosts, including Netcup and Scaleway. OVH
  221. hit the sweet spot of pricing, specs, and terms of use.&lt;/p&gt;
  222. &lt;h2&gt;We built this shitty&lt;/h2&gt;
  223. &lt;p&gt;Due to a miscalculation, the server I provisioned on Hetzner used spinning rust
  224. HDDs instead of SSDs. This gave us a ton of storage overhead we didn&#39;t need, and
  225. was also slow as fuck and made many simple things very painful. Even git
  226. operations and restarting services could take minutes instead of seconds.&lt;/p&gt;
  227. &lt;p&gt;The upgrade to Mastodon v4.2.0 last October was particularly painful. I first
  228. upgraded the server from Ubuntu 20.04 to Ubuntu 22.04, and planned to keep going
  229. to Ubuntu 24.04. This required a PostgreSQL upgrade from v15 to v17. I started
  230. this upgrade at 15:00, and gave up for the day when the database finally
  231. finished rebuilding at 01:30. The server was down the whole time. Bummer.&lt;/p&gt;
  232. &lt;h2&gt;A lot of effort went into making this look effortless&lt;/h2&gt;
  233. &lt;p&gt;A challenge of running a server like this is needing to know a little bit about
  234. everything. It was clear to me that I could do better than 10.5 hours of
  235. downtime, but I wasn&#39;t sure how to get there. I&#39;ve done a lot of reading about
  236. PostgreSQL migration strategies since October.&lt;/p&gt;
  237. &lt;p&gt;The server database is backed up twice a day. The &lt;code&gt;pg_dump&lt;/code&gt; takes about 2 hours,
  238. and the upload is another half hour, to say nothing of restoring the db on a new
  239. host. Not awesome.&lt;/p&gt;
  240. &lt;p&gt;A test &lt;code&gt;rsync --checksum&lt;/code&gt; of the database took about 80 minutes, even for
  241. subsequent rsyncs that (in theory) had to transfer less data.&lt;/p&gt;
  242. &lt;p&gt;Replication was daunting, but I stuck with it. In the end it was pretty painless
  243. and worked &lt;em&gt;extremely&lt;/em&gt; well.&lt;/p&gt;
  244. &lt;p&gt;I created a replication role on the old server, xoxo-4:&lt;/p&gt;
  245. &lt;pre&gt;&lt;code&gt;CREATE ROLE xoxo5 WITH REPLICATION PASSWORD &#39;secret_password&#39; LOGIN;
  246. &lt;/code&gt;&lt;/pre&gt;
  247. &lt;p&gt;And I updated the access rules in &lt;code&gt;/etc/postgresql/17/main/pg_hba.conf&lt;/code&gt;:&lt;/p&gt;
  248. &lt;pre&gt;&lt;code&gt;# Allow replication from xoxo5@10.0.0.5
  249. host    replication     xoxo5           10.0.0.5/32       scram-sha-256
  250. &lt;/code&gt;&lt;/pre&gt;
  251. &lt;p&gt;On the new host, xoxo-5, I emptied out the &lt;code&gt;/var/lib/postgresql/17/main&lt;/code&gt;
  252. directory and enabled replication:&lt;/p&gt;
  253. &lt;pre&gt;&lt;code&gt;sudo -u postgres pg_basebackup -h 10.0.0.4 -p 5432 -U xoxo5 -D /var/lib/postgresql/17/main/ -Fp -Xs -R
  254. &lt;/code&gt;&lt;/pre&gt;
  255. &lt;p&gt;This took a few hours but it was worth every second. Once the backup was done,
  256. the results were extremely promising: &lt;code&gt;select * from pg_stat_replication&lt;/code&gt; and
  257. &lt;a href=&quot;https://pgmetrics.io/&quot;&gt;pgmetrics&lt;/a&gt; showed delays in the milliseconds, and spot checking counts in
  258. the &lt;code&gt;statuses&lt;/code&gt; and &lt;code&gt;accounts&lt;/code&gt; tables looked good (other than &lt;code&gt;count(*)&lt;/code&gt; taking
  259. over 10 minutes on xoxo-4).&lt;/p&gt;
  260. &lt;p&gt;In theory the hardest, slowest part was done: the 88GB database was ready for
  261. cutover whenever we were.&lt;/p&gt;
  262. &lt;h2&gt;Not zero-downtime but I remain chuffed&lt;/h2&gt;
  263. &lt;p&gt;I was emboldened by successful replication and from listening to Eurovision
  264. playlists at high volume for the previous hour. After some encouraging words
  265. like &amp;quot;why not&amp;quot; and &amp;quot;if you fuck this up maybe i can focus on work,&amp;quot; I finalised
  266. a migration plan and kicked things off.&lt;/p&gt;
  267. &lt;p&gt;&lt;img src=&quot;https://sixohthree.com/media/2025/04/focus.png&quot; alt=&quot;Screenshot from Discord, Clarity says: thinking emoji, if it goes wrong and the server crashes that&#39;ll probably just help me focus on work better&quot;&gt;&lt;/p&gt;
  268. &lt;p&gt;I had done a lot of work already at this point:&lt;/p&gt;
  269. &lt;ul&gt;
  270. &lt;li&gt;I had run the &lt;a href=&quot;https://docs.joinmastodon.org/admin/install/&quot;&gt;server setup guide&lt;/a&gt; and finished an initial rsync on some
  271. key directories, including the nginx config&lt;/li&gt;
  272. &lt;li&gt;A bunch of server config, including Mastodon service files, backup
  273. configuration, and crons are in an Ansible playbook, which I had already run&lt;/li&gt;
  274. &lt;li&gt;The domain TTL was already ramped down to 60 seconds&lt;/li&gt;
  275. &lt;/ul&gt;
  276. &lt;p&gt;Winding down xoxo-4 looked like this:&lt;/p&gt;
  277. &lt;pre&gt;&lt;code&gt;mastodon-bounce stop all     # wrapper script that runs systemctl on all mastodon services
  278. mastodon-bounce disable all
  279. systemctl disable --now redis-server.service
  280. &lt;/code&gt;&lt;/pre&gt;
  281. &lt;p&gt;Bringing things back up on xoxo-5 looked like this:&lt;/p&gt;
  282. &lt;pre&gt;&lt;code&gt;/root/sync.sh # /home/mastodon/live, /var/lib/redis, /etc/letsencrypt, /etc/nginx
  283. pg_ctlcluster 17 main promote
  284. systemctl enable --now redis-server.service
  285. mastodon-bounce start all
  286. mastodon-bounce enable all
  287. RAILS_ENV=production ./bin/tootctl feeds build
  288. RAILS_ENV=production ./bin/tootctl search deploy
  289. &lt;/code&gt;&lt;/pre&gt;
  290. &lt;p&gt;I would also run a few SQL commands to check data consistency:&lt;/p&gt;
  291. &lt;pre&gt;&lt;code&gt;sudo -u postgres psql -c &#39;&#92;x&#39; -c &#39;select * from pg_stat_replication&#39;
  292. time sudo -u mastodon psql mastodon_production -c &amp;quot;select count(1) from statuses&amp;quot;
  293. time sudo -u mastodon psql mastodon_production -c &amp;quot;select id, created_at from statuses order by created_at desc limit 10&amp;quot;
  294. time sudo -u mastodon psql mastodon_production -c &amp;quot;select count(1) from accounts&amp;quot;
  295. &lt;/code&gt;&lt;/pre&gt;
  296. &lt;h2&gt;Job&#39;s done&lt;/h2&gt;
  297. &lt;p&gt;The migration took about 15 minutes from start to finish. Next time, with SSD
  298. hosts on both sides, I could probably get it down to seconds or maybe even zero
  299. downtime.&lt;/p&gt;
  300. &lt;p&gt;I did hit one snag that was obfuscated by caching in the Mastodon service
  301. worker: the mastodon account&#39;s home directory was created with permissions
  302. &lt;code&gt;0750&lt;/code&gt;, and Nginx could not read files in the web directory, causing a lot of
  303. busted client pages for about 30 minutes after I &amp;quot;finished&amp;quot; the migration.
  304. There&#39;s always something.&lt;/p&gt;
  305. &lt;p&gt;But still! It&#39;s done and I&#39;m happy with how it went.&lt;/p&gt;
  306. &lt;p&gt;Let&#39;s not do it again for a long time.&lt;/p&gt;
  307. </content>
  308.  </entry>
  309.  <entry>
  310.    <title>XOXO 2024</title>
  311.    <link href="https://sixohthree.com/blog/2024/xoxo-2024/" />
  312.    <updated>2024-08-27T00:00:00Z</updated>
  313.    <id>https://sixohthree.com/blog/2024/xoxo-2024/</id>
  314.    <content type="html">&lt;p&gt;&lt;img src=&quot;https://sixohthree.com/media/2024/08/badges.jpg&quot; alt=&quot;Five XOXO Festival badges&quot;&gt; &lt;em&gt;Badge lineup: 2015, 2016, 2018, 2019, 2024&lt;/em&gt;&lt;/p&gt;
  315. &lt;p&gt;The final XOXO Festival wrapped up this weekend in Portland, Oregon. It was my
  316. fifth XOXO, and it&#39;s been 5 years since the previous festival, XOXO 2019.&lt;/p&gt;
  317. &lt;p&gt;Five years is a long time. Maybe long enough that, like me, you see a change in
  318. yourself. Since 2019, I&#39;m a little frayed around the edges, more cautious, more
  319. reserved in the face of an unfriendly world.&lt;/p&gt;
  320. &lt;p&gt;I have allowed myself to harden in the past five years. I saw it happening and I
  321. fucking leaned in. It was a learned response to a hostile environment. The
  322. timeline of this blog is a reflection of that change: withdrawal, retreat, a
  323. reluctance to engage.&lt;/p&gt;
  324. &lt;p&gt;XOXO is an event, yes. It&#39;s a particular point in time with a beginning and an
  325. end. But XOXO is also a feeling of curiosity, a sense of wonder, a rejection of
  326. cynicism, a community. A reminder. &lt;a href=&quot;https://xoxo.zone/@jkent/113036275692117626&quot;&gt;A dream&lt;/a&gt;.&lt;/p&gt;
  327. &lt;p&gt;XOXO is made of people. This weekend, those people reminded me what it&#39;s like to
  328. allow myself to feel joy and hope. I saw a lot of old friends and maybe made
  329. some new ones. I heard their stories and felt their excitement. Hibernating
  330. parts of me woke up, did a little stretch, and thought maybe it&#39;s time to leave
  331. the cave.&lt;/p&gt;
  332. &lt;p&gt;It&#39;s easy to harden up. &lt;a href=&quot;https://www.youtube.com/watch?v=cNwy1Th4NYo&quot;&gt;Only natural&lt;/a&gt;, as I heard through &lt;a href=&quot;https://aratin.gay/&quot;&gt;a friend&lt;/a&gt;.
  333. Going soft again is not so easy. All these great people make me want to at least
  334. try.&lt;/p&gt;
  335. &lt;p&gt;There will not be another XOXO Festival, but there are many people who embody
  336. its spirit, whether they associate it with the festival or not. I will try to
  337. remember that without the festival&#39;s periodic reminder.&lt;/p&gt;
  338. &lt;p&gt;&lt;img src=&quot;https://sixohthree.com/media/2024/08/tent.jpg&quot; alt=&quot;People at night on a lawn under strings of lights, in front of a large white tent&quot;&gt;
  339. &lt;em&gt;The traditional &amp;quot;leaving XOXO&amp;quot; shot, 2024&lt;/em&gt;&lt;/p&gt;
  340. &lt;h2&gt;Collected XOXO 2024 Posts&lt;/h2&gt;
  341. &lt;ul&gt;
  342. &lt;li&gt;&lt;a href=&quot;https://www.spideyj.com/the-final-xoxo/&quot;&gt;The Final XOXO&lt;/a&gt; by Kit Jones
  343. (SpideyJ)&lt;/li&gt;
  344. &lt;li&gt;&lt;a href=&quot;https://hey.georgie.nu/post-xoxo/&quot;&gt;some thoughts (but not enough thoughts), post-XOXO 2024&lt;/a&gt;
  345. by Georgie&lt;/li&gt;
  346. &lt;li&gt;&lt;a href=&quot;https://buttondown.com/hupfen/archive/this-will-all-end-in-tears/&quot;&gt;This Will All End in Tears&lt;/a&gt;
  347. by Zoe Landon&lt;/li&gt;
  348. &lt;li&gt;&lt;a href=&quot;https://lyonheart.us/xoxo-2024/&quot;&gt;My experience of XOXO 2024&lt;/a&gt; by Matthew Lyon&lt;/li&gt;
  349. &lt;li&gt;&lt;a href=&quot;https://brookshelley.com/posts/2024-08-27-xoxo/&quot;&gt;The Last XOXO: 2024&lt;/a&gt; by
  350. Brook Shelley&lt;/li&gt;
  351. &lt;li&gt;&lt;a href=&quot;https://kottke.org/24/08/thanks-xoxo&quot;&gt;Thanks, XOXO&lt;/a&gt; by Jason Kottke&lt;/li&gt;
  352. &lt;li&gt;&lt;a href=&quot;https://phildini.dev/xoxo-2024&quot;&gt;XOXO 2024&lt;/a&gt; by Phil Dini&lt;/li&gt;
  353. &lt;li&gt;&lt;a href=&quot;https://bamoon.com/my-first-year-with-xoxo/&quot;&gt;My first year with XOXO&lt;/a&gt; by
  354. Brian Moon&lt;/li&gt;
  355. &lt;li&gt;&lt;a href=&quot;https://justinpot.com/the-internet-doesnt-have-to-feel-like-this/&quot;&gt;The internet doesn’t have to feel like this&lt;/a&gt;
  356. by Justin Pot&lt;/li&gt;
  357. &lt;li&gt;&lt;a href=&quot;https://netninja.com/2024/08/29/lowering-expectations-one-project-at-a-time/&quot;&gt;Lowering Expectations, One Project at a Time&lt;/a&gt;
  358. by BrianEnigma&lt;/li&gt;
  359. &lt;li&gt;&lt;a href=&quot;https://geekdad.com/2024/08/creating-community-at-xoxo/&quot;&gt;Creating Community at XOXO&lt;/a&gt;
  360. by Jonathan Liu&lt;/li&gt;
  361. &lt;li&gt;&lt;a href=&quot;https://jrubenoff.com/writing/xoxo-festival/&quot;&gt;XOXO taught me it was OK to be weird&lt;/a&gt;
  362. by Josh Rubenoff&lt;/li&gt;
  363. &lt;li&gt;&lt;a href=&quot;https://benjaminchait.net/archives/xoxo-2024&quot;&gt;XOXO 2024&lt;/a&gt; by Benjamin Chait&lt;/li&gt;
  364. &lt;li&gt;&lt;a href=&quot;https://emorydunn.com/blog/2024/09/xoxo/&quot;&gt;XOXO&lt;/a&gt; by Emory Dunn&lt;/li&gt;
  365. &lt;li&gt;&lt;a href=&quot;https://open.substack.com/pub/byvishmili/p/spotted-a-deep-dive-into-the-digital&quot;&gt;Spotted: A deep dive into the digital jungle, where the survival of the fittest isn’t about brawn but brains—and a little (a lot of) kindness, too&lt;/a&gt;
  366. by Višnja Milidragović&lt;/li&gt;
  367. &lt;li&gt;&lt;a href=&quot;https://jwithy.weblog.lol/2024/09/it-has-been-a-time&quot;&gt;It has been a time&lt;/a&gt; by
  368. Jim Withington&lt;/li&gt;
  369. &lt;li&gt;&lt;a href=&quot;https://www.mmmx.cloud/after-xoxo&quot;&gt;After xoxo&lt;/a&gt; by Ním Daghlian&lt;/li&gt;
  370. &lt;li&gt;&lt;a href=&quot;https://clarity.flowers/journal/goodbye_xoxo.html&quot;&gt;goodbye, xoxo&lt;/a&gt; by clarity
  371. flowers&lt;/li&gt;
  372. &lt;li&gt;&lt;a href=&quot;https://www.rawsignal.ca/newsletter-archive/lower-your-expectations&quot;&gt;Lower your expectations&lt;/a&gt;
  373. by Johnathan and Melissa Nightingale&lt;/li&gt;
  374. &lt;li&gt;&lt;a href=&quot;https://arun.is/blog/farewell-xoxo/&quot;&gt;Farewell, XOXO&lt;/a&gt; by Arun Venkatesan&lt;/li&gt;
  375. &lt;li&gt;Photo album:
  376. &lt;a href=&quot;https://www.flickr.com/photos/linkletter/albums/72177720320167689/&quot;&gt;XOXO Festival 2024&lt;/a&gt;
  377. by Ian Linkletter&lt;/li&gt;
  378. &lt;/ul&gt;
  379. </content>
  380.  </entry>
  381.  <entry>
  382.    <title>Marshall Turner Moulton, 1928-2022</title>
  383.    <link href="https://sixohthree.com/blog/2022/marshall-turner-moulton/" />
  384.    <updated>2022-07-27T00:00:00Z</updated>
  385.    <id>https://sixohthree.com/blog/2022/marshall-turner-moulton/</id>
  386.    <content type="html">&lt;p&gt;January 3, 1928 - July 22, 2022. Rest in peace, Grampy.&lt;/p&gt;
  387. &lt;p&gt;&lt;img src=&quot;https://sixohthree.com/media/2022/mtm.jpg&quot; alt=&quot;Marshall Turner Moulton&quot;&gt;&lt;/p&gt;
  388. </content>
  389.  </entry>
  390.  <entry>
  391.    <title>Introductions</title>
  392.    <link href="https://sixohthree.com/blog/2022/introductions/" />
  393.    <updated>2022-04-26T00:00:00Z</updated>
  394.    <id>https://sixohthree.com/blog/2022/introductions/</id>
  395.    <content type="html">&lt;p&gt;Is Elon Musk buying Twitter? Maybe.&lt;/p&gt;
  396. &lt;p&gt;Is the Fediverse hoppin&#39;? Definitely.&lt;/p&gt;
  397. &lt;p&gt;&lt;img src=&quot;https://sixohthree.com/media/2022/introductions.png&quot; alt=&quot;introductions&quot;&gt;&lt;/p&gt;
  398. </content>
  399.  </entry>
  400.  <entry>
  401.    <title>Hollybank Road</title>
  402.    <link href="https://sixohthree.com/blog/2022/hollybank-road/" />
  403.    <updated>2022-03-31T00:00:00Z</updated>
  404.    <id>https://sixohthree.com/blog/2022/hollybank-road/</id>
  405.    <content type="html">&lt;p&gt;Air thick with the smell of spring onions.&lt;/p&gt;
  406. &lt;p&gt;Cool beers and good craic over the garden wall on any night of the week.&lt;/p&gt;
  407. &lt;p&gt;That&#39;s what I will carry with me.&lt;/p&gt;
  408. </content>
  409.  </entry>
  410. </feed>

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid Atom 1.0" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//blogs.bwerp.net/feeds/atom.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda