diff --git a/src/freedombone-utils-firewall b/src/freedombone-utils-firewall
index 481b6158a77c68b9477315fcc9b603b5e4747fcb..3cf55736fff1a3563a1d840baaead978cff8f3d4 100755
--- a/src/freedombone-utils-firewall
+++ b/src/freedombone-utils-firewall
@@ -482,4 +482,29 @@ function firewall_drop_spoofed_packets {
     mark_completed $FUNCNAME
 }
 
+function firewall_rate_limits {
+    if [[ $(is_completed $FUNCNAME) == "1" ]]; then
+        return
+    fi
+
+    # Limit connections per source IP
+    iptables -A INPUT -p tcp -m connlimit --connlimit-above 111 -j REJECT --reject-with tcp-reset
+
+    # Limit RST packets
+    iptables -A INPUT -p tcp --tcp-flags RST RST -m limit --limit 2/s --limit-burst 2 -j ACCEPT
+    iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP
+
+    # Limit new TCP connections per second per source IP
+    iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT
+    iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP
+
+    # SSH brute-force protection
+    iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --set
+    iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 -j DROP
+
+    function_check save_firewall_settings
+    save_firewall_settings
+    mark_completed $FUNCNAME
+}
+
 # NOTE: deliberately no exit 0
diff --git a/src/freedombone-utils-setup b/src/freedombone-utils-setup
index b4778161d97776a8a63426efdedd01f3d7505f3d..63c45fb3fc06ebdedcb8add626ffada1903f545a 100755
--- a/src/freedombone-utils-setup
+++ b/src/freedombone-utils-setup
@@ -567,6 +567,9 @@ function setup_firewall {
     function_check firewall_drop_spoofed_packets
     firewall_drop_spoofed_packets
 
+    function_check firewall_rate_limits
+    firewall_rate_limits
+
     function_check configure_firewall_for_dns
     configure_firewall_for_dns