Jellyfin Security Hardening 2026: CrowdSec, GeoIP Blocking, Rate Limiting & Intrusion Detection

Jellyfin Security Hardening 2026: CrowdSec, GeoIP Blocking, Rate Limiting & Intrusion Detection

Jellyfin Security Hardening 2026: Beyond Fail2Ban

If your Jellyfin server is accessible from the internet, it is being attacked. Right now. Automated bots scan the entire IPv4 space in hours looking for exposed services.

Fail2Ban is a good start - but it is reactive (bans after attacks) and isolated (each server learns independently). In 2026, better tools exist.

This guide covers a layered security approach that goes far beyond basic password protection.


The Security Stack

LayerToolWhat it does
1. NetworkGeoIP blockingBlock entire countries you never access from
2. EdgeRate limitingPrevent brute-force at the reverse proxy
3. DetectionCrowdSecCollaborative IPS with crowd-sourced blocklists
4. Authentication2FA + SSOSecond factor for all accounts
5. ContainerDocker hardeningMinimize attack surface
6. MonitoringJellyWatch + alertsReal-time visibility

Layer 1: GeoIP Country Blocking

If you only access your server from 2-3 countries, block everything else. This eliminates 80%+ of automated attacks instantly.

With Caddy + MaxMind GeoIP

# Caddyfile with geoip module
jellyfin.yourdomain.com {
    @blocked {
        not maxmind_geolocation {
            db_path /etc/caddy/GeoLite2-Country.mmdb
            allow_countries FR US DE GB CA
        }
    }
    respond @blocked 403

    reverse_proxy jellyfin:8096
}

With Nginx + ngx_http_geoip2_module

# In http block
geoip2 /etc/nginx/GeoLite2-Country.mmdb {
    auto_reload 24h;
    $geoip2_country_code country iso_code;
}

# In server block
if ($geoip2_country_code !~ ^(FR|US|DE|GB|CA)$) {
    return 403;
}

With Cloudflare (easiest)

If you use Cloudflare Tunnel or proxy:

  1. Security → WAF → Custom Rules → Create Rule
  2. Expression: (not ip.geoip.country in {"FR" "US" "DE" "GB" "CA"})
  3. Action: Block

Zero server-side configuration needed.


Layer 2: Rate Limiting

Prevent brute-force login attempts at the reverse proxy level - before they even reach Jellyfin.

Caddy rate limiting

jellyfin.yourdomain.com {
    rate_limit {
        zone jellyfin_login {
            key {remote_host}
            events 5
            window 1m
        }
    }

    reverse_proxy jellyfin:8096
}

Nginx rate limiting

# In http block
limit_req_zone $binary_remote_addr zone=jellyfin_login:10m rate=5r/m;

# In location block for login endpoint
location /Users/AuthenticateByName {
    limit_req zone=jellyfin_login burst=3 nodelay;
    proxy_pass http://jellyfin:8096;
}

This limits login attempts to 5 per minute per IP - legitimate users never hit this limit.


Layer 3: CrowdSec - The Modern Fail2Ban

CrowdSec is an open-source, collaborative intrusion prevention system. Unlike Fail2Ban:

  • Crowd-sourced blocklists - when one CrowdSec user detects an attacker, ALL users benefit
  • Behavioral detection - not just regex on logs, but scenario-based analysis
  • Multi-service - one agent protects Jellyfin, SSH, Nginx, and more
  • Remediation components - block at firewall, reverse proxy, or Cloudflare level

Docker Compose setup

services:
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    environment:
      - COLLECTIONS=crowdsecurity/linux crowdsecurity/nginx LePresidente/jellyfin
      - GID=1000
    volumes:
      - ./crowdsec/config:/etc/crowdsec
      - ./crowdsec/data:/var/lib/crowdsec/data
      - /var/log:/var/log:ro
      - ./jellyfin/config/log:/var/log/jellyfin:ro
    restart: unless-stopped

  crowdsec-bouncer:
    image: fbonalair/traefik-crowdsec-bouncer:latest
    container_name: crowdsec-bouncer
    environment:
      - CROWDSEC_BOUNCER_API_KEY=your_bouncer_key
      - CROWDSEC_AGENT_HOST=crowdsec:8080
    restart: unless-stopped

Install the Jellyfin collection

docker exec crowdsec cscli collections install LePresidente/jellyfin

This installs:

  • Parser: understands Jellyfin log format
  • Scenario: detects brute-force login attempts
  • Blocklist: community-shared attacker IPs

How CrowdSec protects Jellyfin

  1. CrowdSec reads Jellyfin logs (/var/log/jellyfin/)
  2. Detects patterns: 5 failed logins from same IP in 1 minute
  3. Creates a decision: ban this IP for 4 hours
  4. The bouncer (at your reverse proxy) enforces the ban
  5. The attacker IP is shared with the CrowdSec community
  6. Other CrowdSec users preemptively block this IP

