<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nirjas Jakilim</title>
    <description>The latest articles on Forem by Nirjas Jakilim (@nirzak).</description>
    <link>https://forem.com/nirzak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F734213%2F2ea59fa0-e5d7-495f-9da6-83ad66efdb31.jpeg</url>
      <title>Forem: Nirjas Jakilim</title>
      <link>https://forem.com/nirzak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nirzak"/>
    <language>en</language>
    <item>
      <title>Setting Up CrowdSec on your Linux Server: A Complete Guide</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Sat, 11 Apr 2026 18:51:27 +0000</pubDate>
      <link>https://forem.com/nirzak/setting-up-crowdsec-on-your-linux-server-a-complete-guide-14ak</link>
      <guid>https://forem.com/nirzak/setting-up-crowdsec-on-your-linux-server-a-complete-guide-14ak</guid>
      <description>&lt;p&gt;Previously, I wrote about setting up fail2ban to protect your server from malicious attacks and brute-force attempts, which works quite well. However, there is a better alternative: &lt;strong&gt;CrowdSec&lt;/strong&gt;. CrowdSec is an open-source, collaborative security engine that detects and blocks malicious behavior using shared threat intelligence. Unlike traditional fail2ban-style tools, it crowdsources attack patterns across its entire user base, which means your server benefits from bans triggered by attacks on other machines worldwide.&lt;br&gt;
This guide walks through a full production setup on the Ubuntu 22.04 LTS operating system, which should also work on other systems.&lt;/p&gt;


&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A server running Ubuntu or any other operating system&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sudo&lt;/code&gt; access&lt;/li&gt;
&lt;li&gt;nftables installed (&lt;code&gt;sudo apt install nftables -y&lt;/code&gt;) [iptables will also work. But needs separate setup for that]&lt;/li&gt;
&lt;li&gt;Grafana Prometheus for monitoring section&lt;/li&gt;
&lt;li&gt;A Telegram account (for the optional notification section)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  1. Installing CrowdSec
&lt;/h2&gt;

&lt;p&gt;CrowdSec provides an official repository script that handles APT source registration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add the CrowdSec repository&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://install.crowdsec.net | &lt;span class="nb"&gt;sudo &lt;/span&gt;bash

&lt;span class="c"&gt;# Install the agent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;crowdsec &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the service is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status crowdsec
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On first install, CrowdSec runs a detection wizard (&lt;code&gt;wizard.sh&lt;/code&gt;) that scans your running services and pre-populates the log acquisition config. You can find the log acquisition config from this location and configure it as per your use case &lt;code&gt;/etc/crowdsec/acquis.yaml&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Enrolling into the CrowdSec Security Engine
&lt;/h2&gt;

&lt;p&gt;Enrollment links your local agent to the &lt;a href="https://app.crowdsec.net" rel="noopener noreferrer"&gt;CrowdSec Console&lt;/a&gt;, giving you access to the shared blocklist network, centralized alert management and remote decision control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a free account at &lt;a href="https://app.crowdsec.net" rel="noopener noreferrer"&gt;app.crowdsec.net&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Engines → Enroll&lt;/strong&gt; and copy your enrollment key&lt;/li&gt;
&lt;li&gt;Run on your server:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli console enroll &amp;lt;YOUR_ENROLLMENT_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Restart CrowdSec:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart crowdsec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Go back to the Console and &lt;strong&gt;accept&lt;/strong&gt; the engine from the UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once accepted, your instance appears under &lt;strong&gt;Engines&lt;/strong&gt; with a green status. You can now install their blocklists from the UI and manage decisions remotely.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Installing the Firewall Bouncer
&lt;/h2&gt;

&lt;p&gt;Now that you have your security engine running, it's time to install the remediation component. The remediation component is primarily responsible for blocking threat actors. One great thing about CrowdSec is that you can choose which type of remediation component you want. For example, if you want to ban an IP from your firewall, you can use cs-firewall-bouncer. If you want to restrict the IP from your Nginx server, then you will install cs-nginx-bouncer, and there are many more options. Here, we will use the nftables-compatible cs-firewall-bouncer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;crowdsec-firewall-bouncer-nftables &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable and start it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; crowdsec-firewall-bouncer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm the bouncer registered with the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli bouncers list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Ensure the &lt;code&gt;nf_tables&lt;/code&gt; kernel module is loaded before starting the bouncer: &lt;code&gt;sudo modprobe nf_tables&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Installing Collections
&lt;/h2&gt;

&lt;p&gt;Collections bundle parsers and detection scenarios for specific services. Install the ones matching your environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Core service collections&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/nginx
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/sshd
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/mysql
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/linux

&lt;span class="c"&gt;# Optional but recommended&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/http-cve
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections &lt;span class="nb"&gt;install &lt;/span&gt;crowdsecurity/iptables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the configuration change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Reload to activate new parsers and scenarios&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload crowdsec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify what's installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli collections list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should show something like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuv77z4xv888c4182sws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuv77z4xv888c4182sws.png" alt="Crowdsec collection list example" width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; There's a lot of already developed collections by their community out there. You can search the available collections on their console app and then install it with the mentioned command.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Configuring Log Acquisition
&lt;/h2&gt;

&lt;p&gt;CrowdSec reads logs via &lt;code&gt;/etc/crowdsec/acquis.yaml&lt;/code&gt;. While the wizard generates this automatically, you should review and modify it based on your specific use cases. For example, if your Nginx logs are stored in a custom location rather than &lt;code&gt;/var/log/nginx/error.log&lt;/code&gt;, you must update the configuration accordingly. Below is a sample illustrating the structure of an acquis.yaml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/crowdsec/acquis.yaml&lt;/span&gt;

&lt;span class="na"&gt;filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/nginx/access.log&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/nginx/error.log&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# SSH auth logs&lt;/span&gt;
&lt;span class="na"&gt;filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/auth.log&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;syslog&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# MySQL error log&lt;/span&gt;
&lt;span class="na"&gt;filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/mysql/error.log&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# General syslog and kernel log&lt;/span&gt;
&lt;span class="na"&gt;filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/syslog&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/kern.log&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;syslog&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After any changes don't forget to reload crowdsec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload crowdsec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;sudo cscli metrics&lt;/code&gt; to confirm log files are being tailed. Zero parsed lines typically means a missing collection or wrong &lt;code&gt;type&lt;/code&gt; label.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Whitelisting IPs with cscli allowlist
&lt;/h2&gt;

&lt;p&gt;CrowdSec newer versions include a native allowlist command to permanently exempt IPs or CIDRs from bans. It is useful for your own infrastructure, monitoring tools or trusted partners. My recommendation is always whitelist your own IPs so that you don't get accidentally banned and blocked out of your own server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create an allowlist:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists create my_allowlist &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Trusted internal and monitoring IPs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add IPs or CIDRs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Single IP&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists add my_allowlist 192.168.1.10 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--comment&lt;/span&gt; &lt;span class="s2"&gt;"Internal monitoring"&lt;/span&gt;

&lt;span class="c"&gt;# CIDR range&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists add my_allowlist 10.0.0.0/8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--comment&lt;/span&gt; &lt;span class="s2"&gt;"Private network range"&lt;/span&gt;

&lt;span class="c"&gt;# Multiple IPs at once&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists add my_allowlist &lt;span class="se"&gt;\&lt;/span&gt;
  203.0.113.5 203.0.113.10 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--comment&lt;/span&gt; &lt;span class="s2"&gt;"Partner IPs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Manage allowlists:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists list
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists inspect my_allowlist
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists remove my_allowlist 203.0.113.5
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli allowlists delete my_allowlist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Allowlisted IPs are evaluated before any decision is applied and they will never be banned even if they trigger a scenario.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Configuring nftables as the Bouncer Backend
&lt;/h2&gt;

&lt;p&gt;Edit the bouncer config at &lt;code&gt;/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nftables&lt;/span&gt;
&lt;span class="na"&gt;update_frequency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
&lt;span class="na"&gt;log_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file&lt;/span&gt;
&lt;span class="na"&gt;log_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/log/&lt;/span&gt;
&lt;span class="na"&gt;log_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;info&lt;/span&gt;
&lt;span class="na"&gt;log_compression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;log_max_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;span class="na"&gt;log_max_backups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="na"&gt;log_max_age&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;span class="na"&gt;api_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8080/&lt;/span&gt;
&lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;BOUNCER_API_KEY&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;insecure_skip_verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;disable_ipv6&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;deny_action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DROP&lt;/span&gt;
&lt;span class="na"&gt;deny_log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;supported_decisions_types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ban&lt;/span&gt;
&lt;span class="na"&gt;blacklists_ipv4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec-blacklists&lt;/span&gt;
&lt;span class="na"&gt;blacklists_ipv6&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec6-blacklists&lt;/span&gt;
&lt;span class="na"&gt;ipset_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nethash&lt;/span&gt;

&lt;span class="c1"&gt;## nftables&lt;/span&gt;
&lt;span class="na"&gt;nftables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ipv4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;set-only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec&lt;/span&gt;
    &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec-chain&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-10&lt;/span&gt;
  &lt;span class="na"&gt;ipv6&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;set-only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec6&lt;/span&gt;
    &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crowdsec6-chain&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-10&lt;/span&gt;

&lt;span class="na"&gt;nftables_hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;input&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;forward&lt;/span&gt;

&lt;span class="c1"&gt;# packet filter&lt;/span&gt;
&lt;span class="na"&gt;pf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# an empty string disables the anchor&lt;/span&gt;
  &lt;span class="na"&gt;anchor_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bouncer API key is auto-generated on install. To retrieve or regenerate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli bouncers list

