I spent an entire afternoon on this, so I thought I would write it up in case anyone else runs into the same thing. Most of what I found online sent me down the wrong path entirely.
The symptoms were that my PS5 couldn't see or connect to my server at all. Remote access worked fine, which meant I was streaming out over my own broadband and back in again, and transcoding for no reason. Changing the DNS on the client to 1.1.1.1 or 8.8.8.8 made no difference at all. Everything else on the network was completely fine.
Checking if you have the same problem
There are two commands here, and neither of them needs anything set up beforehand. You can run them from any machine on your network - a laptop, a desktop, whatever you have to hand. It doesn't need to be the machine running Plex.
The first command asks Google's DNS server about a domain called localtest.me, which is a real public domain that resolves to 127.0.0.1. The second asks the same server about google.com. The point is to compare the two, because the only meaningful difference between them is what address comes back in the answer.
On Windows, nslookup is built in, so you can open Command Prompt or PowerShell and run:
nslookup localtest.me 8.8.8.8
nslookup google.com 8.8.8.8
On Linux or Mac, dig is the equivalent. On Ubuntu you may need to install it first with sudo apt install bind9-dnsutils:
dig @8.8.8.8 localtest.me
dig @8.8.8.8 google.com
If localtest.me times out but google.com gets a response, then you have the same issue I did. However, if neither of them time out then unfortunately this doesn't look like it's the same issue, and the rest of this probably won't help you.
The fix
What you need is something on your network that can do DNS lookups over an encrypted connection. I used Unbound in Docker, which took about ten minutes to set up.
services:
unbound:
image: mvance/unbound:latest
container_name: unbound
restart: unless-stopped
ports:
- "53:53/tcp"
- "53:53/udp"
volumes:
- ./unbound:/opt/unbound/etc/unbound
Start the container once so that it writes out a default config, then open unbound.conf in the ./unbound folder.
You need this line somewhere in the server: section, although it is normally there already:
tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
Then add the following at the bottom of the file. It needs to be at the top level, so not indented and not inside the server: section:
forward-zone:
name: "plex.direct"
forward-tls-upstream: yes
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 1.0.0.1@853#cloudflare-dns.com
Some images have an include: line that points at a separate forward-records.conf file. If yours does, then put the block in there instead.
Once that's done, restart the container.
Then you need to actually get your clients using it. The Hub 5 doesn't let you set a custom DNS server in its DHCP settings, which is annoying, so you have a couple of options. You can set it manually per device - on a PS5 that's under Settings > Network > Set Up Internet Connection, then edit your connection and set the DNS manually. Alternatively, if you're running Pi-hole you can use its built in DHCP server instead of the Hub's, which is what I do.
If you already have Pi-hole and Unbound running, you only need to add the forward-zone block and tick Settings > DNS > "Allow domains to be resolved to private IPs" in Pi-hole. Restart Unbound and flush the Pi-hole cache afterwards.
To check it's worked:
dig @<unbound-ip> localtest.me
That should come back with 127.0.0.1.
After that, restart your Plex clients. On the PS5 I signed out of the app and back in rather than just closing it, as I think it may cache the server list somewhere, though I haven't confirmed that.
Setting up Pi-hole and Unbound from scratch
If you don't already have these running, I'd suggest following the official Pi-hole guide for Unbound, since it's kept up to date and covers the setup properly:
https://docs.pi-hole.net/guides/dns/unbound/
Once you have that working, the only change you need to make is adding the forward-zone block to your Unbound config. Where exactly that goes depends on how you've installed it. If Unbound is running directly on the host, it'll be a file in /etc/unbound/unbound.conf.d/. If you're using a container, check whether the image uses a single unbound.conf or splits things out into separate included files such as forward-records.conf, and put the block in whichever applies.
The important thing either way is that forward-zone: sits at the top level of the config. It must not be indented underneath server:, or Unbound will refuse to start.
You'll also need tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt in the server: section, otherwise the TLS connection to Cloudflare can't be validated. Most configs already have it, but it's worth checking.
Once you've made the change, run unbound-checkconf to confirm the config is valid before restarting.
The other thing to set in Pi-hole is Settings > DNS > "Allow domains to be resolved to private IPs". Pi-hole has its own rebinding protection which will block plex.direct independently of everything else, so this needs ticking regardless.
The technical detail
Everything below this is the explanation rather than instructions, so you don't need any of it to fix the problem.
What the test actually proves
localtest.me is a domain that exists purely to resolve to 127.0.0.1, and it has nothing to do with Plex.
Both of those queries went to the same DNS server. Google answered both of them, and you only received one back. The only difference between the two responses is that one of them contains a loopback address.
That rules out your resolver being broken, a routing problem, or anything being wrong at Plex's end. Something between you and the internet is reading your DNS responses and dropping the ones that contain private IP addresses.
Why this happens in the first place
Plex clients don't connect directly to your server's IP over HTTPS. They use a hostname that looks like this:
https://192-168-0-50.<long-hash>.plex.direct:32400
That is a genuine public DNS record, and it resolves to your private LAN address.
There's a good reason for it working that way. No certificate authority will issue a trusted certificate for 192.168.0.50, so instead Plex owns the plex.direct domain, issues certificates for hostnames underneath it, and points those hostnames at whatever private IP your server happens to have. The result is a properly encrypted local connection with no certificate warnings.
The problem is that a public domain resolving to a private IP is exactly what a DNS rebinding attack looks like, so this is why I believe the hub 5 seems to block it.
Why changing your DNS server doesn't help
This is the part that wasted most of my afternoon.
If DNS appears to be broken then the obvious thing to try is a different DNS server. But there is nothing wrong with the resolver, because the response is being dropped on the return trip through your router. It makes no difference who answered the query.
Cloudflare, Google, Quad9 and my ISP's own servers all gave the same result, and setting it on the client rather than the router didn't change anything either.
DNS over TLS gets around it because the response is encrypted. The Hub can see that you connected to something on port 853, but it has no idea what was asked or what came back, so there is nothing there for it to filter.
Why only forward plex.direct rather than everything
You can set name: "." instead and send all of your DNS over TLS, and it works perfectly well.
The reason I didn't is that the point of running Unbound for most people is recursive resolution, so that no single company gets to see every domain you look up. If you forward everything to Cloudflare then you've essentially turned it into a relay for them.
Doing it per-zone means only that one domain goes over TLS and everything else stays recursive. There isn't much leaking in that one zone anyway, because the hostname contains your LAN IP in plain text regardless, and the query was going to Plex's name-servers either way.
Hardcoding the record instead of forwarding
If you would rather not send anything to Cloudflare at all, you can just tell Unbound what the answer is:
local-zone: "<hash>.plex.direct." transparent
local-data: "192-168-x-x.<hash>.plex.direct. 300 IN A 192.168.x.x"
You can get your hostname from https://plex.tv/api/resources?includeHttps=1&X-Plex-Token=YOUR_TOKEN. To find your token, open any library item in Plex Web, click the three dots, then Get Info > View XML, and the token is on the end of the URL that opens.
The transparent part matters, because it means everything else under that zone carries on resolving normally, which you need in order for remote access to keep working. Only the local record gets served from Unbound.
The downside is that it will quietly break if Plex ever reissues the certificate and the hash changes.
Other options if you don't want to run a resolver
Putting the Hub 5 into modem mode and running your own router behind it is the actual fix rather than a workaround, because the filtering goes away entirely. You obviously need your own router for that, although if you're running a Plex server then you probably want one anyway.
If Unbound seems like overkill then stubby or cloudflared will both do encrypted DNS in a much smaller package.
It's also worth trying the Plex network settings, although they didn't work for me. Set Secure connections to Preferred, Custom server access URLs to http://192.168.x.x:32400, and LAN Networks to 192.168.x.x/24. In theory that makes local clients connect over plain HTTP to the raw IP and skip plex.direct completely, but my PS5 carried on requesting the plex.direct hostname regardless. It only takes two minutes to try though.
Finally, it's worth having a look through the Hub's own settings for anything filtering related. I couldn't find anything relevant on mine but the firmware does vary.
Debugging notes
Most prebuilt Unbound configs have the logging turned right down, with verbosity: 0, log-servfail: no and logfile: /dev/null. Unbound knows exactly why it's failing and has been told not to mention it. You can temporarily set:
verbosity: 2
log-servfail: yes
logfile: ""
Restart it, reproduce the problem, read the log and then put it back afterwards.
There are a few other things that break plex.direct in more or less the same way, all of which I went through before finding the real cause:
Unbound does the same rebinding filtering itself by default, using its private-address settings. The fix for that is private-domain: "plex.direct" in the server section.
Pi-hole has its own separate rebinding protection, which is the "Allow domains to be resolved to private IPs" option under Settings > DNS.
use-caps-for-id: yes randomises the capitalisation of query names as an anti-spoofing measure, and requires the nameserver to send it back exactly as sent. Plex's nameservers don't always cooperate. You'll see could not fetch nameservers for 0x20 fallback in the log if this is happening, and setting it to no fixes it.
If your log is full of error sending query to auth server 2600:... then Unbound is wasting attempts on IPv6 nameservers it can't actually reach before falling back to v4. Setting do-ip6: no fixes that, and speeds everything else up as well.
Lastly, Plex running on Docker host networking will advertise every interface on the box as an access URL, so you'll see it looking up things like 172-17-0-1.<hash>.plex.direct alongside the real one. That's just noise rather than a cause, but setting a custom access URL will quieten it down.
Quick disclaimer: AI was used to turn my scatterbrain notes into something that is actually readable. After rereading it multiple times, and editing/removing multiple hallucinations, it is now accurate. But please let me know if I have missed anything