undownable

How to monitor Jellyfin from outside your network

Updated Aug 19, 2026

Jellyfin is one of the few self hosted media servers that gives you a proper health endpoint instead of making you guess. That is worth using well, and worth understanding the limits of.

What breaks quietly

Jellyfin logs an error and carries on. It does not phone you, and any notification plugin you have wired up originates inside the same container, on the same host, behind the same router that is often the actual problem.

Only the last two are visible from the internet, and none are visible to something running on the same box. That asymmetry is the whole argument for an outside prober.

The endpoints worth checking

Jellyfin serves HTTP on port 8096 by default. HTTPS on 8920 exists but is off unless you enable it, and most people terminate TLS at a reverse proxy instead.

GET /health is a genuine liveness endpoint. Jellyfin documents it as verifying HTTP and database connectivity, and it returns 200 when both work. It needs no authentication. One documented caveat: it does not behave correctly during startup or database migrations, so give it a confirmation threshold rather than paging on the first failure after an update.

For a stricter assertion, GET /System/Info/Public also answers unauthenticated, returning JSON including ServerName, Version, ProductName, Id, and StartupWizardCompleted. A JSON check can pin Version, or confirm StartupWizardCompleted is true, which catches the ugly case where a volume did not mount and Jellyfin came back offering the first run wizard to the internet.

Endpoint Auth Good for
/health None HTTP plus database liveness
/System/Info/Public None JSON assertions on version and setup state
/System/Info API key Full server detail, admin only
TCP 8096 None Port and process reachability

The authenticated /System/Info needs an API key in an Authorization header using the MediaBrowser scheme, in the form MediaBrowser Token="yourkey". Create the key from the Dashboard under Advanced, then API Keys. Undownable stores custom request headers encrypted. Older bare token headers such as X-Emby-Token still work on many builds but are the legacy path.

Exposed through a proxy or tunnel

If Jellyfin is published at a hostname your users type, check that hostname. Checking the LAN IP tells you nothing about the path everyone else takes.

curl -fsS -o /dev/null -w '%{http_code}\n' https://jellyfin.example.com/health
# 200

Pair it with an SSL certificate check on the same hostname. Expiry is the most common way a working Jellyfin becomes unreachable, and escalating warnings turn that into a calendar reminder instead of an incident.

One trap: if your reverse proxy returns a friendly maintenance page on upstream errors, a plain HTTP check sees 200 and stays green while Jellyfin is dead. That is where the JSON check on /System/Info/Public earns its keep, because a maintenance page has no ServerName field.

Private installs: push a heartbeat instead

Keeping Jellyfin behind a VPN does not mean giving up external monitoring. Flip the direction and have the host report in, so silence becomes the alert.

*/2 * * * * curl -fsS -m 10 https://undownable.com/ping/your-monitor-id > /dev/null

Better, chain it behind the local health probe so it reflects Jellyfin rather than the machine:

*/2 * * * * curl -fsS -m 10 http://127.0.0.1:8096/health > /dev/null \
  && curl -fsS -m 10 https://undownable.com/ping/your-monitor-id > /dev/null

When /health stops returning 200 the first curl exits non zero, the second never runs, and the heartbeat goes quiet. Expect a ping roughly every two minutes with grace for one missed run, and you get an incident within about five minutes of a failure, from a service that is not in your house.

Heartbeats accept GET or POST, so this works equally well from a systemd timer or a sidecar container.

Alerts that outlive the outage

A notification plugin inside Jellyfin cannot tell you Jellyfin stopped. Route alerting through something outside the failure domain:

Turn on flap suppression if your container restarts on a schedule, and set a maintenance window around update night.

Does Jellyfin really have a /health endpoint?

Yes. GET /health is documented by Jellyfin as verifying HTTP and database connectivity, requires no authentication, and returns 200 when healthy. The docs warn it misbehaves during startup and database migrations, so allow a confirmation threshold.

Should I check /health or /System/Info/Public?

Check /health for liveness and /System/Info/Public when you want a JSON assertion a reverse proxy error page cannot fake. Many people run both: one cheap liveness check and one stricter identity check.

Do I need an API key?

Not for /health or /System/Info/Public, which both answer unauthenticated. You need one only for admin endpoints such as /System/Info, sent as Authorization with the MediaBrowser Token form.

Is it safe to expose /health to the internet?

It reveals only that the server is alive. /System/Info/Public is the more interesting one, since it exposes server name and version to anyone. If that bothers you, keep Jellyfin private and use the gated heartbeat.

Related reading

Monitoring that watches from the outside

Free plan with 10 monitors, plus a 14-day Pro trial. No credit card required.

Start free