&lt;span class="c"&gt;# Regenerate if needed&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli bouncers delete crowdsec-firewall-bouncer
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli bouncers add crowdsec-firewall-bouncer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the bouncer and verify nftables rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart crowdsec-firewall-bouncer
&lt;span class="nb"&gt;sudo &lt;/span&gt;nft list ruleset | &lt;span class="nb"&gt;grep &lt;/span&gt;crowdsec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; If you're running both &lt;code&gt;iptables&lt;/code&gt; and &lt;code&gt;nftables&lt;/code&gt;, use the &lt;code&gt;iptables-nft&lt;/code&gt; backend to avoid rule conflicts: &lt;code&gt;sudo update-alternatives --set iptables /usr/sbin/iptables-nft&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Prometheus + Grafana Integration
&lt;/h2&gt;

&lt;p&gt;CrowdSec exposes a Prometheus metrics endpoint out of the box — no extra plugin needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Prometheus in CrowdSec
&lt;/h3&gt;

&lt;p&gt;Confirm or add the following in &lt;code&gt;/etc/crowdsec/config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;full&lt;/span&gt;
  &lt;span class="na"&gt;listen_addr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1&lt;/span&gt;
  &lt;span class="na"&gt;listen_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6060&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload and test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload crowdsec
curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:6060/metrics | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure Prometheus to Scrape CrowdSec
&lt;/h3&gt;

&lt;p&gt;Add a scrape job to your &lt;code&gt;prometheus.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;crowdsec'&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;localhost:6060'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload Prometheus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload prometheus
&lt;span class="c"&gt;# Or via the HTTP API if enabled:&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:9090/-/reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Import the Grafana Dashboard
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Grafana, go to &lt;strong&gt;Dashboards → Import&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use dashboard ID &lt;strong&gt;21419&lt;/strong&gt; (Crowdsec Metrics)&lt;/li&gt;
&lt;li&gt;Select your Prometheus datasource and click &lt;strong&gt;Import&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You can also import dashboards from their official github repository here: &lt;a href="https://github.com/crowdsecurity/grafana-dashboards/tree/master/dashboards_v5" rel="noopener noreferrer"&gt;Crowdsec Grafana Dashboards&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key metrics to monitor:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cs_active_decisions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current active bans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cs_alerts_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total scenarios triggered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cs_lapi_requests_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bouncer polling activity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cs_parser_hits_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Log lines processed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. Telegram Notification Integration
&lt;/h2&gt;

&lt;p&gt;CrowdSec's HTTP notification plugin can POST alerts to any webhook, including Telegram's Bot API. Alerts include inline buttons linking the offending IP to Shodan and the CrowdSec CTI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Telegram Bot
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Telegram and search for &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;/newbot&lt;/code&gt; and follow the prompts — save your &lt;strong&gt;bot token&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add the bot to your target group or channel&lt;/li&gt;
&lt;li&gt;Get the &lt;strong&gt;chat ID&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.telegram.org/bot&amp;lt;BOT_TOKEN&amp;gt;/getUpdates &lt;span class="se"&gt;\&lt;/span&gt;
  | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'"id"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Group chat IDs are &lt;strong&gt;negative integers&lt;/strong&gt; (e.g., &lt;code&gt;-123456789&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Configure the Plugin
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;/etc/crowdsec/notifications/http_tg.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Author: Nirjas Jakilim&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http_tg&lt;/span&gt;
&lt;span class="na"&gt;log_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;info&lt;/span&gt;

