<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like apple-google-aligned-incentives, simple-backups-restic-hetzner but not migrating-from-github-to-forgejo, why-you-should-be-using-https</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/apple-google-aligned-incentives,simple-backups-restic-hetzner/unlike/migrating-from-github-to-forgejo,why-you-should-be-using-https/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2025-11-01T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>Thinking more about backups</title>
        <link href="https://chameth.com/thinking-more-about-backups/"/>
        <updated>2025-11-01T00:00:00Z</updated>
        <id>https://chameth.com/thinking-more-about-backups/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/thinking-more-about-backups/backblaze.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/thinking-more-about-backups/backblaze.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/thinking-more-about-backups/backblaze.png&#34; alt=&#34;The Backblaze logo: a stylised flame above the word Backblaze&#34; loading=&#34;lazy&#34; width=&#34;500&#34; height=&#34;320&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The Backblaze logo&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Almost a year ago I wrote about &lt;a href=&#34;https://chameth.com/simple-backups-restic-hetzner/&#34;&gt;how I do backups with Restic and Hetzner&lt;/a&gt;.
That system has been ticking along well ever since, but recently I had some… thoughts. These backups are
all well and good if I accidentally delete a file, or a database gets corrupted, or something, but there are
two glaring issues:&lt;/p&gt;
&lt;p&gt;Firstly, I’m backing up my Hetzner server to Hetzner cloud storage. If something happens to Hetzner — or
my Hetzner account — then all my eggs go down with that basket. Obviously Hetzner are a big organisation
and aren’t likely to just vanish overnight, but I’m less confident about my account. Could a false abuse
report get it suspended? What if the UK passes
&lt;a href=&#34;https://www.legislation.gov.uk/ukpga/2023/50/contents&#34;&gt;even more dumb laws&lt;/a&gt; and Hetzner decide it’s easier
just to not do business with people here? This is the same sort of concern I have about Google accounts:
if you have half of your life in Google Drive and Google Mail, what happens if you comment on a YouTube
video, get flagged by an AI moderation process, and your account gets suspended? It’s probably not very
likely, but these are things my brain likes to dwell on.&lt;/p&gt;
&lt;p&gt;Secondly, the credentials to access the backups sit on each machine that is backed up. If someone malicious
gained access to the machine, they’d also have access to delete or tamper with all the backups. It feels
a little silly that the same attack could take down both the originals and the backups. There’s no way to
avoid that with Hetzner’s S3 implementation, as far as I can tell.&lt;/p&gt;
&lt;h3 id=&#34;exploring-options&#34;&gt;Exploring options&lt;/h3&gt;
&lt;p&gt;I toyed with the idea of making local copies of the backups, but the only way to avoid the same problems
would be to keep them offline and do a manual copy every now and then. I didn’t really want to do that,
and was concerned that if I did a monthly offline backup then I stood to lose up to a month of data in
the worst case.&lt;/p&gt;
&lt;p&gt;I then looked around at other S3 providers. &lt;a href=&#34;https://aws.amazon.com/s3/storage-classes/glacier/&#34;&gt;Amazon’s glacier offering&lt;/a&gt;
is tempting due to its very low storage costs, but you pay for that if you ever want to restore anything.
There are also lots of weird pricing edge cases around moving data between storage classes, minimum file
sizes, and so on. A much better option is &lt;a href=&#34;https://www.backblaze.com/cloud-storage&#34;&gt;Backblaze’s B2&lt;/a&gt; product.
Their pricing is much more straight-forward, and they have an interesting feature that’s particularly useful
in this case: &lt;a href=&#34;https://www.backblaze.com/blog/backblaze-b2-lifecycle-rules/&#34;&gt;lifecycle rules&lt;/a&gt;. Coupled with
the ability to create API keys that don’t have access to delete files (just “hide” them), this allows for
what’s effectively an append-only store.&lt;/p&gt;
&lt;p&gt;This works more-or-less out of the box with Restic. &lt;a href=&#34;https://pricey.uk/blog/restic-backups-without-delete/&#34;&gt;Joseph Price has a guide&lt;/a&gt;
that goes into the setup in a bit more depth. Basically, whenever Restic would delete a file (e.g. during
a “forget” or “prune” operation), it instead gets hidden and is only deleted when the B2 lifecycle rules
decide it should be. I’ve kept the existing Hetzner S3 backups for now, and just added an extra step to
the end of my script: a simple &lt;code&gt;restic copy&lt;/code&gt; and a &lt;code&gt;restic forget&lt;/code&gt;. B2 actually works out cheaper than the
Hetzner storage, as they don’t bill you for a minimum of 1TB storage; my current usage is around $3/month.
Not a bad price for some extra peace of mind!&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Further Adventures in Music Organisation</title>
        <link href="https://chameth.com/further-adventures-in-music-organisation/"/>
        <updated>2025-09-21T00:00:00Z</updated>
        <id>https://chameth.com/further-adventures-in-music-organisation/</id>
        <content xml:lang="en" type="html">&lt;p&gt;I wrote before about how I’d &lt;a href=&#34;https://chameth.com/escaping-spotify-the-hard-way/&#34;&gt;dropped Spotify in favour of locally stored music&lt;/a&gt;,
