Self-hosted music synergy

I've had something very specific which has irritated me for a long time, namely that of what to do with my local MP3s. At face value the solution is simple, they're just MP3s right - just store them locally on your computer, and then sync them to your phone! Well, that's what I've been doing (in combination with Nextcloud), however it's always been a pain to make sure that what's deleted on the phone is deleted on the computer, and vice versa. Not to mention the fact that if I ever switched to an iPhone in the future I would be out of luck. The other solution is a cloud solution, which I did use back in ~2012 when Google Music was still around (RIP) but seeing how I already have a Nextcloud instance that sounds unnecessarily wasteful. Up until now I've been unable to think of any way of solving this, especially ways in how I could keep using my favorite MP3-player on the desktop (cmus) in tandem with that solution, but just yesterday I managed to come up with a solution: use Nextcloud in combination with Airsonic. Spoiler alert: it works flawlessly.

In order to make that work I had to have the following features: I needed to be able to upload files via a Nextcloud instance as usual with the Nextcloud desktop client (so that it appears as local files on my computer), files which then can be seen from other programs. This is impossible using the regular Nextcloud way of handling files as they have locked-down permissions. What I ended up finding was the 'External storage' app on Nextcloud, which allowed me to "mount" a local folder on the server for my account. I refer here to the official documentation available here, but the steps are pretty simple: 1.) change ownership of the folder in question to www-data (or whatever user is running Nextcloud), 2.) change the permission of that folder to 0750.

Airsonic is a self-hosted music streamer, specifically designed to handle very large music collections, as well as podcast support. This is totally overkill for my needs, but it was in my research the one that came both highly recommended and provided ubiquitous app support for both iOS and Android. The web UI leaves something to be desired, hearkening back to the days of PHP in the late 00's:

For my needs this isn't a big deal seeing that I won't touch the WebUI unless I have to do admin-stuff.

Setting up Airsonic was easy seeing as I already had docker set up on my server, so I just used the linuxserver docker package available here [copy-pasting the docker-compose block from the documentation]. Here you have to change the PUID & PGID to the web user(which you can get from running id WEBUSER, replacing WEBUSER with e.g. www-data), as well as changing CONTEXT_PATH to your desired subdomain. For example, if you plan on hosting it at https://YOURDOMAIN.com/airsonic you change it to airsonic. After running docker-compose up -d I was up and running locally at port 4040. Everything at that point worked, with the exception of duplicate albums, which was the result of me setting the podcast directory as identical to the music directory (whoops!). However, as I put it behind nginx (using the official configuration as available here) I ran into my first real issue: all the album art was missing from the WebUI (but working on my phone). I fixed it by finding some random nginx config file on GitHub (and subsequently quickly forgot where I found it). The reverse proxy block looks like follows:

location /music {
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host  $http_host;
    proxy_set_header Host              $http_host;
    proxy_max_temp_file_size           0;

    # Use secure headers to avoid XSS and many other things
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "no-referrer";

    # variables to keep line length under 80
    set $SCR "script-src 'self' 'unsafe-inline' 'unsafe-eval'";
    set $FRM "frame-src 'self'";
    set $OBJ "object-src 'self'";
    add_header Content-Security-Policy "${SCR}; ${FRM}; ${OBJ}";

    proxy_pass                         http://127.0.0.1:4040;
    proxy_redirect                     http:// https://;
}

Now I have seamless integration between my computer and my phone without me having to depend on syncing specific folders to my phone - now I can just play and sync whatever I like to, without any hassle. Neat!