&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;{&lt;/span&gt;
   &lt;span class="s"&gt;"chat_id": "-YOUR_CHAT_ID",&lt;/span&gt;
   &lt;span class="s"&gt;"text": "&lt;/span&gt;
     &lt;span class="s"&gt;{{range . -}}&lt;/span&gt;
     &lt;span class="s"&gt;{{$alert := . -}}&lt;/span&gt;
     &lt;span class="s"&gt;{{range .Decisions -}}&lt;/span&gt;
     &lt;span class="s"&gt;{{if $alert.Source.Cn -}}&lt;/span&gt;
  &lt;span class="s"&gt;Scenario: {{.Scenario}}&lt;/span&gt;
  &lt;span class="s"&gt;IP: {{.Value}}&lt;/span&gt;
  &lt;span class="s"&gt;Ban Duration: {{.Duration}}&lt;/span&gt;
  &lt;span class="s"&gt;Country: {{$alert.Source.Cn}}&lt;/span&gt;
  &lt;span class="s"&gt;AS Name: {{$alert.Source.AsName}}&lt;/span&gt;
    &lt;span class="s"&gt;{{end}}&lt;/span&gt;
     &lt;span class="s"&gt;{{if not $alert.Source.Cn -}}&lt;/span&gt;
  &lt;span class="s"&gt;Scenario: {{.Scenario}}&lt;/span&gt;
  &lt;span class="s"&gt;IP: {{.Value}}&lt;/span&gt;
  &lt;span class="s"&gt;Ban Duration: {{.Duration}}&lt;/span&gt;
  &lt;span class="s"&gt;Country: Unknown&lt;/span&gt;
    &lt;span class="s"&gt;{{end}}&lt;/span&gt;
     &lt;span class="s"&gt;{{end -}}&lt;/span&gt;
     &lt;span class="s"&gt;{{end -}}&lt;/span&gt;
   &lt;span class="s"&gt;",&lt;/span&gt;
   &lt;span class="s"&gt;"reply_markup": {&lt;/span&gt;
      &lt;span class="s"&gt;"inline_keyboard": [&lt;/span&gt;
          &lt;span class="s"&gt;{{ $arrLength := len . -}}&lt;/span&gt;
          &lt;span class="s"&gt;{{ range $i, $value := . -}}&lt;/span&gt;
          &lt;span class="s"&gt;{{ $V := $value.Source.Value -}}&lt;/span&gt;
          &lt;span class="s"&gt;[&lt;/span&gt;
              &lt;span class="s"&gt;{&lt;/span&gt;
                  &lt;span class="s"&gt;"text": "See {{ $V }} on shodan.io",&lt;/span&gt;
                  &lt;span class="s"&gt;"url": "https://www.shodan.io/host/{{ $V }}"&lt;/span&gt;
              &lt;span class="s"&gt;},&lt;/span&gt;
              &lt;span class="s"&gt;{&lt;/span&gt;
                  &lt;span class="s"&gt;"text": "See {{ $V }} on crowdsec.net",&lt;/span&gt;
                  &lt;span class="s"&gt;"url": "https://app.crowdsec.net/cti/{{ $V }}"&lt;/span&gt;
              &lt;span class="s"&gt;}&lt;/span&gt;
          &lt;span class="s"&gt;]{{if lt $i ( sub $arrLength 1) }},{{end }}&lt;/span&gt;
          &lt;span class="s"&gt;{{end -}}&lt;/span&gt;
      &lt;span class="s"&gt;]&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://api.telegram.org/bot&amp;lt;BOT_TOKEN&amp;gt;/sendMessage&lt;/span&gt;
&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add Notifications in profiles.yaml
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/crowdsec/profiles.yaml&lt;/code&gt; to attach &lt;code&gt;http_tg&lt;/code&gt; to your remediation profiles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Skip re-banning IPs that already have an active decision&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;silence_ip_remediation&lt;/span&gt;
&lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Alert.Remediation == &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; &amp;amp;&amp;amp; Alert.GetScope() == "Ip" &amp;amp;&amp;amp; GetActiveDecisionsCount(Alert.GetValue()) &amp;gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="na"&gt;on_success&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;break&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Default IP ban — 500h with Telegram notification&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default_ip_remediation&lt;/span&gt;
&lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Alert.Remediation == &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; &amp;amp;&amp;amp; Alert.GetScope() == "Ip"&lt;/span&gt;
&lt;span class="na"&gt;decisions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ban&lt;/span&gt;
    &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;500h&lt;/span&gt;
&lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;http_tg&lt;/span&gt;
&lt;span class="na"&gt;on_success&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;break&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Range ban — 500h with Telegram notification&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default_range_remediation&lt;/span&gt;
&lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Alert.Remediation == &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; &amp;amp;&amp;amp; Alert.GetScope() == "Range"&lt;/span&gt;
&lt;span class="na"&gt;decisions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ban&lt;/span&gt;
    &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;500h&lt;/span&gt;
&lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;http_tg&lt;/span&gt;
&lt;span class="na"&gt;on_success&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Reload and Test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload crowdsec

&lt;span class="c"&gt;# Send a test notification&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli notifications &lt;span class="nb"&gt;test &lt;/span&gt;http_tg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the test fails, check &lt;code&gt;/var/log/crowdsec/crowdsec.log&lt;/code&gt; for plugin errors. Common issues: wrong chat ID format, bot not added to the group, or malformed JSON in the &lt;code&gt;format&lt;/code&gt; template.&lt;/p&gt;

&lt;p&gt;If everything is alright the alert notifications will be like as below&lt;/p&gt;

&lt;p&gt;!Crowdsec telegram notification example](&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ne0av5eesel0xqe4j5o8.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ne0av5eesel0xqe4j5o8.png&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying the Full Stack
&lt;/h2&gt;

&lt;p&gt;Once everything is configured, run these commands to confirm each layer is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Agent status and active decisions&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli decisions list
&lt;span class="nb"&gt;sudo &lt;/span&gt;cscli alerts list

&lt;span class="c"&gt;# Bouncer is enforcing bans&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nft list ruleset | &lt;span class="nb"&gt;grep &lt;/span&gt;crowdsec

&lt;span class="c"&gt;# Metrics endpoint alive&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:6060/metrics | &lt;span class="nb"&gt;grep &lt;/span&gt;cs_active

&lt;span class="c"&gt;# All services healthy&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status crowdsec crowdsec-firewall-bouncer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You now have a fully operational CrowdSec stack: the agent parsing logs from nginx, SSH, MySQL, and syslog, the nftables bouncer enforcing bans at the kernel level, IP allowlists protecting trusted sources, Prometheus and Grafana providing observability and Telegram delivering real-time alerts with one-click threat investigation links.&lt;/p&gt;

&lt;p&gt;Because CrowdSec is collaborative, every ban your instance issues contributes back to the shared blocklist making the network stronger for everyone.&lt;/p&gt;

</description>
      <category>crowdsec</category>
      <category>security</category>
      <category>linux</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>SSHD Hardening tricks that almost reduced 99% brute force attacks from my servers</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Mon, 30 Mar 2026 17:02:06 +0000</pubDate>
      <link>https://forem.com/nirzak/sshd-hardening-tricks-that-almost-reduced-99-brute-force-attacks-from-my-servers-48ap</link>
      <guid>https://forem.com/nirzak/sshd-hardening-tricks-that-almost-reduced-99-brute-force-attacks-from-my-servers-48ap</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1" class="crayons-story__hidden-navigation-link"&gt;Top SSHD Hardening Tricks I Use to Keep My Server Safe from Brute Force Attacks&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nirzak" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F734213%2F2ea59fa0-e5d7-495f-9da6-83ad66efdb31.jpeg" alt="nirzak profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nirzak" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Nirjas Jakilim
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Nirjas Jakilim
                
              
              &lt;div id="story-author-preview-content-3431767" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nirzak" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F734213%2F2ea59fa0-e5d7-495f-9da6-83ad66efdb31.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Nirjas Jakilim&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 30&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1" id="article-link-3431767"&gt;
          Top SSHD Hardening Tricks I Use to Keep My Server Safe from Brute Force Attacks
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sshd"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sshd&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ssh"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ssh&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/linux"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;linux&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>sshd</category>
      <category>security</category>
      <category>ssh</category>
      <category>linux</category>
    </item>
    <item>
      <title>Top SSHD Hardening Tricks I Use to Keep My Server Safe from Brute Force Attacks</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Mon, 30 Mar 2026 16:57:25 +0000</pubDate>
      <link>https://forem.com/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1</link>
      <guid>https://forem.com/nirzak/top-sshd-hardening-tricks-i-use-to-keep-my-server-safe-from-brute-force-attacks-54j1</guid>
      <description>&lt;p&gt;&lt;em&gt;The moment you expose your server to the internet with a public IP, if you check the &lt;code&gt;/var/log/auth.log&lt;/code&gt; file, you will be in a complete panic within a moment. Numerous bots and attackers will start brute-forcing your server to gain access. This is very alarming if your server is not protected with proper SSHD hardening, as attackers might compromise your system at any moment. Fortunately, there is an exact sshd_config hardening process you can apply to every new server to make brute-force attacks a non-issue. Here are nine straightforward steps to lock down your server.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Always keep a backup SSH window open for your server. Never forget to test the configuration with the sshd -t command before applying changes to avoid getting locked out.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Change the Default Port
&lt;/h2&gt;

&lt;p&gt;The single biggest drop in noise. Automated scanners and attackers almost exclusively target port 22. So, if you move to a high, non-standard port that will eliminate almost ~99% of bot traffic overnight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/ssh/sshd_config&lt;/span&gt;
&lt;span class="k"&gt;Port&lt;/span&gt; &lt;span class="m"&gt;2222&lt;/span&gt; &lt;span class="c1"&gt;# Pick anything from 1024–65535&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to update your firewall rules and use &lt;code&gt;ssh -p &amp;lt;your_port&amp;gt; user@host&lt;/code&gt; going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Disable Root Login
&lt;/h2&gt;

&lt;p&gt;Never allow direct root SSH access. That's like opening your server's main door to the attackers. If an attacker gets in, they can do almost anything on your servers. You may want them to at least need to escalate privileges separately. Always log in as a regular user and then use sudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;PermitRootLogin&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you still really need direct root ssh login then you can use the config mentioned below to strictly enforce key based login for the root user&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;PermitRootLogin&lt;/span&gt; prohibit-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Always confirm you have sudo access before disabling root login.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Enforce Key-Based Authentication (No Passwords)
&lt;/h2&gt;

&lt;p&gt;Password auth is a significant attack surface. So, you should kill it entirely. SSH keys are the minimum bar. Then you can also pair with a strong passphrase on the key itself. You can apply the following settings to enforce strict key based access on your server and restrict password based logins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;PasswordAuthentication&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;PubkeyAuthentication&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;span class="k"&gt;AuthenticationMethods&lt;/span&gt; publickey
&lt;span class="k"&gt;ChallengeResponseAuthentication&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;UsePAM&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;PasswordAuthentication no&lt;/code&gt; completely disable password based authentication&lt;br&gt;
&lt;code&gt;PubkeyAuthentication yes&lt;/code&gt; only allowed key based authentication&lt;br&gt;
&lt;code&gt;AuthenticationMethods publickey&lt;/code&gt; enforce key based authentication method only&lt;br&gt;
&lt;code&gt;ChallengeResponseAuthentication no&lt;/code&gt; disables keyboard interactive authentication&lt;br&gt;
&lt;code&gt;UsePAM yes&lt;/code&gt; enables pluggable authentication module&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Restrict Which Users Can SSH
&lt;/h2&gt;

&lt;p&gt;Whitelist the exact users (or groups) that need SSH access. It can significantly reduce the attack surface since only users you explicitly allow can now login. Everyone else is denied at the sshd level even if they have valid credentials.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;AllowUsers&lt;/span&gt; &amp;lt;your_username_here&amp;gt; &amp;lt;anotheruser&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or by group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;AllowGroups&lt;/span&gt; sshusers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use the AllowGroups directive then you can add any user to the sshusers group&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; sshusers &amp;lt;youruser&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Limit Authentication Attempts per Connection
&lt;/h2&gt;

&lt;p&gt;Reduce how many tries an attacker gets before the connection is dropped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;MaxAuthTries&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;LoginGraceTime&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="k"&gt;MaxStartups&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;:30:60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;MaxAuthTries 3&lt;/code&gt; will drop the connection after the failure attempt count reach to 3&lt;br&gt;
&lt;code&gt;LoginGraceTime 20&lt;/code&gt; will disconnect if not authenticated within 20 seconds&lt;br&gt;
&lt;code&gt;MaxStartups&lt;/code&gt; will throttle unauthenticated connection attempts&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Disable Features You Don't Use
&lt;/h2&gt;

&lt;p&gt;Every enabled feature is a potential attack vector. Disable anything you don't actively need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;X11Forwarding&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;AllowTcpForwarding&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt; &lt;span class="c1"&gt;# unless you need SSH tunneling&lt;/span&gt;
&lt;span class="k"&gt;AllowAgentForwarding&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;PermitTunnel&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;GatewayPorts&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;PermitEmptyPassword&lt;/span&gt; &lt;span class="no"&gt;no&lt;/span&gt;
&lt;span class="k"&gt;IgnoreRhosts&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Enforce Strong Ciphers and Key Exchange Algorithms
&lt;/h2&gt;

&lt;p&gt;Strip out legacy ciphers. Attackers can downgrade your connection to weak crypto if you leave old algorithms enabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;KexAlgorithms&lt;/span&gt; curve25519-sha256,diffie-hellman-group16-sha512
&lt;span class="k"&gt;Ciphers&lt;/span&gt; aes256-gcm@openssh.com,chacha20-poly1305@openssh.com
&lt;span class="k"&gt;MACs&lt;/span&gt; hmac-sha2–256-etm@openssh.com,hmac-sha2–512-etm@openssh.com
&lt;span class="k"&gt;HostKeyAlgorithms&lt;/span&gt; ssh-ed25519,rsa-sha2–512
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Use tools like fail2ban or crowdsec
&lt;/h2&gt;

&lt;p&gt;Even with all the above, bots will keep trying. fail2ban watches your auth logs and auto-bans IPs after repeated failures. Pair it with the custom port from tip #1.&lt;br&gt;
If you need to setup fail2ban then I have covered it in a separate article here: &lt;a href="https://dev.to/nirzak/guide-to-secure-your-self-hosted-stacks-like-nginx-ssh-vaultwarden-with-fail2ban-4k4c"&gt;Guide to Secure Your Self-Hosted Stacks like Nginx, SSH, &amp;amp; Vaultwarden with Fail2ban&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/fail2ban/jail.local
&lt;/span&gt;&lt;span class="nn"&gt;[sshd]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2222    # Mention your ssh port here&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sshd&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(sshd_log)s&lt;/span&gt;
&lt;span class="py"&gt;backend&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(sshd_backend)s&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3600 # ban for 1 hour. Ypu can increase it&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;About crowdsec I will cover it on a separate article.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Restrict SSH Access at the Firewall Level
&lt;/h2&gt;

&lt;p&gt;If you connect from a static IP or a VPN, whitelist that IP in your firewall. This is the hardest gate of all, the port never even responds to unauthorized sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# UFW example&lt;/span&gt;
ufw allow from 203.0.113.10 to any port 2222

&lt;span class="c"&gt;# iptables example&lt;/span&gt;
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp - dport 2222 &lt;span class="nt"&gt;-s&lt;/span&gt; 203.0.113.10 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp - dport 2222 &lt;span class="nt"&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Apply the Changes
&lt;/h2&gt;

&lt;p&gt;Always test your config before reloading because one syntax error locks you out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sshd &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the above command didn't show any error then run the following command to reload your sshd config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;None of these tricks is a silver bullet on its own, but defense in depth is the main goal. My standard stack for any new VPS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move SSH off port 22&lt;/li&gt;
&lt;li&gt;Keys only, no passwords&lt;/li&gt;
&lt;li&gt;Whitelist users&lt;/li&gt;
&lt;li&gt;fail2ban or crowdsec watching auth logs&lt;/li&gt;
&lt;li&gt;Firewall IP allowlist if feasible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all of this in place, brute-force attacks become background noise that you never have to think about again.&lt;/p&gt;

</description>
      <category>sshd</category>
      <category>security</category>
      <category>ssh</category>
      <category>linux</category>
    </item>
    <item>
      <title>Configuring a Cluster File System on OCI using OCFS2</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Sat, 28 Mar 2026 18:23:13 +0000</pubDate>
      <link>https://forem.com/nirzak/configuring-a-cluster-file-system-on-oci-using-ocfs2-117h</link>
      <guid>https://forem.com/nirzak/configuring-a-cluster-file-system-on-oci-using-ocfs2-117h</guid>
      <description>&lt;p&gt;Setting up a shared file system across multiple virtual machines in the cloud can be tricky, but Oracle Cluster File System Version 2 (OCFS2) makes it straightforward. If you are running instances on Oracle Cloud Infrastructure (OCI) and need multiple VMs to read and write to the same block volume simultaneously, this guide will walk you through the process on Ubuntu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin the configuration, ensure you have the following infrastructure in place:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At least Two Ubuntu VMs provisioned:&lt;/strong&gt; For this guide, we will use &lt;strong&gt;server1 (IP: 10.0.1.85)&lt;/strong&gt; and &lt;strong&gt;server2 (IP: 10.0.1.235)&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;A Block Volume&lt;/strong&gt; created and attached to both VMs.&lt;br&gt;
&lt;strong&gt;The access type&lt;/strong&gt; for the block volume must be set to &lt;strong&gt;Read/write - shareable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once these resources are ready, you can proceed to configure the cluster file system.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Configure Security Rules
&lt;/h2&gt;

&lt;p&gt;OCFS2 nodes need to communicate with each other over specific ports. You must update your OCI Virtual Cloud Network (VCN) security lists to allow internal traffic.&lt;/p&gt;

&lt;p&gt;Allow TCP communication on &lt;strong&gt;ports 7777 and 3260&lt;/strong&gt;. Add the following ingress rules for your private subnet (&lt;strong&gt;e.g., 10.0.1.0/24&lt;/strong&gt;):&lt;/p&gt;

&lt;p&gt;Source: 10.0.1.0/24 | IP Protocol: TCP | Destination Port: 7777&lt;br&gt;
Source: 10.0.1.0/24 | IP Protocol: TCP | Destination Port: 3260&lt;/p&gt;

&lt;p&gt;To verify the connectivity between the VMs, run the following netcat commands from one VM to the other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nc &lt;span class="nt"&gt;-vz&lt;/span&gt; 10.0.1.85 3260&lt;span class="p"&gt;;&lt;/span&gt;
nc &lt;span class="nt"&gt;-vz&lt;/span&gt; 10.0.1.85 7777
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your security rules are correct, the connection will show as "&lt;strong&gt;refused&lt;/strong&gt;" because the cluster services are not running yet. This is expected. Do the same thing from the other VM with your &lt;strong&gt;server2&lt;/strong&gt; ip. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install OCFS2 Packages
&lt;/h2&gt;

&lt;p&gt;Log into both VMs and install the necessary OCFS2 tools. Run the following command on both machines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ocfs2-tools-dev ocfs2-tools &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Define the Cluster
&lt;/h2&gt;

&lt;p&gt;Next, we need to create the cluster definition using the o2cb utility. This will generate the &lt;code&gt;/etc/ocfs2/cluster.conf&lt;/code&gt; file if it doesn't already exist.&lt;/p&gt;

&lt;p&gt;Run the following command on both VMs to create a cluster named ociocfs2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb add-cluster ociocfs2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, add your nodes to the cluster. Run these commands on both VMs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb add-node ociocfs2 server1 &lt;span class="nt"&gt;--ip&lt;/span&gt; 10.0.1.85&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb add-node ociocfs2 server2 &lt;span class="nt"&gt;--ip&lt;/span&gt; 10.0.1.235
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the configuration by checking the .conf file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cat&lt;/span&gt; /etc/ocfs2/cluster.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should list your cluster name, the heartbeat mode, and the details for both nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ociocfs2&lt;/span&gt;
        &lt;span class="py"&gt;heartbeat_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
        &lt;span class="py"&gt;node_count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2&lt;/span&gt;

&lt;span class="py"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="py"&gt;cluster&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ociocfs2&lt;/span&gt;
        &lt;span class="py"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0&lt;/span&gt;
        &lt;span class="py"&gt;ip_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;7777&lt;/span&gt;
        &lt;span class="py"&gt;ip_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10.0.1.85&lt;/span&gt;
        &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;server1&lt;/span&gt;

&lt;span class="py"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="py"&gt;cluster&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ociocfs2&lt;/span&gt;
        &lt;span class="py"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
        &lt;span class="py"&gt;ip_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;7777&lt;/span&gt;
        &lt;span class="py"&gt;ip_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10.0.1.235&lt;/span&gt;
        &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;server2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Attach the Block Volume via iSCSI
&lt;/h2&gt;

&lt;p&gt;You need to run the iSCSI commands provided in your OCI console to attach the block volume at the OS level. To get the commands, go to you cloud console's storage&amp;gt;block volume and then click on your block volume name. There's on the attached instances click on the 3 dot menu of your each instance's section. You can get there the attach and detach commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1uutqb9yk71oe6ietei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1uutqb9yk71oe6ietei.png" alt="iSCSI command option page" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On server1:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-o&lt;/span&gt; new &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-p&lt;/span&gt; 169.254.2.2:3260&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-o&lt;/span&gt; update &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-n&lt;/span&gt; node.startup &lt;span class="nt"&gt;-v&lt;/span&gt; automatic&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-p&lt;/span&gt; 169.254.2.2:3260 &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;On server2:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-o&lt;/span&gt; new &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-p&lt;/span&gt; 169.254.2.3:3260&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-o&lt;/span&gt; update &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-n&lt;/span&gt; node.startup &lt;span class="nt"&gt;-v&lt;/span&gt; automatic&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iscsiadm &lt;span class="nt"&gt;-m&lt;/span&gt; node &lt;span class="nt"&gt;-T&lt;/span&gt; iqn.2015-12.com.oracleiaas:5f2a1b82-9c40-4e1a-8b3d-72f6a5b9c1e4 &lt;span class="nt"&gt;-p&lt;/span&gt; 169.254.2.3:3260 &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once attached, identify the device path of your new volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fdisk &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for a pattern like &lt;code&gt;/dev/sdb&lt;/code&gt; whose size exactly match your created block volume's size. That should be your target device. For the remainder of this guide, we will assume the device is &lt;code&gt;/dev/sdb&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Format and Sync the Partition
&lt;/h2&gt;

&lt;p&gt;Start the cluster services before creating the partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start ocfs2&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start o2cb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, format the partition on only one machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mkfs.ocfs2 &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"ocfs2"&lt;/span&gt; /dev/sdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize the superblock, format the journals, and establish the cluster stack. Once it says mkfs.ocfs2 successful, the formatting is complete.&lt;/p&gt;

&lt;p&gt;To ensure the partition table is updated across your environment, run the following sync command on both VMs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;blockdev &lt;span class="nt"&gt;--rereadpt&lt;/span&gt; /dev/sdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Final Configuration and Mounting
&lt;/h2&gt;

&lt;p&gt;Reconfigure the cluster tools on both VMs by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg-reconfigure ocfs2-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, provide the exact cluster name you defined earlier (ociocfs2).&lt;br&gt;
To ensure the drive mounts automatically on boot, add the following line to your &lt;code&gt;/etc/fstab&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;/&lt;span class="n"&gt;dev&lt;/span&gt;/&lt;span class="n"&gt;sdb&lt;/span&gt; /&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;ocfs2&lt;/span&gt; &lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="n"&gt;netdev&lt;/span&gt;,&lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to configure the kernel for cluster operation so the changes persist across reboots. Add these entries to your &lt;code&gt;/etc/sysctl.conf&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Define panic and panic_on_oops for cluster operation 
&lt;/span&gt;&lt;span class="py"&gt;kernel.panic&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;
&lt;span class="py"&gt;kernel.panic_on_oops&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure the /data target directory exists on both VMs. Then, run the mount command on only one node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is configured correctly, the volume should now be mounted on both nodes automatically.&lt;br&gt;
You can verify the mount point on your instances using df -hT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;nirzak@server1:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-hT&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;data
&lt;span class="go"&gt;/dev/sdb      ocfs2  106G  2.2G  104G   3% /data

&lt;/span&gt;&lt;span class="gp"&gt;nirzak@server2:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-hT&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; /data
&lt;span class="go"&gt;/dev/sdb      ocfs2  106G  2.2G  104G   3% /data
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting &amp;amp; Expanding the Cluster
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Module Errors:&lt;/strong&gt; If you encounter a module error during setup, you may need to install the Oracle-specific Linux modules. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;linux-modules-extra-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Adding New Nodes:&lt;/strong&gt; If you need to make changes to your nodes or add new ones to the cluster configuration later, you must unregister and re-register the cluster using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb unregister-cluster &amp;lt;cluster_name&amp;gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb register-cluster &amp;lt;cluster_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart both services&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart ocfs2 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart o2cb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After restarting the services, you can mount the file system to the new node with:&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount.ocfs2 /dev/sdb /data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to replace /dev/sdb with your devices's path and /data with your mountpoint's path. Your cluster file system should now be online. Try to copy file on one server's directory and check if it appears on the second server or not. If it appears yourc cluster should be working fine.&lt;/p&gt;

</description>
      <category>oci</category>
      <category>cluster</category>
      <category>filesystem</category>
      <category>ocfs2</category>
    </item>
    <item>
      <title>Guide to Secure Your Self-Hosted Stacks like Nginx, SSH, &amp; Vaultwarden with Fail2ban</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Thu, 26 Mar 2026 18:50:07 +0000</pubDate>
      <link>https://forem.com/nirzak/guide-to-secure-your-self-hosted-stacks-like-nginx-ssh-vaultwarden-with-fail2ban-4k4c</link>
      <guid>https://forem.com/nirzak/guide-to-secure-your-self-hosted-stacks-like-nginx-ssh-vaultwarden-with-fail2ban-4k4c</guid>
      <description>&lt;p&gt;If you are self-hosting services and expose them to public interfaces then you already know the anxiety of watching your server logs. The moment you expose port 22 (SSH) or 443 (HTTPS) to the internet, botnets and automated scripts begin knocking on your door. Whether they are brute-forcing your SSH credentials, probing Nginx for vulnerabilities, or trying to break into your Vaultwarden password manager, the noise is endless.&lt;br&gt;
You can't sit there and manually block IPs all day. You need an automated bouncer.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Fail2ban&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Fail2ban is an intrusion prevention software framework that protects computer servers from brute-force attacks. It works by scanning log files (like &lt;code&gt;/var/log/auth.log&lt;/code&gt; or &lt;code&gt;Nginx access logs&lt;/code&gt;) and dynamically updating your firewall rules to ban IPs that show malicious signs.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through setting up a robust Fail2ban configuration tailored for a modern self-hosted stack featuring SSH, Nginx, and Vaultwarden.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Installation
&lt;/h2&gt;

&lt;p&gt;First, let's get Fail2ban installed. On a Debian/Ubuntu-based system, you can install it via apt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fail2ban
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Never edit the default &lt;code&gt;/etc/fail2ban/jail.conf&lt;/code&gt; file directly. Package updates will overwrite it. Instead, we create a .local file, which Fail2ban reads to override the defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Defining the Jails (jail.local)
&lt;/h2&gt;

&lt;p&gt;A "jail" in Fail2ban is essentially a rule. It tells the service which log file to watch, which filter (regex) to use, and what the punishment should be.&lt;br&gt;
Create a new file at &lt;code&gt;/etc/fail2ban/jail.local&lt;/code&gt; and paste in the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[sshd]&lt;/span&gt;
&lt;span class="c"&gt;# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
&lt;/span&gt;&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ssh&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sshd&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(sshd_log)s&lt;/span&gt;
&lt;span class="py"&gt;backend&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(sshd_backend)s&lt;/span&gt;

&lt;span class="nn"&gt;[vaultwarden]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;80,443,8081&lt;/span&gt;
&lt;span class="py"&gt;backend&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;pyinotify&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;vaultwarden&lt;/span&gt;
&lt;span class="py"&gt;banaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(banaction_allports)s&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/opt/vaultwarden/vw-logs/access.log&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;

&lt;span class="nn"&gt;[nginx-http-auth]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;http,https&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(nginx_error_log)s&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;nginx-http-auth&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;

&lt;span class="nn"&gt;[nginx-bad-status]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;http,https&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(nginx_access_log)s&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;nginx-bad-status&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;15&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10w&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;

&lt;span class="nn"&gt;[nginx-botsearch]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;http,https&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(nginx_error_log)s&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;nginx-botsearch&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2&lt;/span&gt;

&lt;span class="nn"&gt;[recidive]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/var/log/fail2ban.log&lt;/span&gt;
&lt;span class="py"&gt;banaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(banaction_allports)s&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;4w&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Don't forget to change the vaultwarden logpath &lt;code&gt;/opt/vaultwarden/vw-logs/access.log&lt;/code&gt; according to your server's log path. &lt;/p&gt;

&lt;p&gt;What's happening here?&lt;br&gt;
&lt;strong&gt;[sshd]:&lt;/strong&gt; The standard SSH protection. We are keeping it enabled to prevent basic brute-force ssh attacks.&lt;br&gt;
&lt;strong&gt;[vaultwarden]:&lt;/strong&gt; Protects our password manager. It watches all relevant web ports and uses banaction_allports to completely lock out an offending IP across all services. If someone fails a login 3 times in 10 minutes, they are banned for an hour.&lt;br&gt;
&lt;strong&gt;[nginx-*]:&lt;/strong&gt; These jails protect the web server. They handle failed HTTP authentications, aggressive bot searches and excessive "bad" HTTP status codes (like 404s or 403s).&lt;br&gt;
&lt;strong&gt;[recidive]:&lt;/strong&gt; The ultimate ban-hammer. This jail actually monitors Fail2ban's own log file. If an IP gets banned multiple times by other jails within a day, the recidive jail steps in and slaps them with a massive 4-week ban.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Creating Custom Filters
&lt;/h2&gt;

&lt;p&gt;Jails rely on filters to know what a "failed" attempt looks like. While Fail2ban comes with default filters for SSH and basic Nginx auth, we need to create custom filters for our specific Vaultwarden setup and our Nginx bad-status rules.&lt;br&gt;
Filters are stored in /etc/fail2ban/filter.d/.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Vaultwarden Filter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a file at /etc/fail2ban/filter.d/vaultwarden.local:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[INCLUDES]&lt;/span&gt;
&lt;span class="py"&gt;before&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;common.conf&lt;/span&gt;

&lt;span class="nn"&gt;[Definition]&lt;/span&gt;
&lt;span class="py"&gt;failregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;^.*?Username or password is incorrect&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt; &lt;span class="s"&gt;Try again&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt; &lt;span class="s"&gt;IP: &amp;lt;ADDR&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt; &lt;span class="s"&gt;Username:.*$&lt;/span&gt;
&lt;span class="py"&gt;ignoreregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple regex specifically targets the exact string Vaultwarden outputs to its log file when a login fails, capturing the offender's IP address ().&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Nginx Bad Status Filter&lt;/strong&gt;&lt;br&gt;
Create a file at /etc/fail2ban/filter.d/nginx-bad-status.conf:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Definition]&lt;/span&gt;
&lt;span class="c"&gt;# Match standard log format - handles both normal HTTP requests and malformed requests (hex)
&lt;/span&gt;&lt;span class="py"&gt;failregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;^&amp;lt;HOST&amp;gt; .* "&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s"&gt;+ [^"]*" (?:400|401|403|404|405|444) &lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s"&gt;+ ".*" ".*"$&lt;/span&gt;
            &lt;span class="err"&gt;^&amp;lt;HOST&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;.*&lt;/span&gt; &lt;span class="err"&gt;".*"&lt;/span&gt; &lt;span class="err"&gt;(?:400|401|403|404|405|444)&lt;/span&gt; &lt;span class="err"&gt;\d+&lt;/span&gt; &lt;span class="err"&gt;".*"&lt;/span&gt; &lt;span class="err"&gt;".*"$&lt;/span&gt;

&lt;span class="c"&gt;# Ignore common legitimate 404s
&lt;/span&gt;&lt;span class="py"&gt;ignoreregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;^&amp;lt;HOST&amp;gt; .* "GET (?:/favicon&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s"&gt;ico|/robots&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s"&gt;txt|/sitemap&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s"&gt;xml).* 404 &lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s"&gt;+ ".*" ".*"$&lt;/span&gt;

&lt;span class="c"&gt;# Define the timestamp pattern in your logs
&lt;/span&gt;&lt;span class="py"&gt;datepattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%%d/%%b/%%Y:%%H:%%M:%%S %%z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an incredibly useful filter. Scanners constantly hit servers with malformed requests or search for hidden directories, generating 4xx errors. This catches them while safely ignoring harmless requests for missing favicons or robots.txt files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Start the Engine
&lt;/h2&gt;

&lt;p&gt;With your configurations and filters in place, it's time to start Fail2ban and let it do its job.&lt;/p&gt;

&lt;p&gt;Restart the service to apply the new configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the status of your jails at any time using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the details of a specific jail (like who is currently banned):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status vaultwarden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Fail2ban is a lightweight, incredibly effective tool for keeping the noise out of your server. By combining service-specific jails like Vaultwarden with broad-stroke protections like Nginx bad-status and the long-term recidive ban, you drastically reduce the attack surface of your self-hosted infrastructure.&lt;br&gt;
Set it, forget it and enjoy the peace of mind. There's also another great tool to use as a complete firewall solution for your servers and that is crowdsec. I will write a separate guideline for that one later.&lt;/p&gt;

</description>
      <category>fail2ban</category>
      <category>nginx</category>
      <category>vaultwarden</category>
      <category>sshd</category>
    </item>
    <item>
      <title>Hardening Nginx: A Practical Guide to Modular Security Configuration</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Thu, 26 Mar 2026 17:41:35 +0000</pubDate>
      <link>https://forem.com/nirzak/hardening-nginx-a-practical-guide-to-modular-security-configuration-4bno</link>
      <guid>https://forem.com/nirzak/hardening-nginx-a-practical-guide-to-modular-security-configuration-4bno</guid>
      <description>&lt;p&gt;Out of the box, Nginx is incredibly fast and efficient but it isn't inherently secure against modern automated attacks like scanners, scraping bots and most sophisticated brute force attacks. Over time, I've set up a modular approach to hardening my Nginx setups. By splitting the security configurations into multiple logical files, it becomes much easier later to maintain, audit, and apply them across multiple virtual hosts.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk you through the essential configurations that will significantly improve your server's security. Please note before proceeding to the main article. You will need to install &lt;strong&gt;nginx-module-headers-more&lt;/strong&gt; module for the &lt;strong&gt;more_set_headers&lt;/strong&gt; directive to work. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Global Security Settings
&lt;/h2&gt;

&lt;p&gt;This configurations will cover server-wide settings, masking the server identity and filtering out malicious traffic before it even reaches your application.&lt;br&gt;
By leveraging Nginx's map module, we can identify path traversal attempts, unauthorized bot scanners, and cloud metadata SSRF attempts efficiently without cluttering our server blocks with heavy conditional arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hide Nginx version&lt;/span&gt;
&lt;span class="k"&gt;server_tokens&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Mask the server name (Note: requires the headers-more-nginx-module)&lt;/span&gt;
&lt;span class="k"&gt;more_set_headers&lt;/span&gt; &lt;span class="s"&gt;"Server:&lt;/span&gt; &lt;span class="s"&gt;AnyNameHere"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Identify sesitive paths URIs&lt;/span&gt;
&lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="nv"&gt;$request_uri&lt;/span&gt; &lt;span class="nv"&gt;$bad_request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*wp-admin"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:phpunit|phpinfo|phpmyadmin|php-?my-?admin|administrator|wp|wordpress)"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:/&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.env|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.git|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.svn|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.hg|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.DS_Store|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.idea|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.htaccess|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.htpasswd)"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:etc/passwd|proc|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;/\/&lt;/span&gt;&lt;span class="s"&gt;)+"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# Path traversal attempts (e.g., ../../etc/passwd)&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;./|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;x5c)"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# Cloud Metadata SSRF attempts&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:169&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.254&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.169&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.254)"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# Block direct access to common script/backup extensions remove it if you actually want to host this extension files on your server&lt;/span&gt;
    &lt;span class="kn"&gt;"~*&lt;/span&gt;&lt;span class="s"&gt;(?:&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.sh|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.bash|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.bak|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.sql|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.tar|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.gz|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.zip)&lt;/span&gt;$&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Identify malicious automated scanners and bots&lt;/span&gt;
&lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="nv"&gt;$http_user_agent&lt;/span&gt; &lt;span class="nv"&gt;$bad_user_agent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*havij|nikto|scan|loader|fetch|acunetix|sonic|nessus|sqlmap|zgrab|masscan|nmap|dirb|gobuster|shodan|censys|wpscan"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Combine the conditions&lt;/span&gt;
&lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bad_request$bad_user_agent&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;$is_bad_request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;"~*1"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Global rate limiting settings for DDos Protection. Change the limits according to your needs&lt;/span&gt;
&lt;span class="k"&gt;limit_req_zone&lt;/span&gt; &lt;span class="nv"&gt;$binary_remote_addr&lt;/span&gt; &lt;span class="s"&gt;zone=ratelimit:10m&lt;/span&gt; &lt;span class="s"&gt;rate=20r/s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to apply it:&lt;/strong&gt; Save the above configuration as security-global.conf file inside &lt;strong&gt;/etc/nginx/snippets&lt;/strong&gt; directory. Include this file inside your main &lt;code&gt;http {}&lt;/code&gt; block in nginx.conf. Like as below,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;include /etc/nginx/snippets/security-global.conf;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, to actually drop the malicious traffic, add this simple check inside your &lt;code&gt;server {}&lt;/code&gt; blocks of your main nginx configuration or on any blocks where you want to apply them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$is_bad_request&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# Closes the connection immediately without a response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To apply the rate limiting setting add the following line on any of your &lt;code&gt;server {}&lt;/code&gt; block of the main nginx configuration,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;limit_req zone=ratelimit burst=20 nodelay;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Location-Specific Rules
&lt;/h2&gt;