but things have advanced a bit since. I had a few issues: Tauon would
occasionally manage to lose its database and along with it all my carefully
constructed playlists and song ratings&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and the experience on my phone was
not very fun.&lt;/p&gt;
&lt;p&gt;I had to manually sync the music by plugging my phone in to the
computer, and sometimes it just refused to mount the right partition. I don’t
think there’s really a good way to debug an Apple phone not behaving properly
when connected to a Linux desktop. Then I started wanting more than one playlist
synced&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, and trying to find a way to make that work just broke me.&lt;/p&gt;
&lt;p&gt;I spent a while looking at different ways of hosting the music centrally.
&lt;a href=&#34;https://www.plex.tv/en-gb/plexamp/&#34;&gt;Plexamp&lt;/a&gt; gets lots of good reviews, and
I’ve used Plex a fair bit. I set about spinning up a Plex server, and just
could not get it working. The server ran fine, served the web interface, but
would neither associate with my account nor run standalone. The docs were
contradictory and there was very little useful logging. After a lot of
frustration, I stumbled across mentions that
&lt;a href=&#34;https://lowendbox.com/blog/plex-blocks-hetzner-in-move-against-piracy/&#34;&gt;Plex block running on Hetzner&lt;/a&gt;.
I assume that’s the cause of my issues, although I have no way to know for sure.
I use Hetzner for all my servers and other hosted services, but Plex have
decided I can’t run the self-hosted software that I have a lifetime subscription
for there. What the actual fuck?&lt;/p&gt;
&lt;p&gt;I could have probably worked around the arbitrary restriction, but I didn’t
want to throw more time down the drain. Instead, I set up
&lt;a href=&#34;https://www.navidrome.org/&#34;&gt;Navidrome&lt;/a&gt;, an open source music server. It
supports the Subsonic protocol, which means you can use a whole slew of
different clients with it (or even write your own). It also means there’s a
nice way to get data in and out of it programmatically, which I recall being
a bit of a fight with Plex.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;syncing-and-organising&#34;&gt;Syncing and organising&lt;/h3&gt;
&lt;p&gt;All my music lived on my desktop, but now I wanted it on my server. At first
I just used &lt;code&gt;rsync&lt;/code&gt; to copy everything up. I’d maintain a local “master” copy,
and periodically shove the changes to the server&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. That quickly got old,
so I set up &lt;a href=&#34;https://syncthing.net/&#34;&gt;Syncthing&lt;/a&gt; to keep the two folders in
sync. That worked… for a while.&lt;/p&gt;
&lt;p&gt;Concurrently, I was looking at improving the organisation of my music. It
was mostly organised by some Go programs I’d thrown together to automate the
importing, with no real validation of metadata or anything else. Some albums
got split up into multiple folders because the tracks had different artists
(and didn’t have an album artist set); some artists ended up with multiple
folders with slight spelling or case variations. It was upsetting.&lt;/p&gt;
&lt;p&gt;I’d used &lt;a href=&#34;https://picard.musicbrainz.org/&#34;&gt;MusicBrainz Picard&lt;/a&gt; before to fix
some issues, but I didn’t really like the UI, especially when trying to do
bulk actions. The main alternative is &lt;a href=&#34;https://beets.io/&#34;&gt;beets&lt;/a&gt;, which
describes itself as “the music geek’s media organiser”, and is entirely
command line. I was intrigued.&lt;/p&gt;
&lt;p&gt;I started playing around with beets, and quickly noticed a problem. Every time
I changed a metadata tag in a music file, Syncthing had to upload the entire
file. I was frequently changing tags across the whole library as I got beets
set up how I wanted, and Syncthing was handling it by uploading gigabytes of
files for every minor change. I was already a bit unhappy with having the
content duplicated in two places, so now I was using a command line organiser
I figured I could just get rid of my local copy and move everything to the
server.&lt;/p&gt;
&lt;p&gt;I set up a Docker container for beets, and then wrote some incredibly hacky
shell scripts so I could run &lt;code&gt;beet&lt;/code&gt; locally on my desktop and it would SSH
to the server over Tailscale and exec into the container, passing the arguments
along. Then I did one final sync of the music library, got rid of Syncthing,
double checked I had a backup and deleted all of my local music.&lt;/p&gt;
&lt;h3 id=&#34;bears-beets-battlestar-galactica&#34;&gt;Bears, Beets, Battlestar Galactica&lt;/h3&gt;
&lt;p&gt;Beets is amazing. It has a vast array of plugins that can do almost anything
you could want with a music library, and the command line workflow works really
well for me. It’s very well documented, and all the individual parts are
pleasingly simple and easy to understand.&lt;/p&gt;
&lt;p&gt;Here’s what it looks like when importing some new music:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/beets-importing.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/beets-importing.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/further-adventures-in-music-organisation/beets-importing.png&#34; alt=&#34;Screenshot of beets output when importing an album. It shows the source folder in blue, the matched metadata information in white with green highlights, the MusicBrainz URL, then a listing of all tracks&#34; loading=&#34;lazy&#34; width=&#34;782&#34; height=&#34;377&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Beets importing an album&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If it doesn’t get a perfect match then it shows the closest matches, and
summarises what’s different about them (missing tracks, different names,
etc), and lets you decide what to do. Aside from the metadata matching, it’s
doing a lot of things under the hood that aren’t necessarily apparent. It:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Looks up the genre from Last.fm&lt;/li&gt;
&lt;li&gt;Analyses all the tracks and writes ReplayGain metadata to them&lt;/li&gt;
&lt;li&gt;Fetches album art&lt;/li&gt;
&lt;li&gt;Checks all the files to make sure they’re actually playable&lt;/li&gt;
&lt;li&gt;Scrubs any existing metadata tags&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also maintains its own database, and you can query against it. The query
language is both simple and quite powerful, like the rest of beets. As an
example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ beet ls artist:&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Linkin Park&amp;#34;&lt;/span&gt; year:2025 length:2:00..2:30 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Linkin Park - From Zero - Casualty
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Almost all the other commands also let you use the query syntax, which makes
the whole tool really powerful. Want to delete all country tracks that you
added last month? No problem. Redownload all the album art for a certain
band? Easy. You can even do smart playlists using the filters.&lt;/p&gt;
&lt;h3 id=&#34;actually-playing-music&#34;&gt;Actually playing music&lt;/h3&gt;
&lt;p&gt;With all this organisation, I’ve not actually mentioned one tiny detail: how
I actually play music now. Navidrome has a web UI, which is perfectly usable,
but I don’t really want my web browser involved as it makes balancing sound
levels tricky, and getting media keys working is a pain. Thankfully there
are loads of Subsonic clients. I’ve tried several, but eventually settled on
&lt;a href=&#34;https://github.com/jeffvli/feishin&#34;&gt;Feishin&lt;/a&gt; on the desktop. It’s very pretty:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/feishin.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/feishin.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/further-adventures-in-music-organisation/feishin.jpg&#34; alt=&#34;A screenshot of Feishin. On the left side of the screen is the album art (Love, Drugs &amp;amp; Misery by Eva Under Fire), with the track, album, artist, year and file format below it. On the right hand side is a tabbed panel, currently showing &amp;#39;Up Next&amp;#39; which shows a queue of music. At the bottom is a standard player interface with play/pause/skip/etc buttons.&#34; loading=&#34;lazy&#34; width=&#34;1723&#34; height=&#34;985&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Feishin’s ’now playing’ screen&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;What attracted me to it, though, was its built-in support for Navidrome’s smart
playlists. These aren’t even properly exposed in Navidrome’s web UI yet, but
Feishin has a visual editor that lets you create and edit them. I ended up with
an identical system to the playlists I had in Tauon: a “blacklist” playlist
which are tracks I never want to play, a “favourites” playlist, and then an
“everything” playlist which is the entire catalogue minus the blacklist.&lt;/p&gt;
&lt;p&gt;On iOS I’ve settled on &lt;a href=&#34;https://www.reddit.com/r/arpeggiApp/&#34;&gt;Arpeggi&lt;/a&gt;. It’s
not actually on the App Store yet, but available via TestFlight. It’s one of
those really nicely polished apps that are obviously a labour of love, not just
out to do the minimum possible to get your money. It can cache songs offline,
and automatically download entire playlists, and supports all of the standard
Subsonic features like rating, reporting plays back to the server, and so on.&lt;/p&gt;
&lt;p&gt;One unexpected benefit of using a central server is that it handles reporting
plays to &lt;a href=&#34;https://last.fm/&#34;&gt;Last.fm&lt;/a&gt; and &lt;a href=&#34;https://listenbrainz.org/&#34;&gt;ListenBrainz&lt;/a&gt;
instead of the clients. I don’t think I’ve ever bothered to configure my mobile
clients to do that before, and now it just works automagically. I’m relying on
those services more for recommendations and discovery, as that’s something you
lose out on when self-hosting.&lt;/p&gt;
&lt;h3 id=&#34;making-bad-decisions-about-bitrates&#34;&gt;Making bad decisions about bitrates&lt;/h3&gt;
&lt;p&gt;With all the moving, copying, and organising, I started thinking about how
large the collection was. The songs were all in different formats, depending
on when and where I’d picked them up, and I couldn’t tell the difference
between them. I did a test and transcoded an MP3 file down to 128kbps, and
still couldn’t tell the difference. So armed with that sample size of 1, I
transcoded the entire library and saved &lt;em&gt;so much&lt;/em&gt; space.&lt;/p&gt;
&lt;p&gt;I don’t remember which track I did that first test with, but it must have
been a very unlucky pick. I quickly started to notice the distortions caused
by the low bitrate. It was particularly bad in any song with a lot of treble,
and started to really annoy me. I started a painful process of reimporting
things in their original format. Beets came in clutch again, both with the
import process (if you import a duplicate album, it asks if you want to
replace the original, and shows the format and bitrate of them for comparison),
and keeping track of what was left to fix (&lt;code&gt;beet ls bitrate:..128000&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Having started paying more attention to the sound quality, I think I’ve been
nibbled on by the audiophile bug. I’ve been trying to get new music in FLAC
format where possible. I’m pretty sure I &lt;em&gt;can’t&lt;/em&gt; tell the difference between
a decent bitrate MP3 and a FLAC, but maybe if I got a better DAC and some nice
headphones…? Someone please hide my credit card!&lt;/p&gt;
&lt;p&gt;As for the library taking up a lot of space, I now realise it’s a price worth
paying. I might need to swap out the server to one with more storage at some
point in the future, but it’s generally worth upgrading every few years with
rented dedicated servers anyway, as you often get more for the same amount of
money. Next upgrade I’ll just make sure there’s an appropriately-sized disk
instead of focusing entirely on RAM and CPU.&lt;/p&gt;
&lt;h3 id=&#34;writing-more-code&#34;&gt;Writing more code&lt;/h3&gt;
&lt;p&gt;Naturally, this whole process spawned several side projects. When browsing
albums in Navidrome, I was a bit upset that the album art wasn’t all a
consistent size. I thought about scripting something to crop them consistently,
but then I had a better idea, and &lt;a href=&#34;https://github.com/csmith/jewelcase&#34;&gt;jewelcase&lt;/a&gt;
was born. It takes the album art, crops it down to a consistent size, and then
renders it inside a jewel case. It applies some slight effects, like adjusting
the colours, rounding the corners, and tweaking the edges so it looks a bit more
real. I don’t know why&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, but every time I see the effect it gives me a little
spark of joy.&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/jewelcase.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/further-adventures-in-music-organisation/jewelcase.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/further-adventures-in-music-organisation/jewelcase.jpg&#34; alt=&#34;A comparison screenshot. On the left are four albums, with their unaltered artwork. Some are different aspect ratios. On the right are the same four albums, but the art work is now consistently rendered as though its in a jewel case.&#34; loading=&#34;lazy&#34; width=&#34;1737&#34; height=&#34;702&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Album art, before and after jewelcase is applied&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The other project is &lt;a href=&#34;https://github.com/csmith/bass&#34;&gt;BASS&lt;/a&gt;, a tool that uses
the Subsonic API to grab information about my music catalogue, and then
generates a “Daily Mix” playlist. It uses a system of weights to select tracks
semi-randomly, biasing towards favourite tracks, those that haven’t been played
much, and a few other criteria. This gives me a nice balance between having my
favourites on repeat, and exploring the full library at random.&lt;/p&gt;
&lt;p&gt;All the weights in BASS are customisable, so I can tweak it to my heart’s
desire, and anyone else can also run it and configure it entirely differently
to me if they want to. I can’t imagine I would’ve been able to do that if I were
using Plex!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I was running a version from git as the stable release had fun dependency
issues on Arch, so it’s possible this wouldn’t be an issue in normal use. I also
started backing up the database, but it’s still annoying to have to restore it. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;A “favourites” playlist for me, and a more “family friendly” playlist
for when I’m playing music out loud that has a bit less screaming/swearing/etc. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;One of the reasons for starting this was being annoyed by the periodic
sync to my phone, obviously it makes perfect sense to introduce a new, different
periodic sync. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Nostalgia? A little bit of OCD? Both? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>How tech companies failed to build the Star Trek computer</title>
        <link href="https://chameth.com/how-tech-companies-failed-to-build-the-star-trek-computer/"/>
        <updated>2025-07-16T00:00:00Z</updated>
        <id>https://chameth.com/how-tech-companies-failed-to-build-the-star-trek-computer/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/how-tech-companies-failed-to-build-the-star-trek-computer/enterprise-computer-room.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/how-tech-companies-failed-to-build-the-star-trek-computer/enterprise-computer-room.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/how-tech-companies-failed-to-build-the-star-trek-computer/enterprise-computer-room.jpg&#34; alt=&#34;Still from an episode of Star Trek: The Next Generation, with various characters stood around in a computer core room&#34; loading=&#34;lazy&#34; width=&#34;500&#34; height=&#34;376&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;A computer core room on the Enterprise-D&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In most Star Trek series, the ship or station computer is ever-present in the
background, waiting to be called on by the main characters&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. It nearly
always does exactly the right thing, and there’s little limit to the functions
it can perform. Take this mundane example from DS9:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;KIRA: Computer, establish link with the Bajoran Medical Index for the Northwestern District. &lt;br/&gt;
COMPUTER: Link established. &lt;br/&gt;
KIRA: Access all information on Doctor Surmak Ren. &lt;br/&gt;
COMPUTER: There are no records matching that name. &lt;br/&gt;
KIRA: Try the Northeastern District, same search. &lt;br/&gt;
COMPUTER: Doctor Surmak Ren, currently serving as Chief Administrator of the Ilvian Medical Complex. &lt;br/&gt;
KIRA: Computer, open a channel to the Ilvian Medical Complex. Administrator’s office.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The computer is doing some kind of networking to a database only identified by
name. It does a search and summarises the lack of results. It then repeats the
process with another database, and succinctly announces the results. Finally,
it opens a communication channel to a specific room in a facility, based only
on its name.&lt;/p&gt;
&lt;p&gt;This whole interaction is remarkably boring&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. Kira doesn’t have to know
any URLs or API endpoints, or what protocol she wants to use. She doesn’t have
to open a specific app and then login and then try the query again. She just
says what she wants and the computer does it.&lt;/p&gt;
&lt;p&gt;It seems like this should be one of the most easily obtainable bits of sci-fi
wizardry with our current technology. We have multiple massive companies
throwing lots of money at digital assistants, LLMs that are improving at an
insane rate, but we’re somehow not even close to the usability or usefulness of
the Trek computers. What gives?&lt;/p&gt;
&lt;h3 id=&#34;boring-is-well-boring&#34;&gt;Boring is, well, boring.&lt;/h3&gt;
&lt;p&gt;Larry Page once said something that might help explain it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Star Trek computer doesn’t seem that interesting. They ask it random
questions, it thinks for a while. I think we can do better than that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the same Larry Page that founded Google, whose mission statement is
“to organize the world’s information and make it universally accessible and
useful”. Of all people, surely he should find an omnipresent computer that can
answer ‘random questions’ interesting?! It seems like it should be the epitome
of Google’s mission!&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Google’s “better than that” seems to have been to stuff LLMs into every product
they can, even when you don’t want them there. Even when they’re worse than the
normal content they displace. These things look &lt;em&gt;exciting&lt;/em&gt; when they’re part of
a scripted demo at Google I/O, but they fall flat and just get in the way when
they’re exposed to the reality of day-to-day use.&lt;/p&gt;
&lt;p&gt;The Star Trek computer is the opposite: it isn’t snazzy, but it is genuinely
useful. That means it’s not an attractive target for the company execs who want
marketing opportunities, and it’s not appealing for engineers who need to
demonstrate “impact”. But even if Google did try to make the Trek computer,
there are other problems…&lt;/p&gt;
&lt;h3 id=&#34;assistants-need-to-be-free&#34;&gt;Assistants need to be free&lt;/h3&gt;
&lt;p&gt;A significant amount of tech companies’ business models currently revolves
around trapping users in walled gardens. They want you using &lt;em&gt;their&lt;/em&gt; ecosystem;
that way they get more data from you, and you’re more likely to spend more money
on their other offerings that work together. There’s barely any incentive to
allow any kind of interoperability with other platforms outside carefully
contracted integrations.&lt;/p&gt;
&lt;p&gt;I remember trying to help a family member move their photos from iCloud to
Google Photos. At one point they turned around and said, exasperated, “why is
this so hard? Aren’t they both in the cloud?!”. It’s easy to dismiss that as
someone who hasn’t quite grasped the fundamental idea that “the cloud” is just
someone else’s computers, but that’s not the whole story. There’s no reason why
there shouldn’t be a quick and easy transfer: both services already allow
uploading and downloading, there’s just no incentive for the companies involved
to make it so&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;These kinds of misaligned incentives and walled garden business models cause
even more problems when it comes to digital assistants. Siri is basically never
going to be able to interact with, say, your Google Drive; &lt;del&gt;Bard&lt;/del&gt; Gemini
is never going to be able to send a message via iMessage. Even when there are
appropriately blessed interactions, they’re so clunky. Can you imagine Captain
Picard saying “Computer, ask the turbolift skill to take me to deck 5”?&lt;/p&gt;
&lt;h3 id=&#34;someone-elses-computer&#34;&gt;Someone else’s computer&lt;/h3&gt;
&lt;p&gt;Software issues aside, there’s still a key difference between the Star Trek
computers and our current batch of digital assistants: where they run. The
Trek computers are all housed within the ship or station they serve; they can
connect elsewhere to gather information, but they run entirely independently.
If they go wrong, a local engineer can go in and fix things. While some of our
assistants may have physical hardware in your home, they don’t work without
a vast cloud apparatus behind them. If your Internet connection fails, they
become paperweights. If the company running them decide to remove some
functionality you depend on, you have no recourse.&lt;/p&gt;
&lt;p&gt;That kind of helplessness isn’t limited to assistants, either. There’s a rapidly
growing trend of being unable to modify or repair hardware you fully own and
control. Part of this is just that they’re becoming more complex: it’s a lot
harder to replace a microchip than a gear, but companies are also going out
of their way to make it more difficult for users through draconian DRM
regimes&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; and aggressive intellectual property enforcement. If the US Navy
can’t repair their own equipment because a corporation says so, what hope do
consumers have?&lt;/p&gt;
&lt;p&gt;We’re approaching a point where you don’t actually own anything. Software
is cloud and subscription based, hardware is unrepairable. Even cars can
be remotely updated and have features added or removed. The Federation wouldn’t
allow a third party control over their ships&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;, so why are we so happy to
put up with it in everything we consume?&lt;/p&gt;
&lt;h3 id=&#34;a-small-ray-of-hope&#34;&gt;A small ray of hope?&lt;/h3&gt;
&lt;p&gt;The most promising way of tackling all of these problems is through legislation.
The EU’s &lt;a href=&#34;https://digital-markets-act.ec.europa.eu/index_en&#34;&gt;Digital Market Act&lt;/a&gt;
is an attempt to force ‘gatekeepers’ like Google, Apple and Meta, to allow
third-party access to their services. It seems like a pretty reasonable
approach, but the tech companies are unsurprisingly resisting it. Apple in
particular have gone out of their way to refuse to comply, and when forced to
do so have limited the functionality to people in Europe.
Still, the DMA is a promising start, and if similar legislation is introduced
(and robustly enforced) elsewhere it might start forcing companies to behave a
bit better.&lt;/p&gt;
&lt;p&gt;There are also smaller companies that actually do the right thing.
&lt;a href=&#34;https://frame.work/gb/en&#34;&gt;Framework&lt;/a&gt; make laptops that are user-serviceable;
&lt;a href=&#34;https://www.fairphone.com/&#34;&gt;Fairphone&lt;/a&gt; do the same for mobile phones. Smaller
software companies provide useful, open APIs. The average person on the street
will probably have never heard of these, unfortunately, but they do still
exist. Maybe as the bigger tech companies tighten the screws more, people will
turn to alternatives like this? Or maybe we’ll just keep accepting that our
computers work for everyone but us?&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Unless, of course, the computer is playing the role of the episode’s
MacGuffin and has contracted space-computer-COVID or something, then it’s a lot
less in-the-background. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;It’s almost like it only exists to move the plot along. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;You can generally export your data, thanks to a combination of legislation
and efforts like Google’s “Data Liberation Front”, but I’ve never seen an export
format that could then just be imported into an equivalent commercial product. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Oh, you’ve changed the screen on your iPhone? Better hope it can do the
secret handshake with the Apple hardware. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;I think there might actually have been an episode where that did in fact
happen. We’ll just ignore that as a plot contrivance. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Simple backups with Restic and Hetzner Cloud</title>
        <link href="https://chameth.com/simple-backups-restic-hetzner/"/>
        <updated>2024-12-06T00:00:00Z</updated>
        <id>https://chameth.com/simple-backups-restic-hetzner/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/simple-backups-restic-hetzner/restic.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/simple-backups-restic-hetzner/restic.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/simple-backups-restic-hetzner/restic.png&#34; alt=&#34;The Restic logo — a gopher with two umbrellas.&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;400&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Restic’s mascot, who’s dual-wielding umbrellas to save you from a rainy day.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have a confession: for the past few years I’ve not been backing up any of my
computers. Everyone knows that you &lt;em&gt;should&lt;/em&gt; do backups, but actually getting
around to doing it is another story.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong: most of my important things are “backed up” by virtue of
being committed to remote git repositories, or attached to e-mails, or
re-obtainable from the original source, and so on. I don’t think any machine
failing completely would be a disaster for me, but it would certainly be a pain.&lt;/p&gt;
&lt;p&gt;This week I finally got around to doing something, and it ended up being a lot
more straight forward than my previous forays into backup-land.&lt;/p&gt;
&lt;h3 id=&#34;restic&#34;&gt;Restic&lt;/h3&gt;
&lt;p&gt;After soliciting a few opinions, the choice of backup software came down to
either &lt;a href=&#34;https://www.borgbackup.org/&#34;&gt;Borg&lt;/a&gt; or &lt;a href=&#34;https://restic.net/&#34;&gt;Restic&lt;/a&gt;.
I’m pretty sure either would have done what I want, but I leaned towards Restic
for a few reasons: it has a more informative website, it’s written in Go
rather than Python&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and Borg seems to be transitioning between major
releases at the moment&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;The way Restic works is pretty simple: you initialise a ‘repository’, and can
then call &lt;code&gt;restic backup /some/path&lt;/code&gt; and it’ll get backed up to the repository.
Restic handles keeping different backups separate, and only sending data that’s
changed, and deduplicating, and so on. You basically point it at a thing you
don’t want to lose, and it sorts it out for you. Perfect.&lt;/p&gt;
&lt;p&gt;There are equally straight-forward commands for removing old snapshots
(&lt;code&gt;restic forget&lt;/code&gt;) and verifying backups (&lt;code&gt;restic check&lt;/code&gt;). One of the nice things
about modern backup solutions is they support a whole range of backends. I was
originally going to spin up a small VPS to host my backups, but noticed that
Restic supported S3-compatible stores…&lt;/p&gt;
&lt;h3 id=&#34;hetzner-cloud-object-storage&#34;&gt;Hetzner Cloud Object Storage&lt;/h3&gt;
&lt;p&gt;I host my servers with Hetzner, and was going to use them to spin up a VPS as
well. Despite the “Cloud” branding on a bunch of products, they offer reasonable
prices and good service. A couple of months ago, they started offering
&lt;a href=&#34;https://docs.hetzner.com/storage/object-storage/overview&#34;&gt;S3-compatible object storage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The pricing isn’t totally straight forward, but for continuous use the “free
quota” amounts to 1TB of storage and 1TB of egress a month. Ingress is free,
as is traffic within the &lt;code&gt;eu-central&lt;/code&gt; region (where all my servers are). That
quota is only awarded when you pay the “base price”, though, which is €4.99 a
month. So basically it’s €5 a month for 1TB of storage and enough egress to
fully restore every single byte. That’s better value than any VPS I can find,
much cheaper than Amazon S3, and about the same as
&lt;a href=&#34;https://www.backblaze.com/cloud-storage&#34;&gt;Backblaze B2&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;getting-them-to-work-together&#34;&gt;Getting them to work together&lt;/h3&gt;
&lt;p&gt;Now you’d think making the tool that supports S3-compatible object storage
work with your S3-compatible object storage would be easy, right? Well not
quite. The library Restic uses to deal with S3 backends has some
strange logic for figuring out the bucket name given a URL. It doesn’t quite
seem to work right, though…&lt;/p&gt;
&lt;p&gt;Hetzner buckets have URLs like &lt;code&gt;s3://bucketname.hel1.your-objectstorage.com&lt;/code&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;,
but just passing that to Restic gives an error that the bucket is not specified.
The docs mention there’s an advanced option to make it use the virtual host for
the bucket name: &lt;code&gt;-o s3.bucket-lookup=dns&lt;/code&gt;. But that… also doesn’t work.
What I ended up doing was specifying the URL as
&lt;code&gt;s3://hel1.your-objectstorage.com/bucketname&lt;/code&gt;, and also passing in the &lt;code&gt;dns&lt;/code&gt;
option. The library then seems to muddle its way back to a real, working URL.
I’m not sure why it works like this: maybe it’s just a weird aspect of S3 that
I’m oblivious to?&lt;/p&gt;
&lt;p&gt;The next fun part is that you can configure Restic entirely by using environment
variables, except for that &lt;code&gt;-o s3.bucket-lookup=dns&lt;/code&gt; argument. That has to go
on the command line. I ended up making a little wrapper script to invoke Restic
correctly:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# The password restic will use to encrypt your data. You should generate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# something nice and secure.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;RESTIC_PASSWORD&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;repo-password
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# The path to the repository where restic will save the backup. In our case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# this takes the form `s3:&amp;lt;endpoint&amp;gt;/&amp;lt;bucket&amp;gt;`. Your endpoint might be different&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# to mine depending on the region your bucket is in.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;RESTIC_REPOSITORY&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;s3:hel1.your-objectstorage.com/bucket-name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# The access and secret key generated in the &amp;#39;S3 credentials&amp;#39; section of the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# Hetzner Cloud Console&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;hetzner-access-key-id
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;hetzner-access-key
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# Pass any arguments on to the restic command, along with the magic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# `s3.bucket-lookup` option we need to resolve the S3 URL properly.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;exec&lt;/span&gt; restic -o s3.bucket-lookup&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;dns &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then in the backup script I just alias &lt;code&gt;restic&lt;/code&gt; to use the script:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;set&lt;/span&gt; -eu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# This means any time we use `restic` below, we&amp;#39;ll actually execute our special&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# script which supplies all the env vars and arguments needed to find the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# repository. Make sure the path matches where you saved the script!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;restic&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-s1&#34;&gt;&amp;#39;~/.bin/restic&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# Actually do the backup. Each directory in the list below will be backed up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# separately.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nv&#34;&gt;dirs&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;/some/path/to/backup/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;/some/other/path/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;chroma-nv&#34;&gt;dirs&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[@]&lt;/span&gt;&lt;span class=&#34;chroma-si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;$i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;chroma-nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; restic --verbose backup .&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# Prune our snapshots. You can tweak the numbers here. Run with `--dry-run` to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c1&#34;&gt;# see what effect any changes would have before actually committing to them. &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;restic forget --keep-daily &lt;span class=&#34;chroma-m&#34;&gt;7&lt;/span&gt; --keep-weekly &lt;span class=&#34;chroma-m&#34;&gt;10&lt;/span&gt; --keep-monthly &lt;span class=&#34;chroma-m&#34;&gt;24&lt;/span&gt; --keep-yearly &lt;span class=&#34;chroma-m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The only other notable thing here is that the script changes into the directory
to be backed up. If you give Restic an absolute path, it will create a new
snapshot if the metadata of any folder in the path changes, which is not what
I want.&lt;/p&gt;
&lt;p&gt;If it wasn’t for the S3 URL issues, the whole thing would’ve probably taken
me about half an hour. That’s including setting up the object storage,
installing Restic, and so on. It’s painfully easy. Why didn’t I do this three
years ago?!&lt;/p&gt;
&lt;h3 id=&#34;addendum-a-step-by-step-guide&#34;&gt;Addendum: a step-by-step guide&lt;/h3&gt;
&lt;aside class=&#34;update raised-box&#34;&gt;
  &lt;h5 class=&#34;plain-header&#34;&gt;Update 2025-03-01:&lt;/h5&gt;
  &lt;p&gt;This section was added after the original article was published, following some
helpful feedback. Let me know if you have any problem with these instructions!&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;If you want to do this yourself, here’s a quick step-by-step guide:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to the &lt;a href=&#34;https://console.hetzner.cloud&#34;&gt;Hetzner Cloud Console&lt;/a&gt;, and
create a project.&lt;/li&gt;
&lt;li&gt;On the “Object Storage” tab, create a new bucket. Note the name and the
endpoint.&lt;/li&gt;
&lt;li&gt;On the “Security” tab, go to “S3 Credentials” and generate new credentials.
Note down the access key and the secret key.&lt;/li&gt;
&lt;li&gt;Copy the first shell script above, fill in the password (you can pick!),
endpoint, bucket name, access key and secret key.&lt;/li&gt;
&lt;li&gt;Run the script with the &lt;code&gt;init&lt;/code&gt; argument (e.g. &lt;code&gt;~/.bin/restic init&lt;/code&gt;). This
will create a new repository, and only needs to be done once even if you
backup multiple machines.&lt;/li&gt;
&lt;li&gt;Copy the second shell script above, making sure the &lt;code&gt;restic&lt;/code&gt; alias points
at the script you saved in step 4. Change the list of directories to
whatever you want to backup.&lt;/li&gt;
&lt;li&gt;Schedule the script to be run automatically, using crontab or systemd timers
or however you prefer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To check everything is working, you can use the &lt;code&gt;snapshots&lt;/code&gt; subcommand to see
a list of saved snapshots. You might also want to try to restore a snapshot
using the &lt;code&gt;restore&lt;/code&gt; subcommand.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I’m not trying to be a language snob, but given the choice between two
otherwise equal projects one in Go and one in Python, I’ll take the Go one.
I know I’m not going to have weird library issues down the line, and I’m much
more comfortable rummaging around the source. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;With a “Don’t use this in production!” notice on the shiny new version. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Aside: I really hate URLs like that. What is with the trend for completely
generic domains divorced from the service they’re a part of? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Apple, Google and aligned incentives</title>
        <link href="https://chameth.com/apple-google-aligned-incentives/"/>
        <updated>2020-10-17T00:00:00Z</updated>
        <id>https://chameth.com/apple-google-aligned-incentives/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/apple-google-aligned-incentives/htc-dream.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/apple-google-aligned-incentives/htc-dream.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/apple-google-aligned-incentives/htc-dream.jpg&#34; alt=&#34;White HTC Dream mobile phone&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;225&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The HTC Dream, the first phone released running Android.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For the past decade I’ve exclusively used Android phones. I got the HTC Dream (aka the T-Mobile G1)
shortly after it came out, and dutifully upgraded every 1-2 years. In that timespan I used Android
as the basis for my Master’s Thesis, took a job on the Android team at Google, and eventually
became a contractor specialising in Android app development. So when I switched to using an iPhone
earlier this year a few people were surprised&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-good-old-days&#34;&gt;The good old days&lt;/h3&gt;
&lt;p&gt;When Android was announced in 2007 – alongside the formation of the Open Handset Alliance – it
was positioned as a bastion of openness: it would be built on open standards and the operating
system would be open source. At the time iPhones were strongly coupled to iTunes and Apple was
exercising strict control over what app developers could do.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;When the HTC Dream was released it lived up to expectations. You could write apps for it without
shelling out for a Mac! You could get root access, and it was running Linux under the hood! A
whole ecosystem of custom firmwares and bootloaders started to appear, thanks to the open source
nature of the OS. It shipped with some Google apps, but they were just normal apps that served
as examples of what could be done.&lt;/p&gt;
&lt;p&gt;After the Dream came a line of Nexus devices. These were Android’s flagship devices, designed to
show off what a good Android phone should look like. Both the hardware and software releases
tended to feature interesting, useful upgrades. Some of the original open source apps were
replaced with closed source, Google proprietary ones, but that was OK - the open source
versions lived on in the open source project as examples of what you &lt;em&gt;could&lt;/em&gt; do. The devices
allowed flashing custom firmware, and the OS source was always released… eventually.&lt;/p&gt;
&lt;h3 id=&#34;the-downfall&#34;&gt;The downfall&lt;/h3&gt;
&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/apple-google-aligned-incentives/pixels.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/apple-google-aligned-incentives/pixels.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/apple-google-aligned-incentives/pixels.jpg&#34; alt=&#34;Pixel and Pixel XL phones&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;363&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The Pixel and Pixel XL&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Over time, Android has got less and less free. The Nexus line of phones gave way to the Pixel
range, which got rid of the clearly demarcated border where Android ended and Google began.
&lt;a href=&#34;https://www.android.com/android-11/&#34;&gt;The Android 11 highlights&lt;/a&gt; list is dotted with sections
that say “On Pixel devices…”, and every single one is a software feature that could be
implemented on any device, but Google have decided to keep it proprietary instead of releasing
it as part of the open source platform.&lt;/p&gt;
&lt;p&gt;At the same time more and more functionality has been added to Google Play Services. This was
originally a shared location for Google specific services - in 2012 it merely handled some
Google+ functionality and dealing with OAuth for Google accounts. These days it contains a
huge swathe of Google services, as well as platform functionality such as push notifications,
barcode scanning, geolocation, and so on. Google Play Services isn’t part of the Android
Open Source Project, and is only available under license from Google. You can’t really have
a device without these functions, so as a manufacturer you have the choice between agreeing
to whatever terms Google requires&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; or spending an awful lot of development time creating an
alternative.&lt;/p&gt;
&lt;p&gt;While these are fairly abstract arguments about what a free platform should look like,
during the same period there has been a marked restriction in how you can actually use
Android devices – both as an end-user and as a developer. iOS has always had very stark
restrictions on what apps can do in the background; Android started its life allowing
pretty much anything, like any good general purpose computing device. This inevitably
lead to lots of apps doing lots of things that ranged from stupid to mildly suboptimal,
creating a &lt;a href=&#34;https://en.wikipedia.org/wiki/Tragedy_of_the_commons&#34;&gt;tragedy of the commons&lt;/a&gt;
amongst apps. The victim was the phone’s battery life, and Google’s solution was a
progressive series of restrictions on what apps can do and when. This includes limits
on when push notifications are delivered to a device, how frequently apps can wake up,
and so forth. Some of these can be bypassed by the end-user, but not all, and the
process is fairly cumbersome.&lt;/p&gt;
&lt;h3 id=&#34;aligned-incentives&#34;&gt;Aligned incentives&lt;/h3&gt;
&lt;p&gt;From my point of view, Android and iOS are now pretty much in a similar place.
They’re not general purpose computers, but
&lt;a href=&#34;https://daringfireball.net/linked/2020/08/14/orland-epic-game-consoles&#34;&gt;app consoles&lt;/a&gt;:
much like games consoles they consist of hardware and software that the user lacks
control over but accepts in order to access the library of apps/games.&lt;/p&gt;
&lt;p&gt;Given there’s no clear winner between them in terms of hardware and software, my
decision came down to a more holistic question: how aligned are their
incentives to my own? Apple is a product company: they make their money by
producing shiny things that people want to purchase; Google is an advertising
company: they make their money by using my personal information to show me
targeted adverts.&lt;/p&gt;
&lt;p&gt;For Google, Android was originally a strategic move to ensure that
Apple couldn’t dominate the mobile web, and by extension the revenue from ads.
As a company, there’s nothing to really push them forward in any particular
direction other than one that facilitates advertising. Of course, Google employs
tonnes of good people who want to do good things which counterbalances this, but
I’d still prefer to deal with a company that has an intrinsic motivation to
do things I want them to do, rather than one forced to by regulation, custom,
or the good intent of their employees.&lt;/p&gt;
&lt;p&gt;So the decision became obvious: if I have no strong opinions about the software
and hardware, Apple is the clear winner because their incentives are a lot
better aligned to mine.&lt;/p&gt;
&lt;hr/&gt;
&lt;h3 id=&#34;image-credits&#34;&gt;Image credits&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Photo&lt;/th&gt;
&lt;th&gt;Creator&lt;/th&gt;
&lt;th&gt;Licence&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTC Dream&lt;/td&gt;
&lt;td&gt;Akela NDE&lt;/td&gt;
&lt;td&gt;CC BY-SA 3.0&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://commons.wikimedia.org/w/index.php?curid=6680413&#34;&gt;Wikimedia&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel and Pixel XL&lt;/td&gt;
&lt;td&gt;Maurizio Pesce from Milan, Italia&lt;/td&gt;
&lt;td&gt;CC BY 2.0&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://commons.wikimedia.org/w/index.php?curid=52110138&#34;&gt;Wikimedia&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Or, at least, politely feigned surprise. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;And Google’s terms were particularly onerous: as well as requiring Chrome and Google
Search to be preinstalled, they prevented manufacturers from selling any devices
powered by alternative versions of Android - e.g., Samsung wouldn’t be allowed to
sell a refrigerator that ran Amazon’s FireOS. The European Union handed Google a
$5,000,000,000 fine for this anti-competitive behaviour, which Google are still in
the process of contesting. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
</feed>