CrowdSec vs Fail2Ban

FeatureCrowdSecFail2Ban
DetectionBehavioral scenariosRegex on logs
SharingCrowd-sourced blocklistsIsolated per server
PerformanceGo binary, fastPython, slower
Multi-serviceOne agent, many servicesOne jail per service
RemediationMultiple bouncersiptables only
DashboardYes (web console)No
Docker nativeYesRequires log access

Layer 4: Authentication Hardening

Beyond 2FA (covered in our dedicated guide):

JellyWatchTry JellyWatch — Your Jellyfin companion, everywhere.

Disable password authentication for admin

Use SSO (Authelia/Authentik) as the only login method for admin accounts. Even if someone guesses the password, they cannot log in without the SSO provider.

API key rotation

Rotate your Jellyfin API keys quarterly:

  1. Dashboard → API Keys → Create new key
  2. Update all integrations (JellyWatch, Radarr, Sonarr, etc.)
  3. Delete the old key

Session timeout

Dashboard → Networking → set reasonable session timeouts for inactive users.


Layer 5: Docker Container Hardening

Run as non-root

jellyfin:
  user: "1000:1000"
  read_only: true
  tmpfs:
    - /tmp
  security_opt:
    - no-new-privileges:true

Limit capabilities

  cap_drop:
    - ALL
  cap_add:
    - CHOWN
    - SETUID
    - SETGID

Network isolation

networks:
  frontend:  # Only reverse proxy connects here
  backend:   # Internal services only

Layer 6: Monitoring and Alerting

JellyWatch push notifications

JellyWatch alerts you on:

  • Failed login attempts
  • New device connections
  • Unusual session patterns
  • Server offline detection

CrowdSec dashboard

Access the CrowdSec web console to see:

  • Blocked IPs in real time
  • Attack patterns and origins
  • Community threat intelligence

Uptime Kuma

Monitor your Jellyfin /health endpoint. Get alerted the moment your server goes down.


The Complete Hardened docker-compose.yml

services:
  caddy:
    image: caddy:2-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
    networks:
      - frontend
    restart: unless-stopped

  jellyfin:
    image: jellyfin/jellyfin:latest
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp
      - /cache
    security_opt:
      - no-new-privileges:true
    volumes:
      - ./jellyfin/config:/config
      - /mnt/media:/media:ro
    devices:
      - /dev/dri:/dev/dri
    networks:
      - frontend
    restart: unless-stopped

  crowdsec:
    image: crowdsecurity/crowdsec:latest
    environment:
      - COLLECTIONS=crowdsecurity/linux LePresidente/jellyfin
    volumes:
      - ./crowdsec/config:/etc/crowdsec
      - ./crowdsec/data:/var/lib/crowdsec/data
      - ./jellyfin/config/log:/var/log/jellyfin:ro
    networks:
      - backend
    restart: unless-stopped

networks:
  frontend:
  backend:
    internal: true

volumes:
  caddy_data:

Security Checklist

LayerToolStatus
HTTPSCaddy/Nginx + Let's Encrypt
GeoIP blockingCloudflare or reverse proxy
Rate limitingReverse proxy config
IPSCrowdSec + Jellyfin collection
2FATOTP plugin or Authelia
Container hardeningnon-root, read-only, no-new-privileges
MonitoringJellyWatch + Uptime Kuma
API key rotationQuarterly schedule
UpdatesWatchtower or manual weekly

FAQ

Is CrowdSec free? Yes. The Security Engine is open source and free. The community blocklists are free. Premium blocklists (more comprehensive) are paid.

Does GeoIP blocking affect VPN users? Yes. If a user connects via a VPN in a blocked country, they will be blocked. Whitelist your VPN provider's IP ranges if needed.

Can I use CrowdSec AND Fail2Ban? You can, but it is redundant. CrowdSec replaces Fail2Ban with better detection and crowd-sourced intelligence.

Does this slow down Jellyfin? No. GeoIP and rate limiting happen at the reverse proxy (before Jellyfin). CrowdSec reads logs asynchronously. Zero impact on playback.


Your server is hardened - now monitor it from your pocket. Download JellyWatch on Google Play - failed login alerts, session monitoring, and server health for Jellyfin.

On Emby? Download EmbyWatch on Google Play

Comments 2

SecOps_Admin·

Switched from Fail2Ban to CrowdSec last month. The crowd-sourced blocklists are the killer feature. My server was getting hit by IPs that other CrowdSec users had already flagged. Blocked before they even tried my login page.

NetAdmin·

GeoIP blocking at the Cloudflare level is the easiest win. I only access my server from 3 countries. Blocking everything else eliminated 90% of my failed login attempts overnight. Zero server-side configuration needed.

Leave a comment

Never displayed publicly.
0 / 2000 · Supports limited Markdown: **bold**, *italic*, `code`, [link](url), lists, > quote.