fail2ban
Fail2ban
Fail2ban is an intrusion prevention software framework that protects computer servers from brute-force attacks. Fail2ban operates by monitoring log files (e.g. /var/log/auth.log, /var/log/apache/access.log, etc.) for selected entries and running scripts based on their content.
Jellyfin produces logs that can be monitored by Fail2ban to prevent brute-force attacks on your machine.
Requirements
- Jellyfin remotely accessible
- Fail2ban installed and running
- Knowing where the logs for Jellyfin are stored: by default
/var/log/jellyfin/
for desktop and/config/log/
for docker containers.
Step one: create the jail
You need to create a jail for Fail2ban. If you're on Ubuntu and use nano as editor, run:
sudoedit /etc/fail2ban/jail.d/jellyfin.local
Add this to the new file, replacing /path_to_logs
with the path to the log files above, e.g. /var/log/jellyfin/
:
[jellyfin]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = jellyfin
maxretry = 3
bantime = 86400
findtime = 43200
logpath = /path_to_logs/jellyfin*.log
Save and exit nano.
Note:
-
If Jellyfin is running in a docker container, add the following to the
jellyfin.local
file:action = iptables-allports[name=jellyfin, chain=DOCKER-USER]
-
If you're running Jellyfin on a non-standard port, then change the port from
80,443
to the relevant port say8096,8920
Step two: create the filter
The filter contains a set of rules which Fail2ban will use to identify a failed authentication attempt. Create the filter by running:
sudoedit /etc/fail2ban/filter.d/jellyfin.conf
Paste:
[Definition]
failregex = ^.*Authentication request for .* has been denied \(IP: "<ADDR>"\)\.
Save and exit, then reload Fail2ban:
sudo systemctl restart fail2ban
Check fail2ban is running:
sudo systemctl status fail2ban
Step three: test
Assuming you've at least one failed authentication attempt, you can test this new jail with fail2ban-regex
:
sudo fail2ban-regex /path_to_logs/*.log /etc/fail2ban/filter.d/jellyfin.conf --print-all-matched
Advanced Fail2Ban Setup: Forwarding and Managing Bans on an Upstream Proxy Server
To enhance security, Fail2Ban can manage IP bans on an upstream reverse proxy server instead of directly on the Jellyfin server. This setup allows you to block malicious IPs closer to your network’s entry point, potentially benefiting other services using the same proxy.
This guide offers a configuration for setting up Fail2Ban to manage IP bans on an upstream reverse proxy server using Dynamic Chains, where each Fail2Ban jail creates and manages its own iptables
chain on the upstream server.
Assumptions
- Fail2Ban is installed on your local server (where Jellyfin is running).
- iptables is configured on the upstream server.
Step one: Set Up SSH Key-Based Authentication
Ensure the Fail2Ban server can SSH into the upstream server without needing a password. This is crucial for automating the IP ban/unban process.
Replace <upstream-server-ip>
with the actual IP address of your upstream server.
-
Generate SSH Key (if not already done):
ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa
-
Copy the SSH Key to the Upstream Server:
ssh-copy-id -i /root/.ssh/id_rsa.pub root@<upstream-server-ip>
-
Test SSH Access:
Ensure the SSH connection works without needing a password:
ssh -i /root/.ssh/id_rsa root@<upstream-server-ip>
Step two: Configure Fail2Ban for Dynamic Chains
-
Create the Fail2Ban Action File:
On the Fail2Ban server, create a new action file:
sudo nano /etc/fail2ban/action.d/proxy-iptables-dynamic.conf
And add the Following Configuration, which will dynamically create, manage, and remove
iptables
chains on the upstream server per jail:Remember to replace
<upstream-server-ip>
with the actual IP address of your upstream server.[Definition]
# Option: actionban
# 1. Create the chain if it doesn't exist
# 2. Add the banned IP to the dynamic chain based on the jail name
# 3. Log the event
actionban = ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@<upstream-server-ip> \
'iptables -N f2b-<name> 2>/dev/null || true; \
iptables -C INPUT -j f2b-<name> 2>/dev/null || iptables -I INPUT -j f2b-<name>; \
iptables -I f2b-<name> 1 -s <ip> -j DROP' && \
echo "Banned <ip> from jail <name> via upstream proxy" >> /var/log/fail2ban.log
# Option: actionunban
# 1. Remove the banned IP from the dynamic chain
# 2. Remove the chain if it becomes empty (cleanup)
# 3. Log the event
actionunban = ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@<upstream-server-ip> \
'iptables -D f2b-<name> -s <ip> -j DROP; \
if ! iptables -L f2b-<name> | grep -q "DROP"; then \
iptables -D INPUT -j f2b-<name>; \
iptables -F f2b-<name>; \
iptables -X f2b-<name>; \
fi' && \
echo "Unbanned <ip> from jail <name> via upstream proxy and cleaned up chain if empty" >> /var/log/fail2ban.logAfter making chaneges, save and close the file.
-
Update Fail2Ban Jails to Use the Dynamic Chain Action:
Open your jail configuration file, usually located at
/etc/fail2ban/jail.local
:sudo nano /etc/fail2ban/jail.local
And for each jail you want to manage via the upstream proxy, add or modify the action line to use the proxy-iptables-dynamic action. Here’s an example configuration for two jails:
[jellyfin]
enabled = true
filter = jellyfin
logpath = /path/to/jellyfin/log
maxretry = 3
bantime = 3600
action = proxy-iptables-dynamic
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
action = proxy-iptables-dynamicAfter making chaneges, save and close the file.
Step three: Restart Fail2Ban and Test the Setup
-
Restart Fail2Ban:
After making the configuration changes, restart Fail2Ban to apply the new settings:
sudo systemctl restart fail2ban
-
Check Jail Status:
Verify the status of your jails to ensure they are running correctly:
sudo fail2ban-client status jellyfin
-
Test a Ban:
Trigger a ban by performing invalid login attempts or by manually banning an IP. For example:
sudo fail2ban-client set jellyfin banip 192.168.1.100
-
Verify on Upstream Server:
Check if the IP is banned in the corresponding jail's chain on the upstream server ('f2b-jail-name'):
ssh root@<upstream-server-ip> "iptables -L f2b-jellyfin"
-
Test Unbanning:
To test unbanning, manually unban the IP:
sudo fail2ban-client set jellyfin unbanip 192.168.1.100
-
Verify Unban:
Verify that the IP is removed from the corresponding jail's chain ('f2b-jail-name'):
ssh root@<upstream-server-ip> "iptables -L f2b-jellyfin"
Step four: Monitor Logs
Monitor the Fail2Ban log to ensure that actions are being executed properly:
tail -f /var/log/fail2ban.log
This log will display messages whenever an IP is banned or unbanned, helping you confirm that the configuration is working as expected.