I already host multiple services via caddy as my reverse proxy. Jellyfin, I am worried about authentication. How do you secure it?
What I used to do was: I put jellyfin behind an nginx reverse proxy, on a separate vhost (so on a unique domain). Then I added basic authentication (a htpasswd file) with an unguessable password on the whole domain. Then I added geoip firewall rules so that port 443 was only reachable from the country I was in. I live in small country, so this significantly limits exposure.
Downside of this approach: basic auth is annoying. The jellyfin client doesn’t like it … so I had to use a browser to stream.
Nowadays, I put all my services behind a wireguard VPN and I expose nothing else. Only issue I’ve had is when I was on vacation in a bnb and they used the same IP range as my home network :-|
setup a WAF appliance and forward traffic through it to your current installation.
WAF??
web application firewall.
think of it like an intelligent firewall proxy that can take action against perceived threats like injection attacks or timed attacks. some can also help fight against DDOS when integrated with an actual firewall upstream.
I’ve put it behind WireGuard since only my wife and I use it. Otherwise I’d just use Caddy or other such reverse proxy that does https and then keep Jellyfin and Caddy up to date.
I use good ol’ obscurity. My reverse proxy requires that the correct subdomain is used to access any service that I host and my domain has a wildcard entry. So if you access asdf.example.com you get an error, the same for directly accessing my ip, but going to jellyfin.example.com works. And since i don’t post my valid urls anywhere no web-scraper can find them. This filters out 99% of bots and the rest are handled using authelia and crowdsec
If you’re using jellyfin as the url, that’s an easily guessable name, however if you use random words not related to what’s being hosted chances are less, e.g. salmon.example.com . Also ideally your server should reply with a 200 to * subdomains so scrappers can’t tell valid from invalid domains. Also also, ideally it also sends some random data on each of those so they don’t look exactly the same. But that’s approaching paranoid levels of security.
And since i don’t post my valid urls anywhere no web-scraper can find them
You would ah… be surprised. My urls aren’t published anywhere and I currently have 4 active decisions and over 300 alerts from crowdsec.
It’s true none of those threat actors know my valid subdomains, but that doesn’t mean they don’t know I’m there.
Of course i get a bunch of scanners hitting ports 80 and 443. But if they don’t use the correct domain they all end up on an Nginx server hosting a static error page. Not much they can do there
This is how I found out Google harvests the URLs I visit through Chrome.
Got google bots trying to crawl deep links into a domain that I hadn’t published anywhere.
This is true, and is why I annoyingly have to keep robots.txt on my unpublished domains. Google does honor them for the most part, for now.
That reminds me … another annoying thing Google did was list my private jellyfin instance as a “deceptive site”, after it had uninvitedly crawled it.
A common issue it seems.
Unsurprising, but still shitty. Par for the course for the company these days.
They did that with most of my subdomains
Whats your setup? I just Ngnix Proxy Manager, Jellyfin etc in Docker. Modify ufw rules and also install this on the server (linux) https://github.com/friendly-bits/geoip-shell
For web access, stick it behind a reverse proxy and use something like Authentik/Authelia/SSO provider of your choice to secure it.
For full access including native clients, set up a VPN.
I use Tailscale right now. Which, in fairness, I didn’t state in the post. However, I was hoping to share it more similarly to how I used to with Plex. But, it would appear, I would have to share it through Tailscale only at this point.
Right now none of the native clients support SSO. It is a frequently requested feature but, unfortunately, it doesn’t look like it will be implemented any time soon. As with many OSS projects it is probably a case of “you want it, you build it” - but nobody has actually stepped up.
My setup: Locally (all in docker):
- JF for managing and local access
- JF with read only mounted volumes that uses the network of my Wireguard client container
- Wireguard client opening a tunnel to Wireguard server on VPS ** Ping container regularly doing pings to Wireguard Server so the connection stays up (didn’t manage it otherwise)
VPS (Oracle Cloud free tier, also everything in docker):
- Caddy as a reverse proxy with https enabled and geolocking (only certain countries are allowed to connect to)
- fail2ban to block IPs that try to bruteforce credentials
- Wireguard server
Usernames are not shown in the frontend and have to be entered. Passwords are generated by a password manager and can’t be changed by the user.
So my clients just get the URL of my reverse proxy and can access the read only JF through my Wireguard tunnel. Didn’t have to open any ports on my side. If someone is interested I can share the docker compose files later.
Edit: Here the link to the setup description. Please tell me if something is not clear or you find an error. https://codeberg.org/skjalli/jellyfin-vps-setup
I am interested in your docker compose
Will share this evening after work.
https://codeberg.org/skjalli/jellyfin-vps-setup here you go, took me longer than expected and I hope it’s helpful, might contain a few errors since I had to remove some settings but I guess this should work.
This is honestly awesome! I was thinking about a similar setup for a long time but wasn’t sure how to do this exactly, this seems exactly like the setup I was looking for. Thank you!
You’re welcome, happy that I can help. I also just updated it a bit. In case you find any issues or have questions please let me know. It was mostly trial and error until it ran…
I’m more interested in the fail2ban setup. How did you do that for Jellyfin? Is it through a plugin?
It’s a separate container, currently in the process of writing everything up, will update once done
Thanks!
https://codeberg.org/skjalli/jellyfin-vps-setup here you go, took me longer than expected and I hope it’s helpful, might contain a few errors since I had to remove some settings but I guess this should work.
Thanks! I’ll read more through it when I have the chance!
This seems like a developer/infrastructure level job, any dumb down step by step procedure to recommend?
I am currently in the ptocess to document my docker fioes and upload them to codeberg with a readme, it takes a bit, will let you know once I am done
https://codeberg.org/skjalli/jellyfin-vps-setup here you go, took me longer than expected and I hope it’s helpful, might contain a few errors since I had to remove some settings but I guess this should work.
Thank you! Impressive documentation work, looks like I have to learn docker first.
It’s a steep learning curve for sure but once you get the basics it’s straight forward until you hit very specific problems.
Are you a Windows or Linux user? They often want to push their Docker UI application but in my opinion docker engine with docker compose is enough. There are probably a lot of great tutorials out there and I can recommend https://www.linuxserver.io/ for images.
I am using tailscale but I went a little further to let my family log in with their Gmail( they will not make any account for 1 million dollars)
Tailscale funneled Jellyfin Keycloak (adminless)
Private Tailscale Keycloak admin Postgres dB
I hook up jellyfin to Keycloak (adminless) using the sso plugin. And hook Keycloak up (using the private instance) to use Google as an identity provider with a private app.
SSO plugin is good to know about. Does that address any of the issues with security that someone was previously talking about?
I’d say it’s nearly as secure as
basic authentication. If you restrict deletion to admin users and use role (or group) based auth to restrict that jellyfin admin ability to people with strong passwords in keycloak, i think you are good. Still the only risk is people could delete your media if an adminusers gmail is hacked.
Will say it’s not as secure as restricting access to vpn, you could be brute forced. Frankly it would be preferable to set up rate limiting, but that was a bridge too far for me
I set mine up with Authelia 2FA and restricted media deletion to one user: The administrator.
All others arent allowed to delete. Not even me.
Tailscale is awesome. Alternatively if you’re more technically inclined you can make your own wireguard tailscale and all you need is to get a static IP for your home network. Wireguard will always be safer than each individual service.
all you need is to get a static IP for your home network
Don’t even need a static IP. Dyndns is enough.
Love tailscale. The only issue I had with it is making it play nice with my local, daily driver VPN. Got it worked out tho. So, now everything is jippity jippity.
Use a VPN like Tailscale
I use fail2ban to ban IPs that fall to login and also IPs that perform common scans in the reverse proxy
also have jellyfin disable the account after a number of failed logins.
I have another site on a different port that sits behind basic auth and adds the IP to a short ipset whitelist.
So first I have to auth into that site with basic auth, then I load jellyfin on the other port.
I don’t understand how that isn’t widely deployed. I call it poor man’s Zero Trust.
I mean I’d rather jellyfin fix the bug and let me just put that behind basic auth
deleted by creator
I use Pangolin (https://github.com/fosrl/pangolin)
I was thinking of setting this up recntly after seeing it on Jim’s garage. Do you use it for all your external services or just jellyfin? How does it compare to a fairly robust WAF like bunkerweb?
I use it for all of my external services. It’s just wireguard and traefik under the hood. I have no familiarity with bunkerweb, but pangolin integrates with crowdsec. Specifically it comes out of the box with traefik bouncer, but it is relatively straightforward to add the crowdsec firewall bouncer on the host machine which I have found to be adequate for my needs.
URL is 404
remove the brace at the end
It’s not, though?
Uhh, interesting! Thanks for sharing.
OpenVPN
Or wireguard, depending where & how they want to implement it might be simpler or better/worse on hardware.