&lt;p&gt;Follow this section only if you want to restrict all the hidden files from being served through nginx cause they can be accidentally end up in your web root. Also, Text editors often leave backup files ending in &lt;code&gt;~&lt;/code&gt; and version control systems leave hidden directories like &lt;code&gt;.git&lt;/code&gt;. This file ensures they are never served to the public.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Deny access to all hidden files and directories (starting with a dot)&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Deny access to temporary editor files&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;~$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to apply it:&lt;/strong&gt;&lt;br&gt;
Save the above code block as &lt;strong&gt;security-location.conf&lt;/strong&gt; file inside your &lt;strong&gt;/etc/nginx/snippets&lt;/strong&gt; directory.&lt;br&gt;
Then include the file inside your &lt;code&gt;server {}&lt;/code&gt; block like below,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;include /etc/nginx/snippets/security-location.conf;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;access_log off&lt;/code&gt; and &lt;code&gt;log_not_found off&lt;/code&gt; can prevent your access log from being spammed. but still if you want them on your access log for security purposes then you can set it as &lt;code&gt;access_log on&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. HTTP Security Headers
&lt;/h2&gt;

&lt;p&gt;This is the most crucial part. Injecting the right HTTP headers protects your users from Cross-Site Scripting (XSS), clickjacking, and MIME-type sniffing or various attacks. It reduces attack surfaces greatly. I have covered all the most important security headers except the content security policy header. Since that header need to be configured according to your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Prevent clickjacking by restricting who can embed your site in an iframe&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Force the browser's native XSS filter&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;mode=block"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Prevent MIME-sniffing (forces the browser to respect the declared content type)&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Control how much referrer information is passed to external sites&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Referrer-Policy&lt;/span&gt; &lt;span class="s"&gt;"same-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Restrict access to device hardware (camera, microphone, location)&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Permissions-Policy&lt;/span&gt; &lt;span class="s"&gt;"geolocation=(),&lt;/span&gt; &lt;span class="s"&gt;microphone=(),&lt;/span&gt; &lt;span class="s"&gt;camera=()"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Enforce HTTPS connections for a full year, including subdomains&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=31536000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;includeSubDomains&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;preload"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to apply it:&lt;/strong&gt;&lt;br&gt;
Save the file as &lt;strong&gt;/etc/nginx/snippets/security-headers.conf&lt;/strong&gt; file. You can then include this file in your &lt;code&gt;http {}&lt;/code&gt;, &lt;code&gt;server {}&lt;/code&gt;, or even specific &lt;code&gt;location {}&lt;/code&gt; blocks depending on which application you will need to apply those headers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;By splitting your security configurations into security-global.conf, security-location.conf and security-headers.conf, you can keep your main site configurations incredibly clean. Your typical virtual host file now only needs three simple include statements to achieve a robust baseline of security.&lt;br&gt;
Note: Always remember to test your configuration before reloading the web server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Security is layered. While Nginx hardeing won't fix vulnerable application code but dropping malicious traffic at the edge saves your backend resources and mitigates entire classes of common automated attacks.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>security</category>
      <category>nginxhardening</category>
    </item>
    <item>
      <title>How one line of Rust code and a missing graceful handling mechanism took down almost 25% of Internet traffic</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Wed, 19 Nov 2025 19:11:53 +0000</pubDate>
      <link>https://forem.com/nirzak/how-one-line-of-rust-code-and-a-missing-graceful-handling-mechanism-took-down-almost-25-of-pg0</link>
      <guid>https://forem.com/nirzak/how-one-line-of-rust-code-and-a-missing-graceful-handling-mechanism-took-down-almost-25-of-pg0</guid>
      <description>&lt;p&gt;Cloudflare as usual, published a detailed post-mortem on their site explaining about the root cause of November 18 outage and it was was related to their Bot Management module. Yes, the same module responsible for those CAPTCHA style checks we see whenever we visit a Cloudflare protected site. That’s why many users were seeing bot challenge errors on ChatGPT yesterday.&lt;br&gt;
