diff --git a/check_fail2ban.sh b/check_fail2ban.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ca0f120a5d4d2e7edcf5338f9affd5bdfcc5c65d
--- /dev/null
+++ b/check_fail2ban.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+
+# Default threshold values.
+ips_threshold_warning=20
+ips_threshold_critical=40
+
+print_help() {
+    echo "usage: ${0} [OPTIONS] <jails>"
+    echo "options:"
+    echo -e " -c, --critical <ips count>\t\tcritical threshold values for IP count"
+    echo -e " -h, --help\t\t\t\tprint this help"
+    echo -e " -w, --warning <ips count>\t\twarning threshold values for IP count"
+}
+
+[[ $# -lt 1 ]] && (echo "err: <jails> argument missing"; exit 2)
+
+while [[ $# -gt 1 ]]; do
+    case "$1" in
+        -c|--critical)
+            ips_threshold_critical=$(/usr/bin/awk '{print +$1}' <(echo $2))
+            shift 1
+            ;;
+
+        -w|--warning)
+            ips_threshold_warning=$(/usr/bin/awk '{print +$1}' <(echo $2))
+            shift 1
+            ;;
+
+        -h|--help)
+            print_help
+            exit 0
+            ;;
+
+        *)
+            echo "err: failed to parse argument '$1'."
+            exit 1
+            ;;
+    esac
+    shift 1
+done
+jails=$1
+
+# Format data.
+output=''
+perf=''
+
+ips_scale=";${ips_threshold_warning};${ips_threshold_critical};0;100"
+
+# Is fail2ban service active.
+if /bin/systemctl is-active fail2ban.service 1>/dev/null 2>&1; then
+    output+="OK: fail2ban service is active\n"
+else
+    output+="NOK: fail2ban is inactive\n"
+fi
+
+# Is fail2ban running.
+if sudo /usr/bin/fail2ban-client ping 1>/dev/null 2>&1; then
+    output+="OK: fail2ban is running\n"
+    fail2ban_is_running=true
+else
+    output+="NOK: fail2ban is not running\n"
+    fail2ban_is_running=false
+fi
+
+all_jail_stats=$(sudo /usr/bin/fail2ban-client banned | tr "'" '"' | python3 -c "import collections, json, sys; banned=json.load(sys.stdin); print('\n'.join([f'{name},{len(ips)}' for jails in banned for name, ips in jails.items()]))")
+
+# IP address banned count for expected jails.
+for jail in ${jails//,/ }; do
+    if jail_stats=$(grep "$jail" <(echo "$all_jail_stats")); then
+        jail_name=$(/usr/bin/awk -F ',' '{print $1}' <(echo $jail_stats))
+        if [[ "$jail_name" == "$jail" ]]; then
+            jail_ips=$(/usr/bin/awk -F ',' '{print +$2}' <(echo $jail_stats))
+
+            status='OK'
+            [[ ${jail_ips} -ge $ips_threshold_warning ]] && status='WARNING'
+            [[ ${jail_ips} -ge $ips_threshold_critical ]] && status='CRITICAL'
+            output+="${status}: ${jail} jail hold ${jail_ips} IP address\n"
+
+            perf+="${jail_name}=${jail_ips}${ips_scale} "
+            continue
+        fi
+    fi
+    output+="NOK: ${jail} jail is missing\n"
+done
+
+# Nagios OK status.
+exit_code=0
+# Nagios WARNING status.
+grep --quiet 'WARNING:' <(echo $output) && exit_code=1
+# Nagios CRITICAL status.
+grep --quiet 'NOK:\|CRITICAL:' <(echo $output) && exit_code=2
+
+# Plugin output.
+echo "${output%'\n'}|${perf%' '}"
+exit $exit_code