DIY Music Streaming with NixOS, Jellyfin and Manet
In this post I describe how I’m hosting my own music streaming service with NixOS and Jellyfin on Hetzner for €6 / month. · Frankfurt, GermanyIn this post, I describe how I’m hosting my own music streaming service with NixOS, Jellyfin and Manet on Hetzner for €6 / month.
If you know your way around servers, this is neither a novel nor a complicated setup—quite the opposite; the beauty of this configuration lies in its simplicity.
Table of Contents
Set up a VM with NixOS
The smallest (and cheapest) VM on Hetzner Cloud, CX11 with 1 VCPU and 2 GB RAM, is more than enough1.
Because my music collection is still pretty small, I’ve decided to go with
Hetzner volumes.
If you have more than 100 GB of music, I’d recommend looking into a different
storage solution in combination with rclone
, see
the storage section of an earlier post.
Hetzner doesn’t have a one-click NixOS image, so I chose any image and followed the “traditional” ISO installation as described in this repo: nixos-install-scripts. The NixOS docs also recommend nixos-infect—if you take this path, I’d be genuinely interested to hear how it worked.
Then, just to be safe, I ran nix-channel --update
and
nixos-rebuild switch --upgrade
on the VM to upgrade everything to the latest
version.
After finding my attached volume with ls /dev/sd*
and mounting it with
mount /dev/sdb /mnt/media
(replace /dev/sdb
with the path of your volume),
I ran nixos-generate-config
to regenerate the hardware configuration and
automatically mount it on the next boot.
Because this VM is only for music, I didn’t do anything to harden the vm. If you want more security, take a look at the excellent Paranoid NixOS Setup article by Xe.
Install and configure packages
On the VM, I opened /etc/nixos/configuration.nix
in a text editor.
Nano comes installed out of the box, but you can get vim in an ephemeral shell
with nix-shell -p vim
.
In that file, I started by changing networking.hostName
and time.timeZone
.
Subsequently, I configured the installed packages:
environment.systemPackages = with pkgs; [
jellyfin
jellyfin-web
jellyfin-ffmpeg
caddy
logrotate
];
Jellyfin
Jellyfin is an open-source media server, comparable to Plex.
I installed Jellyfin itself (jellyfin
), the official Jellyfin web client
(jellyfin-web
), and a modified version of FFmpeg for
hardware acceleration (jellyfin-ffmpeg
).
Let’s enable Jellyfin:
services.jellyfin.enable = true;
Caddy
We need a reverse proxy, mostly for automatic HTTPS. I chose Caddy because the configuration is the shortest2:
services.caddy = {
enable = true;
virtualHosts."jellyfin.example.com".extraConfig = ''
reverse_proxy 127.0.0.1:8096
'';
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
You should replace jellyfin.example.com
with the domain you want to use for
your Jellyfin setup. Make sure to point A
and AAAA
records in your domain
provider to the public IP addresses of the VM.
Logrotate
After a few days, I was uploading more music and noticed, that my SFTP uploads
were stalled.
After hours of debugging, I found out, that this apparently was due to a very
large /var/log/auth.log
beeing too large3.
logrotate
fixes this by automatically rotating, compressing and removing this
(and other) log files.
It’s enabled like this:
services.logrotate.enable = true;
Auto-upgrade
To keep maintenance low, I enable automatic system upgrades using the following configuration:
system.autoUpgrade = {
enable = true;
allowReboot = true;
}
This checks every day at 4:40 am by default, so the chances of the VM rebooting while I want to listen to music are very slim.
Apply changes
Run nixos-rebuild switch
to apply the configuration.
Configure Jellyfin
Go to the address of your server and follow the installation wizard to set up
Jellyfin4.
Create a library for your music and upload some to /mnt/media
.
Apps
Having a good mobile app is crucial for me. The official Jellyfin apps are excellent for configuring Jellyfin, but not great for listening to music.
When I discovered Manet, an iOS app, it changed everything. While it looks and feels very similar to Apple Music, it works significantly better. André, the developer who is developing this on the side, is super responsive and quick to fix the occasional bug. Seriously, if you use Jellyfin and iOS, and not use this app, you’re missing out. Did I mention that it’s beautiful and free?
On the web, I’m using the web client. It’s not great, but it’s fine. Hoping for Manet on macOS one day5.
Conclusion
And there you have it: A self-hosted music streaming service for around €6 / month, configured with a few lines of code and requiring little maintenance.
I’ve been using this for over a month now, and I couldn’t be happier.
What does your setup look like? Any feedback? Let me know!
-
I have a load average of 0.05 while listening to music. It’s fine. ↩
-
Caddy adds a
Server
header by default. To remove it, addheader /* { -Server }
to your config. ↩ -
Very deep in Stack Overflow threads was one comment, suggesting that the log file was too large. I can’t find it anymore. Do you have additional information? I’d love to hear from you! ↩
-
I wish this could be configured with Nix. ↩
-
No pressure, André! ↩