So, how does it work? Cloudflare runs a query to extract specific features into a feature file, which is then fed into the Bot Management module. The module uses those feature sets with machine learning models to generate the bot score. Based on that score, it decides whether a request is legitimate or from a bot. Since bot behavior changes rapidly, Cloudflare runs this feature extraction query every few minutes to keep the system updated.&lt;br&gt;
Now, what actually went wrong?&lt;br&gt;
A single line of Rust code ended up changing the behavior of the underlying ClickHouse query that generates the feature file. As a result, the file began containing a massive number of duplicate feature rows, effectively doubling its size. This oversized feature file was then fed into the bot management system, which had a strict maximum size limit. According to cloudflare, the limit is set to 200, well above than their current use of ~60 features. But that oversized file contained more than 200 features. Since the file exceeded that limit, and Cloudflare didn’t implement any graceful handling for this scenario, the software panicked and triggered yesterday’s outage. &lt;br&gt;
The interesting part is not just that there was no graceful handling, but also that there was no fallback logic. Ideally, when encountering a malformed or suspicious feature file with duplicated entries, the system could have logged a warning, discarded the bad file, and continued using the previous valid one. But none of that was implemented. It was simply an unwrap() followed by a panic.&lt;/p&gt;

&lt;p&gt;The code portion that was the source of that unhandled error was shared by cloudflare&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k7m0ifsm8d210665rbt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k7m0ifsm8d210665rbt.png" alt=" " width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This whole incident shows us how important it is to handle even the smallest edge cases in our code, because their impact can be far greater than we expect.&lt;br&gt;
Thanks for reading.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Monitoring Hazelcast Metrics using JMX exporter</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Sat, 19 Jul 2025 17:24:32 +0000</pubDate>
      <link>https://forem.com/nirzak/monitoring-hazelcast-metrics-using-jmx-exporter-40j8</link>
      <guid>https://forem.com/nirzak/monitoring-hazelcast-metrics-using-jmx-exporter-40j8</guid>
      <description>&lt;p&gt;As distributed systems become more complex, monitoring becomes crucial for maintaining application performance and reliability. If you're using Hazelcast as your in-memory data grid, you'll want to keep a close eye on its performance metrics. Today, I'll walk you through setting up JMX exporter to monitor Hazelcast metrics effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Monitor Hazelcast Metrics?
