<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>selfhosting &amp;mdash; Nat Knight</title>
    <link>http://natknight.xyz/tag:selfhosting</link>
    <description>Reflections, diversions, and opinions from a progressive ex-physicist programmer dad with a sore back.</description>
    <pubDate>Sat, 23 May 2026 15:49:12 -0700</pubDate>
    <item>
      <title>Migrating Follows from GoToSocial to Mastodon</title>
      <link>http://natknight.xyz/migrating-follows-from-gotosocial-to-mastodon</link>
      <description>&lt;![CDATA[#selfhosting #fediverse #mastodon #gotosocial #sqlite&#xA;&#xA;This article describes how to migrate your subscriptions from GotoSocial] to [Mastodon]. I recently made this migration; I talk about my motivations [here.&#xA;&#xA;[Mastodon]: https://github.com/mastodon/mastodon&#xA;[GotoSocial]: https://docs.gotosocial.org/en/latest/&#xA;&#xA;This procedure doesn&#39;t handle getting folks over to your new account. It will get you a list of your subscriptions that you can import with Mastodon&#39;s data import feature so you don&#39;t have to re-follow everyone by hand.&#xA;&#xA;I&#39;m not aware of an account migration or user-facing data export feature in GotoSocial, so you&#39;ll need access to your instance&#39;s database (or help from someone who has it, anyways). With those caveats out of the way, here&#39;s the procedure.&#xA;&#xA;!--more--&#xA;&#xA;Extract your Subscriptions&#xA;&#xA;To get your subscriptions (or &#34;Follows&#34;, as the database calls them), you&#39;ll first need to get your user id:&#xA;&#xA;SELECT username, id&#xA;FROM accounts&#xA;WHERE username = &#39;YOURUSERNAMEHERE&#39;&#xA;&#xA;Once you&#39;ve got the id, you can plug it into the following query to get your follow list:&#xA;&#xA;SELECT&#xA;  accounts.username || &#39;@&#39; || accounts.domain&#xA;  AS &#39;Account address&#39;&#xA;FROM accounts&#xA;JOIN follows ON accounts.id = follows.targetaccountid&#xA;WHERE follows.accountid = &#39;YOURID_HERE&#39;&#xA;&#xA;You&#39;ll need the results of this query as a CSV file. There are lots of ways to do that; I used the CSV export feature built into Datasette because I was already using it to figure out the data.&#xA;&#xA;Upload to Mastodon&#xA;&#xA;Once you&#39;ve got your follows in a CSV file you should be able to import them using Mastodon&#39;s [data import feature]. It should be available on your Mastodon instance&#39;s Settings page under Import.&#xA;&#xA;[data import feature]: (https://blog.joinmastodon.org/2019/06/how-to-migrate-from-one-server-to-another/#importing-your-data)&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:selfhosting" class="hashtag"><span>#</span><span class="p-category">selfhosting</span></a> <a href="http://natknight.xyz/tag:fediverse" class="hashtag"><span>#</span><span class="p-category">fediverse</span></a> <a href="http://natknight.xyz/tag:mastodon" class="hashtag"><span>#</span><span class="p-category">mastodon</span></a> <a href="http://natknight.xyz/tag:gotosocial" class="hashtag"><span>#</span><span class="p-category">gotosocial</span></a> <a href="http://natknight.xyz/tag:sqlite" class="hashtag"><span>#</span><span class="p-category">sqlite</span></a></p>

<p>This article describes how to migrate your subscriptions from <a href="https://docs.gotosocial.org/en/latest/">GotoSocial</a> to <a href="https://github.com/mastodon/mastodon">Mastodon</a>. I recently made this migration; I talk about my motivations <a href="migrating-to-hachyderm.html">here</a>.</p>

<p>This procedure doesn&#39;t handle getting folks over to your new account. It will get you a list of your subscriptions that you can import with Mastodon&#39;s data import feature so you don&#39;t have to re-follow everyone by hand.</p>

<p>I&#39;m not aware of an account migration or user-facing data export feature in GotoSocial, so you&#39;ll need access to your instance&#39;s database (or help from someone who has it, anyways). With those caveats out of the way, here&#39;s the procedure.</p>



<h2 id="extract-your-subscriptions" id="extract-your-subscriptions">Extract your Subscriptions</h2>

<p>To get your subscriptions (or “Follows”, as the database calls them), you&#39;ll first need to get your user id:</p>

<pre><code class="language-sql">SELECT username, id
FROM accounts
WHERE username = &#39;YOUR_USERNAME_HERE&#39;
</code></pre>

<p>Once you&#39;ve got the <code>id</code>, you can plug it into the following query to get your follow list:</p>

<pre><code class="language-sql">SELECT
  accounts.username || &#39;@&#39; || accounts.domain
  AS &#39;Account address&#39;
FROM accounts
JOIN follows ON accounts.id = follows.target_account_id
WHERE follows.account_id = &#39;YOUR_ID_HERE&#39;
</code></pre>

<p>You&#39;ll need the results of this query as a CSV file. There are lots of ways to do that; I used the CSV export feature built into <a href="https://datasette.io/">Datasette</a> because I was already using it to figure out the data.</p>

<h2 id="upload-to-mastodon" id="upload-to-mastodon">Upload to Mastodon</h2>

<p>Once you&#39;ve got your follows in a CSV file you should be able to import them using Mastodon&#39;s data import feature. It should be available on your Mastodon instance&#39;s <code>Settings</code> page under <code>Import</code>.</p>
]]></content:encoded>
      <guid>http://natknight.xyz/migrating-follows-from-gotosocial-to-mastodon</guid>
      <pubDate>Wed, 22 Feb 2023 08:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Migrating to Hachyderm</title>
      <link>http://natknight.xyz/migrating-to-hachyderm</link>
      <description>&lt;![CDATA[#selfhosting #mastodon #fediverse #hachyderm&#xA;&#xA;As the trajectory of the bird site got clearer and nastier late last year I decided to migrate to the fediverse. I didn&#39;t want to end up on another platform controlled by a petulant tinpot dictator, so I decided to see if I could host my own [ActivityPub] server. [Mastodon] looked pretty intimidating, but [GotoSocial] is a smaller, lighter, program that (approximately) inter-operates with Mastodon (yay, federation!).&#xA;&#xA;[Mastodon]: https://github.com/mastodon/mastodon&#xA;[GotoSocial]: https://docs.gotosocial.org/en/latest/&#xA;[ActivityPub]: https://en.wikipedia.org/wiki/ActivityPub&#xA;&#xA;!--more--&#xA;&#xA;I ran that server for a couple of months, but eventually decided to shut it down and migrate to [Hachyderm.io]. I did this for a couple of reasons:&#xA;&#xA;[Hachyderm.io]: https://hachyderm.io&#xA;&#xA;GotoSocial ended up being the most resource-intensive thing running on my home-server, and the architecture of ActivityPub meant I was putting (proportionally) more load on other servers than I needed to. This isn&#39;t to say that GotoSocial was doing anything outlandish, but ActivityPub is a chatty protocol and I try to be mindful about spending compute.&#xA;&#xA;Hachyderm has an explicit governance structure, one developed by folks who know what they&#39;re doing a lot better than I do. Holding safe, communal online space seems like a really valuable skill, and I&#39;ll learn it better hanging out on a shared instance  than I will in a private silo.&#xA;&#xA;Atomizing all web hosting into parochial little home-servers isn&#39;t sustainable or desirable, and Hachyderm is a cool project blazing a different trail, so I made a donation to help pay for hosting and made the leap.&#xA;&#xA;I had accumulated a pretty lovely feed of subscriptions, and that kept me locked in for a while, but the beauty of self-hosting is that I had the SQLite database with all my data in it, so I was able to figure out a procedure for migrating (which is described here).&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:selfhosting" class="hashtag"><span>#</span><span class="p-category">selfhosting</span></a> <a href="http://natknight.xyz/tag:mastodon" class="hashtag"><span>#</span><span class="p-category">mastodon</span></a> <a href="http://natknight.xyz/tag:fediverse" class="hashtag"><span>#</span><span class="p-category">fediverse</span></a> <a href="http://natknight.xyz/tag:hachyderm" class="hashtag"><span>#</span><span class="p-category">hachyderm</span></a></p>

<p>As the trajectory of the bird site got clearer and nastier late last year I decided to migrate to the fediverse. I didn&#39;t want to end up on another platform controlled by a petulant tinpot dictator, so I decided to see if I could host my own <a href="https://en.wikipedia.org/wiki/ActivityPub">ActivityPub</a> server. <a href="https://github.com/mastodon/mastodon">Mastodon</a> looked pretty intimidating, but <a href="https://docs.gotosocial.org/en/latest/">GotoSocial</a> is a smaller, lighter, program that (approximately) inter-operates with Mastodon (yay, federation!).</p>



<p>I ran that server for a couple of months, but eventually decided to shut it down and migrate to <a href="https://hachyderm.io">Hachyderm.io</a>. I did this for a couple of reasons:</p>
<ul><li><p>GotoSocial ended up being the most resource-intensive thing running on my home-server, and the architecture of ActivityPub meant I was putting (proportionally) more load on other servers than I needed to. This isn&#39;t to say that GotoSocial was doing anything outlandish, but ActivityPub is a chatty protocol and I try to be mindful about spending compute.</p></li>

<li><p>Hachyderm has an explicit <a href="https://nivenly.org/">governance structure</a>, one developed by folks who know what they&#39;re doing a lot better than I do. Holding safe, communal online space seems like a really valuable skill, and I&#39;ll learn it better hanging out on a shared instance  than I will in a private silo.</p></li></ul>

<p>Atomizing all web hosting into parochial little home-servers isn&#39;t sustainable or desirable, and Hachyderm is a cool project blazing a different trail, so I made a donation to help pay for hosting and made the leap.</p>

<p>I had accumulated a pretty lovely feed of subscriptions, and that kept me locked in for a while, but the beauty of self-hosting is that I had the SQLite database with all my data in it, so I was able to figure out a procedure for migrating (which is described <a href="/migrating-follows-from-gotosocial-to-mastodon">here</a>).</p>
]]></content:encoded>
      <guid>http://natknight.xyz/migrating-to-hachyderm</guid>
      <pubDate>Wed, 22 Feb 2023 08:00:00 +0000</pubDate>
    </item>
    <item>
      <title>A TiddlyWiki Server in Rust</title>
      <link>http://natknight.xyz/a-tiddlywiki-server-in-rust</link>
      <description>&lt;![CDATA[#tiddlywiki #rust #selfhosting #release&#xA;&#xA;I just published the first (v0.1.0) release of tiddly-wiki-server, which implements the TiddlyWiki WebServer API in Rust using Axum, SerDe, and TiddlyWiki.&#xA;&#xA;!--more--&#xA;&#xA;Motivation&#xA;&#xA;One might ask why a new TiddlyWiki server is necessary, since&#xA;&#xA;TiddlyWiki5 includes a first-party NodeJS web server, and&#xA;one of TiddlyWiki&#39;s beautiful features is that it works as as static HTML file.&#xA;&#xA;These are valid points. I confess, this project fulfills quite a narrow use case: I like to self-host my tools on a small, cheap VPS, and the first-party NodeJS server consumes about 100MB of RAM. This isn&#39;t huge, but it&#39;s a decent chunk of my available resources. This server consumes much less (about 10MB, and that&#39;s before I&#39;ve done anything to optimize it).&#xA;&#xA;This was also a project that let me combine two technologies that I like an awful lot, so if it seems self-indulgent, well... maybe it is. &#xA;&#xA;Components&#xA;&#xA;The server makes use of some very nice Crates; I&#39;ll mention some of the big ones:&#xA;&#xA;dl&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/axum&#34;axum/a, a web framework&#xA;/dt&#xA;dd&#xA;I&#39;ve tried a number of Rust web frameworks (Tide, Rocket, simple-http-server); this one&#39;s the first one I feel like I really understood and was productive with (though that might also just be that I&#39;m slowly getting better at Rust). Of particular note is that Axum is compatible with a href=&#34;https://crates.io/crates/tower-http&#34;tower-http/a , so many services and middlewares that you might want already exist.&#xA;/dd&#xA;&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/rusqlite&#34;rusqlite/a, a SQLite binding/a&#xA;/dt&#xA;dd&#xA;I use SQLite for most of my tiny side projects; this one&#39;s no exception. The TiddlyWiki back end mostly treats tiddlers as opaque bags of objects, so the database is little more than a key-value store.&#xA;/dd&#xA;&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/serdejson&#34;serdejson/a, a loosely-typed JSON interface&#xA;/dt&#xA;dd&#xA;If you&#39;re reading about Rust you&#39;re probably familiar with serde, but since I wanted to retain TiddlyWiki&#39;s fairly open schema I needed an ergonomic way to work with un-typed JSON objects.&#xA;/dd&#xA;&#xA;/dl&#xA;&#xA;Future Work&#xA;&#xA;There are lots of ways this project could be added or improved:&#xA;&#xA;More testing; I want this server to be feature-compatible with the first party server.&#xA;User authentication and access control&#xA;Streaming large responses to keep memory small&#xA;&#xA;If any of that sounds interesting to you, pull requests and bug reports are very much welcome!&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:tiddlywiki" class="hashtag"><span>#</span><span class="p-category">tiddlywiki</span></a> <a href="http://natknight.xyz/tag:rust" class="hashtag"><span>#</span><span class="p-category">rust</span></a> <a href="http://natknight.xyz/tag:selfhosting" class="hashtag"><span>#</span><span class="p-category">selfhosting</span></a> <a href="http://natknight.xyz/tag:release" class="hashtag"><span>#</span><span class="p-category">release</span></a></p>

<p>I just published the first (v0.1.0) release of <a href="https://github.com/nathanielknight/tiddly-wiki-server">tiddly-wiki-server</a>, which implements the <a href="https://tiddlywiki.com/#WebServer%20API">TiddlyWiki WebServer API</a> in Rust using Axum, SerDe, and TiddlyWiki.</p>



<h2 id="motivation" id="motivation">Motivation</h2>

<p>One might ask why a new TiddlyWiki server is necessary, since</p>
<ul><li>TiddlyWiki5 includes a first-party NodeJS web server, and</li>
<li>one of TiddlyWiki&#39;s beautiful features is that it works as as static HTML file.</li></ul>

<p>These are valid points. I confess, this project fulfills quite a narrow use case: I like to self-host my tools on a small, cheap VPS, and the first-party NodeJS server consumes about 100MB of RAM. This isn&#39;t huge, but it&#39;s a decent chunk of my available resources. This server consumes much less (about 10MB, and that&#39;s before I&#39;ve done anything to optimize it).</p>

<p>This was also a project that let me combine two technologies that I like an awful lot, so if it seems self-indulgent, well... maybe it is.</p>

<h2 id="components" id="components">Components</h2>

<p>The server makes use of some very nice Crates; I&#39;ll mention some of the big ones:</p>

<dl>
<dt>
  <a href="https://crates.io/crates/axum">axum</a>, a web framework
</dt>
<dd>
I&#39;ve tried a number of Rust web frameworks (Tide, Rocket, simple-http-server); this one&#39;s the first one I feel like I really understood and was productive with (though that might also just be that I&#39;m slowly getting better at Rust). Of particular note is that Axum is compatible with <a href="https://crates.io/crates/tower-http">tower-http</a> , so many services and middlewares that you might want already exist.
</dd>

<dt>
  <a href="https://crates.io/crates/rusqlite">rusqlite</a>, a SQLite binding</a>
</dt>
<dd>
I use SQLite for most of my tiny side projects; this one&#39;s no exception. The TiddlyWiki back end mostly treats tiddlers as opaque bags of objects, so the database is little more than a key-value store.
</dd>

<dt>
  <a href="https://crates.io/crates/serde_json">serde_json</a>, a loosely-typed JSON interface
</dt>
<dd>
If you&#39;re reading about Rust you&#39;re probably familiar with serde, but since I wanted to retain TiddlyWiki&#39;s fairly open schema I needed an ergonomic way to work with un-typed JSON objects.
</dd>

</dl>

<h2 id="future-work" id="future-work">Future Work</h2>

<p>There are lots of ways this project could be added or improved:</p>
<ul><li>More testing; I want this server to be feature-compatible with the first party server.</li>
<li>User authentication and access control</li>
<li>Streaming large responses to keep memory small</li></ul>

<p>If any of that sounds interesting to you, pull requests and bug reports are very much welcome!</p>
]]></content:encoded>
      <guid>http://natknight.xyz/a-tiddlywiki-server-in-rust</guid>
      <pubDate>Mon, 27 Jun 2022 07:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>