Migrating a Jellyfin Domain

Join me in my quest to migrate my Jellyfin installation to a new domain.

Let’s start off with the current situation. I used to run Jellyfin under some old domain that is mostly decommissioned by now. Jellyfin is literally the only thing that’s still running on there (as I could migrate Plex without the end-users even knowing). But to not inconvenience the folks that still have the old domain configured in their browser bookmarks or one of the thousand Jellyfin clients out there, I’ve kept it alive so far, with both domains pointing to the same reverse proxy and being forwarded to the same Jellyfin instance.

This has worked fine for years, but I am not happy with it. In the long run, I want to let the old domain expire, so I have to migrate the users away from there. This will never fully be done, and removing the domain will inconvenience folks, but slowly migrating off of the old domain will be a start.

That’s why today, I am testing how a bunch of Jellyfin clients handle an HTTP 308 redirect to a new domain.

Current Situation

The current situation may best be described by posting the Reverse Proxy (Apache httpd) VirtualHost config that’s running everything:

<VirtualHost *:80>
        ServerName jellyfin.new.example.com
        ServerAlias jellyfin.old.example.com

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
        ServerName jellyfin.new.example.com
        ServerAlias jellyfin.old.example.com

        SSLEngine on
        SSLCertificateFile /etc/pki/tls/certs/jellyfin.new.example.com.crt
        SSLCertificateKeyFile /etc/pki/tls/private/jellyfin.new.example.com.key
        SSLCertificateChainFile /etc/pki/tls/certs/jellyfin.new.example.com-fullchain.crt
        ProxyPass "/"  "http://localhost:8095/"
        ProxyPassReverse "/"  "http://localhost:8095/"
</VirtualHost>

The certificates are configured to contain both CNs for the old and the new domain. Also, obviously, I’ve redacted the actual domains.

The Plan

The plan is simple. Install as many Jellyfin clients as I can find, add an HTTP 308 to the config and see what happens. As I don’t have an Android available right now, I’ll only be testing iOS clients, but I imagine the behaviors should be similar. The new config looks like this:

<VirtualHost *:80>
        ServerName jellyfin.new.example.com

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
        ServerName jellyfin.new.example.com

        SSLEngine on
        SSLCertificateFile /etc/pki/tls/certs/jellyfin.new.example.com.crt
        SSLCertificateKeyFile /etc/pki/tls/private/jellyfin.new.example.com.key
        SSLCertificateChainFile /etc/pki/tls/certs/jellyfin.new.example.com-fullchain.crt
        ProxyPass "/"  "http://localhost:8095/"
        ProxyPassReverse "/"  "http://localhost:8095/"
</VirtualHost>


<VirtualHost *:80>
        ServerName jellyfin.old.example.com

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^ https://jellyfin.new.example.com%{REQUEST_URI} [R=302]
</VirtualHost>
<VirtualHost *:443>
        ServerName jellyfin.old.example.com

        SSLEngine on
        SSLCertificateFile /etc/pki/tls/certs/jellyfin.new.example.com.crt
        SSLCertificateKeyFile /etc/pki/tls/private/jellyfin.new.example.com.key
        SSLCertificateChainFile /etc/pki/tls/certs/jellyfin.new.example.com-fullchain.crt

        RewriteEngine On
        RewriteRule ^ https://jellyfin.new.example.com%{REQUEST_URI} [R=308]
</VirtualHost>

The Results Are In

It’s a mixed bag. Obviously, for the web client, the user gets redirected to the new domain and, since no cookies are being sent, has to log in again. This was to be expected and I don’t think there is any way around this.

The apps however are where things get interesting. All of them internally follow the redirect, which is good so far, and all of them don’t send the login data to the new domain (also good). So all of them get an HTTP 401 back. This is where they diverge. While the official Jellyfin apps know how to handle this and re-displays the login page (best case scenario), every single third-party app I’ve tried just tells the user there was an authentication error, HTTP 401 error, or similar things. So all of them have to be reconfigured.

In the light of this I have checked my Jellyfin/reverse proxy logs to see how many people actually use a third-party app, and luckily it’s only two persons, both using the Infuse app. I’ve messaged them separately, but both know tech enough to change the domain themselves.

For the people using the official app, I expect to have to reset some passwords in the near future, but this is life as a homelab sysadmin after all.

Since things worked out less bad than I expected, I will leave the redirect in place and may be able to fully decommission the domain in the next decade.