the-internet-vagabond-dot-com/2022/09/27/linode_funkwhale.html

290 lines
15 KiB
HTML
Raw Normal View History

2024-06-18 23:26:12 +00:00
<!DOCTYPE html>
<html>
<head>
<title>The Internet Vagabond :: Funkwhale On Linode with Object Storage</title>
<link type="application/atom+xml" rel="alternate" href="https://www.theinternetvagabond.com/feed.xml" title="The Internet Vagabond" />
<meta name="description"
content="Rants of a wandering techy, in search of truth, knowledge, and a decent ping." />
<meta name="author" content="Bill Niblock" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="canonical" href="https://www.theinternetvagabond.com/2022/09/27/linode_funkwhale.html" />
<link rel="stylesheet" type="text/css"
href="https://www.theinternetvagabond.com/src/styles/corrupt_layout.css" />
<link rel="stylesheet" type="text/css"
href="https://www.theinternetvagabond.com/src/styles/corrupt_typog.css" />
<link rel="icon" type="image/x-icon"
href="https://www.theinternetvagabond.com/src/images/favicon.ico" />
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY="
crossorigin="anonymous">
<script data-goatcounter="https://theinternetvagabond.goatcounter.com/count"
async src="https://www.theinternetvagabond.com/src/scripts/goatcounter.js"></script>
</head>
<body>
<div class="cor_page">
<header>
<a href="/">
<div>
<span class="first">T</span>he
<span class="first">I</span>nternet
<span class="first">V</span>agabond
</div>
</a>
</header>
<main>
<article>
<h1 id="funkwhale-on-linode-with-object-storage">Funkwhale on Linode with Object Storage</h1>
<h2 id="funkwhale-setup">Funkwhale Setup</h2>
<p><a href="https://funkwhale.audio/">Funkwhale</a> is a decentralized music service,
connecting to the <a href="https://en.wikipedia.org/wiki/Fediverse">fediverse</a> using the
ActivityPub protocol. It is a web-based application, allowing users to upload,
listen, and share music and podcasts. I think its a cool project, and I can
self-host it, so I did. For a while, Funkwhale offered an all-in-one Docker
container, but they shifted focus to a multi-container approach. I had delayed
my transition from all-in-one to multi-container, but finally this past weekend
I found myself with time and motivation to get it done. The installation of
Funkwhale using Docker is very straight forward. The community has developed a
series of templates that can be fetched, modified, and used to get started very
quickly and easily. Those instructions are
<a href="https://docs.funkwhale.audio/installation/docker.html#multi-container-installation">here</a>.
The only significant modification I made was using <code class="language-plaintext highlighter-rouge">/opt/funkwhale</code> as my
default data and media root. I keep all my Docker configuration in directories
in my home directory as well. Much of these changes can be established in the
<code class="language-plaintext highlighter-rouge">.env</code> file discussed in the installation instructions, but I also scrubbed the
template files created and used during installation to make sure the directories
were as I wanted them. I also proxy Funkwhale and many other services behind
nginx, and there were a few <a href="https://docs.funkwhale.audio/installation/index.html#nginx">additional
steps</a> I had to
take. With all that complete, I had transitioned successfully. I already had SSL
certificates, but if thats also a requirement, they can easily be provisioned
using <a href="https://certbot.eff.org/">Certbot</a>.</p>
<h2 id="object-storage-setup">Object Storage Setup</h2>
<p>In my old setup, I leveraged Funkwhales ability to <a href="https://docs.funkwhale.audio/admin/importing-music.html">in-place import
music</a>. I transferred
about 70GB worth of music to my VPS (using Syncthing &lt;3), filling the disk
almost entirely (<em>98%</em>). It was a temporary solution for a road trip, and I
knew I couldnt keep it that way for long. Funkwhale has the ability to leverage
S3-compatible object storage, and Linode, the provider I already use for my VPS,
offers object storage. Any of the other major cloud providers will also do the
trick; I just went with what was easiest. On the Linode side, theres not much
to it. I created a new bucket, labeled it accordingly, created an access key,
and that was it. The Funkwhale side proved to be a bit challenging, but not, it
turns out, due to configuration. Well, <em>technically</em> it was.</p>
<p>The relevant configuration options on the Funkwhale side, in the <code class="language-plaintext highlighter-rouge">.env</code> file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## External storages configuration
# Funkwhale can store uploaded files on Amazon S3 and S3-compatible storages (such as Minio)
# Uncomment and fill the variables below
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_STORAGE_BUCKET_NAME=
# An optional bucket subdirectory were you want to store the files. This is especially useful
# if you plan to use share the bucket with other services
# AWS_LOCATION=
# If you use a S3-compatible storage such as minio, set the following variable
# the full URL to the storage server. Example:
# AWS_S3_ENDPOINT_URL=https://minio.mydomain.com
AWS_S3_ENDPOINT_URL=
# If you want to serve media directly from your S3 bucket rather than through a proxy,
# set this to false
# PROXY_MEDIA=false
# If you are using Amazon S3 to serve media directly, you will need to specify your region
# name in order to access files. Example:
# AWS_S3_REGION_NAME=eu-west-2
# AWS_S3_REGION_NAME=
# If you are using Amazon S3, use this setting to configure how long generated URLs should stay
# valid. The default value is 3600 (60 minutes). The maximum accepted value is 604800 (7 days)
# AWS_QUERYSTRING_EXPIRE=
# If you are using an S3-compatible object storage provider, and need to provide a default
# ACL for object uploads that is different from the default applied by boto3, you may
# override it here. Example:
# AWS_DEFAULT_ACL=public-read
# Available options can be found here: https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl
AWS_DEFAULT_ACL=
</code></pre></div></div>
<p>Ive included the comments. The entire file is commented, and generally easy
enough to figure out. On the Linode side, when I generated the access key, it
provided me an <em>Access Key</em> and a <em>Secret Key</em>. I had already created a bucket,
and so I had the <em>Bucket Name</em>. The challenge for me was what the <em>Endpoint URL</em>
was, and if I needed to set a <em>Region Name</em> and <em>ACL</em>. Linodes documentation on
their object storage offering is a bit anemic, and so I made use of their setup
instructions for <a href="https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/">using s3cmd with Linode object
storage</a>.
From this guide, I was able to both setup <code class="language-plaintext highlighter-rouge">s3cmd</code>, and also determine what the
<em>Endpoint URL</em> would be. I also set the <em>Region Name</em> and <em>ACL</em> to match what
the UI was showing, but Im still not certain their necessary. Heres the trick,
and the cause of a few hours-worth of confusion: restarting the Docker
containers wasnt re-reading the <code class="language-plaintext highlighter-rouge">.env</code> file; I had to completely stop and
re-create them. It wasnt until I ran <code class="language-plaintext highlighter-rouge">docker inspect funkwhale-docker_api_1</code>
and noticed the environment variables werent set that I figured this out. Could
be this is common knowledge for Docker-gurus; now I know. With the
configuration in place, and the containers recreated, I was able to upload files
through Funkwhale, and watch them be stored in my Linode bucket. My final
configuration options were as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AWS_ACCESS_KEY_ID=&lt;stuff&gt;
AWS_SECRET_ACCESS_KEY=&lt;secret stuff&gt;
AWS_STORAGE_BUCKET_NAME=funkwhale-music-bucket-name
AWS_S3_ENDPOINT_URL=https://us-southeast-1.linodeobjects.com
AWS_S3_REGION_NAME=us-southeast-1
AWS_DEFAULT_ACL=public-read
</code></pre></div></div>
<h2 id="next-steps">Next Steps</h2>
<p>The downside of Funkwhales S3-compatible object storage integration lies in how
files are uploaded. One cannot simply <del>walk into</del> upload files to the bucket;
music must be uploaded through Funkwhales API (via web or other means), and
then Funkwhale stores it accordingly (like for local uploads). I have a lot of
music, and I cant be asked to manually upload it all. Thats, like, 2 hours of
half-hearted work. No, instead, the obvious solution is to build a script that
can automatically upload any new music from my local music directory to
Funkwhale automatically. What Im considering now is how I want to do that. I
could leverage systemd to watch my local music directory, and run the upload
script whenever new music is uploaded. Could even expand it to remove music
whenever I delete it locally, though that seems a bit odd. I could instead setup
a cron or systemd-timer to run at a set interval, and check for any new files
since the last run, and upload them. Regardless of the trigger, the upload
functionality should ideally avoid duplicates, run in a non-blocking fashion,
maybe batch upload files, and be low impact on my desktop. So thats next.</p>
<div class="author_info">
Bill Niblock
<a href="https://unlicense.org/"
aria-label="Code dedicated to the public domain under Unlicense">
<span class="fa fa-cc-pd" aria-hidden="true"
title="Code dedicated to the public domain under Unlicense"</span>
</a>
<a href="https://creativecommons.org/publicdomain/zero/1.0/"
aria-label="Published to the public domain under CC0">
<span class="fa fa-cc-zero" aria-hidden="true"
title="Content dedicated to the public domain under CC0"</span>
</a>
2022-09-27
<br />
[
<a href="/topics/technology">technology</a>
]
</div>
</article>
</main>
<footer>
<nav>
<div><a href="/">home</a></div>
<div><a href="/topics/all">all</a></div>
<div><a href="/topics/gaming">gaming</a></div>
2025-01-03 19:48:05 +00:00
<div><a href="/topics/Life">Life</a></div>
2024-06-18 23:26:12 +00:00
<div><a href="/topics/philosophy">philosophy</a></div>
<div><a href="/topics/technology">technology</a></div>
<div><a href="/topics/writing">writing</a></div>
</nav>
<hr />
2024-08-20 16:05:54 +00:00
<div><a href="https://www.theinternetvagabond.com/now">Life In Progress</a></div>
<hr />
2024-06-18 23:26:12 +00:00
<section class="h-card">
<section class="footer_about" id="about">
<div>The Site</div>
<div>
2024-06-20 19:38:41 +00:00
<a href="https://www.theinternetvagabond.com/feed.xml"
2024-06-18 23:26:12 +00:00
aria-label="RSS feed for the site">
<span class="fa fa-rss" aria-hidden="true"
title="RSS Feed"</span>
</a> |
2024-06-20 19:38:41 +00:00
<a href="https://theinternetvagabond.goatcounter.com/"
2024-06-18 23:26:12 +00:00
aria-label="GoatCounter statistics for the site">
<span class="fa fa-bar-chart" aria-hidden="true"
title="GoatCounter Statistics"</span>
</a> |
2024-06-20 19:38:41 +00:00
<a href="https://codeberg.org/VagabondAzulien/the-internet-vagabond-dot-com"
2024-06-18 23:26:12 +00:00
aria-label="Source code repository for the site">
<span class="fa fa-code" aria-hidden="true"
title="Site Source Code"</span>
</a>
</div>
<a class="u-url u-uid" href="https://theinternetvagabond.com"></a>
<p>
This site is a small slice of internet real-estate that I use for
occasional writing. Nothing I say is visionary or profound. I
focus on technology, gaming, and philosophy. All opinions my
own.
</p>
<div>The Vagabond</div>
<div>
2024-06-20 19:38:41 +00:00
<a rel="me"
2024-06-18 23:26:12 +00:00
href="mailto:bill@theinternetvagabond.com"
aria-label="Email Bill at The Internet Vagabond dot com">
<span class="fa fa-envelope-o" aria-hidden="true"
title="Email bill at theinternetvagabond.com"</span>
</a> |
<a class="u-url" rel="me"
href="https://matrix.to/#/@vagabondazulien:matrix.org"
aria-label="Speak with me on Matrix">
<span class="fa fa-matrix-org" aria-hidden="true"
title="Speak with me on Matrix"</span>
</a> |
<a class="u-url" rel="me"
href="https://mastodon.social/@azulien"
aria-label="Find me on the Fediverse">
<span class="fa fa-mastodon" aria-hidden="true"
title="Find me on the Fediverse"</span>
</a> |
<a class="u-url" rel="me" href="https://www.twitch.tv/vagabondazulien/profile"
aria-label="Link to my Twitch channel">
<span class="fa fa-twitch " aria-hidden="true"
title="My Twitch channel"</span>
</a>
</div>
<p>
My name is <span class="p-name">Bill Niblock</span>. <span
class="p-note">I'm a computer scientist by education, a technologist
by trade, a gamer by hobby, and a philosopher by accident. I
live in <span class="p-locality">Buffalo</span>, <span class="p-region">
2024-06-20 19:38:41 +00:00
New York</span>, <span class="p-country-name">USA</span>.<br />
<br />
My PGP Key is <span class="u-key" id="key">CCE7 3682 331B 5614 9FAB
7383 7359 80B2 6381 C91E</span>.
2024-06-18 23:26:12 +00:00
</p>
</section>
<section style="display: none;">
<span class="p-category">Gaming</span>
<span class="p-category">Technology</span>
<span class="p-category">Philosophy</span>
<span class="p-category">Open Source Software</span>
<span class="p-category">Self-Hosting</span>
<span class="p-category">Coffee</span>
2024-06-20 19:38:41 +00:00
<span class="u-email">bill@theinternetvagabond.com</span>
2024-06-18 23:26:12 +00:00
</section>
</section>
</footer>
</div>
</body>
</html>