&lt;/h2&gt;

&lt;p&gt;Before diving into the setup, let's understand why monitoring Hazelcast is essential. Hazelcast provides valuable insights into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory usage and distribution&lt;/li&gt;
&lt;li&gt;Network communication patterns&lt;/li&gt;
&lt;li&gt;Cache hit/miss ratios&lt;/li&gt;
&lt;li&gt;Queue sizes and processing times&lt;/li&gt;
&lt;li&gt;Connection health and latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics help you optimize performance, troubleshoot issues, and make informed scaling decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we start, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hazelcast instance (embedded or standalone)&lt;/li&gt;
&lt;li&gt;JMX Prometheus Exporter JAR file&lt;/li&gt;
&lt;li&gt;Basic understanding of JVM options and YAML configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Enabling JMX API
&lt;/h2&gt;

&lt;p&gt;The first step is enabling JMX (Java Management Extensions) on your Hazelcast instance. The process differs slightly between embedded and standalone deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Embedded Hazelcast
&lt;/h3&gt;

&lt;p&gt;When running Hazelcast embedded within your application, add these JVM arguments to your application's startup command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-Dcom&lt;/span&gt;.sun.management.jmxremote
&lt;span class="nt"&gt;-Dcom&lt;/span&gt;.sun.management.jmxremote.port&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;portNo&amp;gt;
&lt;span class="nt"&gt;-Dcom&lt;/span&gt;.sun.management.jmxremote.authenticate&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="nt"&gt;-Dhazelcast&lt;/span&gt;.jmx&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="nt"&gt;-javaagent&lt;/span&gt;:path_to_jmx_exporter_jar_file&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;port&amp;gt;:/path_to_jmx_exporter_config/config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important Security Note&lt;/strong&gt;: Set &lt;code&gt;-Dcom.sun.management.jmxremote.authenticate=true&lt;/code&gt; in production environments and configure proper authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Standalone Hazelcast
&lt;/h3&gt;

&lt;p&gt;For standalone Hazelcast instances, navigate to your Hazelcast installation directory and edit the &lt;code&gt;config/jvm.options&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HAZELCAST_HOME&lt;/span&gt;
vim config/jvm.options
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the same JVM arguments mentioned above to this file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Configuring JMX Exporter
&lt;/h2&gt;

&lt;p&gt;Create a configuration file (typically named &lt;code&gt;config.yaml&lt;/code&gt;) for the JMX exporter. This file defines how JMX metrics are transformed into Prometheus format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#---&lt;/span&gt;
&lt;span class="na"&gt;attrNameSnakeCase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;lowercaseOutputName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;lowercaseOutputLabelNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;whitelistObjectNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;com.hazelcast:type=Metrics,*"&lt;/span&gt;

&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^com.hazelcast&amp;lt;type=Metrics,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;instance=(.*),&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prefix=(.*),&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tag([0-9]+)=(.*)&amp;gt;&amp;lt;&amp;gt;(.+):"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hazelcast_$5&lt;/span&gt;
    &lt;span class="na"&gt;attrNameSnakeCase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$1&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$2&lt;/span&gt;
      &lt;span class="na"&gt;tag$3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$4&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^com.hazelcast&amp;lt;type=Metrics,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;instance=(.*),&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prefix=(.*)&amp;gt;&amp;lt;&amp;gt;(.+):"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hazelcast_$3&lt;/span&gt;
    &lt;span class="na"&gt;attrNameSnakeCase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$1&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me break down this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;attrNameSnakeCase&lt;/strong&gt;: Converts attribute names to snake_case format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lowercaseOutputName&lt;/strong&gt;: Ensures metric names are lowercase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;whitelistObjectNames&lt;/strong&gt;: Filters JMX objects to include only Hazelcast metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rules&lt;/strong&gt;: Define patterns for transforming JMX metric names into Prometheus format&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Restart and Verify
&lt;/h2&gt;

&lt;p&gt;After configuring everything, restart your Java application or Hazelcast instance. The metrics should become available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;server_ip&amp;gt;:&amp;lt;jmx_exporter_port&amp;gt;/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding the Metrics Format
&lt;/h2&gt;

&lt;p&gt;Once everything is running, you'll see metrics in Prometheus format. Here are some examples of what to expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hazelcast_total_max_get_latency{instance="hz-instance",prefix="map",tag0="name=request-cache"} 1.0
hazelcast_priority_queue_size{instance="hz-instance",prefix="operation"} 0.0
hazelcast_connection_type{instance="hazelcastInstance",prefix="tcp.connection",tag0="endpoint=[localhost]:5000",tag1="bindAddress=[testserver]:5000"} 1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each metric includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metric name&lt;/strong&gt;: Descriptive name of what's being measured&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Labels&lt;/strong&gt;: Key-value pairs providing context (instance, prefix, tags)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value&lt;/strong&gt;: The actual measurement&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Troubleshooting Tips
&lt;/h2&gt;

&lt;p&gt;Based on my experience implementing this setup, here are some issues you might encounter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Port Conflicts&lt;/strong&gt;: Ensure your JMX and exporter ports don't conflict with other services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Path Issues&lt;/strong&gt;: Double-check that the path to your config.yaml file is absolute and accessible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firewall Restrictions&lt;/strong&gt;: Make sure the specified ports are open and accessible from your monitoring systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory Overhead&lt;/strong&gt;: JMX monitoring adds some overhead, so monitor your application's memory usage after enabling it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security First&lt;/strong&gt;: Always enable authentication in production environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Monitoring&lt;/strong&gt;: Keep an eye on the additional memory and CPU overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective Metrics&lt;/strong&gt;: Use whitelist patterns to export only the metrics you need&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular Updates&lt;/strong&gt;: Keep your JMX exporter version updated for better performance and security&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Integration with Monitoring Stack
&lt;/h2&gt;

&lt;p&gt;Once you have metrics exposed, you can integrate them with your existing monitoring stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus&lt;/strong&gt;: Configure Prometheus to scrape the metrics endpoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana&lt;/strong&gt;: Create dashboards to visualize Hazelcast performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AlertManager&lt;/strong&gt;: Set up alerts for critical thresholds&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Monitoring Hazelcast with JMX exporter provides valuable insights into your distributed cache performance. While the initial setup requires some configuration, the visibility you gain into your system's behavior is invaluable for maintaining robust applications.&lt;/p&gt;

&lt;p&gt;The key is starting simple and gradually expanding your monitoring scope as you understand which metrics matter most for your specific use case. Remember to balance comprehensive monitoring with system performance, and always prioritize security in production environments.&lt;/p&gt;

&lt;p&gt;If you have already implemented this on your environment then I’d love to hear about your experiences and any additional tips you’ve discovered along the way! Thanks for your time!&lt;/p&gt;

</description>
      <category>hazelcast</category>
      <category>jmxexporter</category>
      <category>jmx</category>
      <category>prometheus</category>
    </item>
    <item>
      <title>Jenkins Plugin Update Workaround for Offline or Proxy-Restricted Environments</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Mon, 14 Jul 2025 15:59:13 +0000</pubDate>
      <link>https://forem.com/nirzak/jenkins-plugin-update-workaround-for-offline-or-proxy-restricted-environments-26c1</link>
      <guid>https://forem.com/nirzak/jenkins-plugin-update-workaround-for-offline-or-proxy-restricted-environments-26c1</guid>
      <description>&lt;p&gt;When deploying Jenkins in a secure environment - like behind a corporate firewall or proxy, it’s often creates problems in plugin installations or updates. Because Jenkins fetches plugin metadata and files from dynamic CDN URLs, which makes it hard to whitelist exact endpoints on your proxy or firewall.&lt;/p&gt;

&lt;p&gt;In this guide, I’ll walk you through how to &lt;strong&gt;host your own Jenkins update center mirror&lt;/strong&gt; using a static URL, making it possible to fetch and install plugins without opening up your network to all of Jenkins' CDNs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Jenkins plugin updates rely on URLs that resolve to CDNs or change frequently. In a restricted environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your Jenkins host may have &lt;strong&gt;no direct internet access&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;All outbound traffic must go through a &lt;strong&gt;proxy or firewall&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Whitelisting all possible cdn endpoints is not feasible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Generate your own &lt;code&gt;update-center.json&lt;/code&gt; file, sign it with your own certificate, and serve it from a local or approved static host. Then configure Jenkins to use this static URL as the update site.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Prepare the &lt;code&gt;update-center.json&lt;/code&gt; on Any Internet-Connected Machine
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/Nirzak/jenkins-update-center" rel="noopener noreferrer"&gt;Nirzak/jenkins-update-center&lt;/a&gt; repo: (Thanks to lewark)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/Nirzak/jenkins-update-center.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;jenkins-update-center
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Remove any existing certificates: (Skip this step if you want to use the repo certificate)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; rootCA/update-center.crt rootCA/update-center.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Edit the &lt;code&gt;mirrors.json&lt;/code&gt; file and replace the content with:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"jenkins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://archives.jenkins.io/"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, I used archives.jenkins.io as the mirror. you can also use any other mirror url if you want. You need to allow the mirror url from your proxy or firewall. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a new self-signed cert and key:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; rootCA/update-center.key 2048
   openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-key&lt;/span&gt; rootCA/update-center.key &lt;span class="nt"&gt;-out&lt;/span&gt; rootCA/update-center.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install required Python packages:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Generate the custom update center:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   python3 generator.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your generated &lt;code&gt;update-center.json&lt;/code&gt; will be available in the &lt;code&gt;&amp;lt;current_directory&amp;gt;/updates/jenkins&lt;/code&gt; directory.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Setup on Jenkins Host
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Copy the generated &lt;code&gt;update-center.json&lt;/code&gt; and &lt;code&gt;update-center.crt&lt;/code&gt; to your Jenkins host.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create the required directory:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;JENKINS_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/update-center-rootCAs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Move the cert file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cp &lt;/span&gt;rootCA/update-center.crt &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;JENKINS_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/update-center-rootCAs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 3: Host the &lt;code&gt;update-center.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Use Python’s built-in HTTP server (or any simple web server to serve the file):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;path/to/update-center.json
&lt;span class="nb"&gt;nohup &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 8000 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will serve the file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://your-host:8000/update-center.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 4: Configure Jenkins to Use the New Update Site
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Jenkins UI.&lt;/li&gt;
&lt;li&gt;Navigate to: &lt;strong&gt;Manage Jenkins → Manage Plugins → Advanced&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Update Site URL&lt;/strong&gt; field, enter:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   http://your-host:8000/update-center.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Submit&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  All done!
&lt;/h2&gt;

&lt;p&gt;Now go to the &lt;strong&gt;Available&lt;/strong&gt; or &lt;strong&gt;Updates&lt;/strong&gt; tab under &lt;strong&gt;Manage Plugins&lt;/strong&gt;, and you should be able to install or update any plugin if you allow the mirror from your proxy or firewall. Now you don't need to allow all the other cdn mirror urls from your proxy since it's only using a static url.&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>devops</category>
      <category>ci</category>
      <category>proxy</category>
    </item>
    <item>
      <title>Getting Started with GitHub Actions</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Tue, 17 Oct 2023 16:56:00 +0000</pubDate>
      <link>https://forem.com/nirzak/getting-started-with-github-actions-1ppa</link>
      <guid>https://forem.com/nirzak/getting-started-with-github-actions-1ppa</guid>
      <description>&lt;p&gt;Every software industry nowadays is adapting continuous integration and continuous delivery (CI/CD) platforms to reduce time and effort in the software release process. One such CI/CD platform is Github's Github Actions. Before starting, if you don't know what CI/CD is, then let me tell you, CI (Continuous Integration) basically means automating a build and test phase of a software release cycle. And CD (Continuous Delivery) means to deliver or release it to the customer continuously. So, together they complete a whole release cycle.&lt;/p&gt;

&lt;p&gt;Now, let's get back to Github Action which itselft is a CI/CD solution. Github Actions allows a developer to automate worflows like issues, pull requests, commits, merging almost eveything within github. Now it can be creating a pull request, merging it, assigning someone into the pull request. In fact you can also set organization rules, for example, assign developer permissions etc using this feature.&lt;/p&gt;

&lt;p&gt;Now let's take a dive into the details of Github Action. Every Github Action is a workflow that consists of some core components like events, jobs, steps, actions, and runners. Let's explore them in detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow:&lt;/strong&gt;&lt;br&gt;
A workflow is a configurable automated process consisting of one or multiple jobs running parallelly triggered by events. They are typically declared in YAML files and reside inside &lt;strong&gt;.github/workflows&lt;/strong&gt; directory of a GitHub repository.&lt;br&gt;
&lt;strong&gt;Events:&lt;/strong&gt;&lt;br&gt;
Events are basically the defined triggers that start a workflow. For example: Creating a pull request, Pushing a commit into the repository, A defined scheduled cron time, Merging Pull requests etc can be an example of events.&lt;br&gt;
&lt;strong&gt;Jobs:&lt;/strong&gt;&lt;br&gt;
Jobs are the executed tasks in a workflow that runs after an event is triggered. A workflow can have one or multiple jobs running in parallel.&lt;br&gt;
&lt;strong&gt;Actions:&lt;/strong&gt;&lt;br&gt;
These are the most interesting things in a GitHub workflow. Actions are basically some particular tasks bound as a single package that you can use in any action workflow or you can also make your own.&lt;br&gt;
&lt;strong&gt;Runner:&lt;/strong&gt;&lt;br&gt;
A runner is a series of tasks in a workflow that are executed in a single job. Every runner is responsible for executing a single job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up A Basic Action Workflow:&lt;/strong&gt;&lt;br&gt;
Now let's set up a basic action workflow to see how it works. To do that, let's create a demo repository on GitHub.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inside that repository create a directory named .github and inside that .gihub directory create another directory workflow. So, basically, it will be &lt;strong&gt;.github/workflows&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Inside that .github/workflows directory create a yaml file named demo-workflow.yml&lt;/li&gt;
&lt;li&gt;Copy the following yaml config into that file. (Courtesy of Github Docs)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: GitHub Actions Demo
on: [push]
jobs:
 Explore-GitHub-Actions:
 runs-on: ubuntu-latest
 steps:
 - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
 - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
 - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
 - name: Check out repository code
 uses: actions/checkout@v3
 - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
 - run: echo "🖥️ The workflow is now ready to test your code on the runner."
 - name: List files in the repository
 run: |
 ls ${{ github.workspace }}
 - run: echo "🍏 This job's status is ${{ job.status }}."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Save it and then just push a random commit into that repository and see the workflow in action. Here, We have used [push] as a trigger, so it will trigger for every commit that has been pushed into that repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now let's elaborate on the above workflow in detail.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Here on the first line &lt;strong&gt;"name:"&lt;/strong&gt; is basically the workflow name. You can set this to anything that resembles that workflow. If you omit "name:", GitHub will set it to the workflow file path relative to the root of the repository.&lt;/li&gt;
&lt;li&gt;In the next line &lt;strong&gt;"on:"&lt;/strong&gt; is basically used for the trigger purpose. This is our event trigger. Here, we can use more event triggers like fork, created, and deleted and also particular events like pull_requests, issues etc. for example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on:
  pull_request:
    types: [opened, reopened]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will trigger an event whenever a pull request is created or reopened. Also, you can create multiple custom labels and use them as a trigger using the label's name. For more action triggers take a look at this article: &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows" rel="noopener noreferrer"&gt;Events That Trigger Workflows&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The third line is the jobs part. Here we will define our tasks that will run after the event gets triggered. Inside jobs, there's a section titled &lt;strong&gt;"runs-on:"&lt;/strong&gt; This is basically the environment where the tasks will be executed. In the above case, this is "ubuntu-latest".&lt;/li&gt;
&lt;li&gt;In the steps section, we have defined an &lt;strong&gt;"uses:"&lt;/strong&gt; section. This is basically the action's part. Here, you can use any pre-defined action workflow or make your own action workflow and then can use it by just mentioning the action name like this one &lt;code&gt;actions/checkout@v3&lt;/code&gt;. Here, we are using checkout action workflow which basically clones our repo to a runner, so that we can further run tests on it, deploy it or perform any other tasks on the code.
So, guys that's all for now. To learn more about github actions take a look into github's official documentation about Github Actions here: &lt;a href="https://docs.github.com/en/actions/learn-github-actions" rel="noopener noreferrer"&gt;https://docs.github.com/en/actions/learn-github-actions&lt;/a&gt;
Happy Automating!&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>githubactions</category>
      <category>automation</category>
      <category>cicd</category>
    </item>
    <item>
      <title>My Experience on Hacktoberfest 2023</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Tue, 17 Oct 2023 16:39:27 +0000</pubDate>
      <link>https://forem.com/nirzak/my-experience-on-hacktoberfest-2023-207g</link>
      <guid>https://forem.com/nirzak/my-experience-on-hacktoberfest-2023-207g</guid>
      <description>&lt;h2&gt;
  
  
  My Journey:
&lt;/h2&gt;

&lt;p&gt;I have been participating hacktoberfest since 2021. And here's 2023 and I am on my third hacktoberfest. Though I haven't got time to contribute much but have the chance to complete my goals of 4 PRs. Here's the last PR link that I have got to merge.&lt;br&gt;
&lt;a href="https://github.com/public-apis-dev/public-apis/pull/219" rel="noopener noreferrer"&gt;https://github.com/public-apis-dev/public-apis/pull/219&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This year I have focused much on the non-code repositories rather than coding cause fixing and improving the documentation and increasing the resources for open source developers was my first goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some tips for newcomers:
&lt;/h2&gt;

&lt;p&gt;Remember, always set your goals before jumping into contribution like which type of contribution you want to make. Then search for good first issues and repositories with the hacktoberfest label that matches your goals. &lt;br&gt;
Take some time to read the contribution guidelines (This is really important. Cause every open source repository has guidelines and rules to follow. It can be from contributions to creating pull requests.)&lt;br&gt;
After this do your contribution and create the pull request according to guidelines. Have patience. If the maintainer is inactive then wait for a day to two and then mention him as we have deadlines.&lt;br&gt;
Happy Hacktoberfesting!&lt;br&gt;
Any problems? give me a shout. &lt;/p&gt;

</description>
      <category>hacktoberfest23</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Finally successfully completed hacktoberfest 2023</title>
      <dc:creator>Nirjas Jakilim</dc:creator>
      <pubDate>Fri, 13 Oct 2023 19:15:15 +0000</pubDate>
      <link>https://forem.com/nirzak/finally-successfully-completed-hacktoberfest-2023-3e6o</link>
      <guid>https://forem.com/nirzak/finally-successfully-completed-hacktoberfest-2023-3e6o</guid>
      <description>&lt;p&gt;Finally completed my hacktoberfest journey of 2023. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo140z6jjoirvwqu671go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo140z6jjoirvwqu671go.png" alt="Image description" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hacktoberfest23</category>
    </item>
  </channel>
</rss>
