Skip to content

Usage β€Ί Pre and Post Loader ScriptsΒΆ

CSF includes dedicated directories where you can place custom Bash scripts to run at specific stages of the firewall’s startup process. This allows you to easily maintain persistent, custom firewall rules that are automatically applied each time the CSF service starts or restarts.


SummaryΒΆ

The following is a summary of what this page explains:

  • When you install CSF, two files will be placed on your server. These are known as the pre and post loader scripts:
    1. Preloader: /usr/local/csf/bin/csfpre.sh
    2. Postloader: /usr/local/csf/bin/csfpost.sh
  • These loader scripts scan two different folders on your server to see if you have added any custom bash scripts you want ran when CSF starts. You can place your custom bash scripts in two different folders:
    1. /usr/local/include/csf/pre.d/
      • Place your bash scripts in this folder if you want your scripts to run BEFORE CSF imports the default rules into your server.
    2. /usr/local/include/csf/post.d/
      • Place your bash scripts in this folder if you want your scripts to run AFTER CSF imports the default rules into your server.
  • Once the scripts are added, restart CSF with sudo csf -ra




Location and StructureΒΆ

This section outlines exactly how the pre and post scripts are initialized and loaded.


Loader ScriptsΒΆ

  • When CSF is installed for the first time, two files /usr/local/csf/bin/csfpre.sh and /usr/local/csf/bin/csfpost.sh are automatically created on your system (they will not overwrite existing copies). These files are loader scripts, giving you the ability to add your own custom bash scripts.
    • You must create the pre-loader folder /usr/local/include/csf/pre.d/ and post-loader folder /usr/local/include/csf/post.d/
  • If you already have existing pre/post loader files in place, CSF will respect this and NOT overwrite your existing files. Your existing setup will not be touched.


/usr/local/csf/bin/csfpre.sh
  • The file csfpre.sh installed with CSF loads every custom bash script you drop in the /usr/local/include/csf/pre.d/ folder.
  • If making your own csfpre.sh loader, there are two allowed locations to place this script β€” either one is valid:
    • /usr/local/csf/bin/csfpre.sh (default)
    • /etc/csf/csfpre.sh (alternative)
  • Runs before all default iptables rules are applied; allows you to add custom rules which persist alongside CSF's defaults.
/usr/local/csf/bin/csfpost.sh
  • The file csfpost.sh installed with CSF loads every custom bash script you drop in the /usr/local/include/csf/post.d/ folder.
  • If making your own csfpost.sh loader, there are two allowed locations to place this script β€” either one is valid:
    • /usr/local/csf/bin/csfpost.sh (default)
    • /etc/csf/csfpost.sh (alternative)
  • Runs after all default iptables rules are applied, allowing you to add custom rules which persist alongside CSF's defaults.
pre.sh & post.sh: Multiple Locations Allowed

By default, installing CSF will create the loader files csfpre.sh and csfpost.sh, and place them in the folder /usr/local/csf/bin/.

However, this location is not strict; you can place these loader files in one of two allowed locations:

  • csfpre.sh
    • /usr/local/csf/bin/csfpre.sh
    • /etc/csf/csfpre.sh
  • csfpost.sh
    • /usr/local/csf/bin/csfpost.sh
    • /etc/csf/csfpost.sh


Loader FoldersΒΆ

When the loader scripts /usr/local/csf/bin/csfpre.sh and /usr/local/csf/bin/csfpost.sh run, they check specific folders to see if you have placed any custom bash scripts inside. By placing custom bash scripts in these folders, you can write bash scripts which assist with setting up custom firewall rules which are automatically applied every time CSF starts or restarts, ensuring your custom rules persist.


/usr/local/include/csf/pre.d/
  • Your custom bash scripts will run before CSF applies any default iptables rules.
  • Scripts placed here run automatically every time CSF starts or restarts.
/usr/local/include/csf/post.d/
  • Your custom bash scripts will run after CSF applies any default iptables rules.
  • Scripts placed here run automatically every time CSF starts or restarts.
Defining A New Loader Folder

The CSF loader files /usr/local/csf/bin/csfpre.sh and /usr/local/csf/bin/csfpost.sh will look inside a specific folder for any custom bash scripts you have added.

If you wish to change the folder name / path used for storing your custom bash scripts, open these loader files and change the assigned variable toward the top of each file:

path_csfpred="/usr/local/include/csf/pre.d"
path_csfpostd="/usr/local/include/csf/post.d"


Loader ExampleΒΆ

We have provided both example structures of how your scripts can be set up. Script names can be any name you want, no restrictions.

This example stores your loader files in:

  • /usr/local/csf/bin/csfpre.sh
  • /usr/local/csf/bin/csfpost.sh
πŸ“ usr
  πŸ“ local
      πŸ“ csf
        πŸ“ bin
            πŸ“„ csfpre.sh
            πŸ“„ csfpost.sh
      πŸ“ include
        πŸ“ csf
            πŸ“ pre.d
              πŸ“„ my_rules_before.sh
            πŸ“ post.d
              πŸ“„ my_docker_rules.sh
              πŸ“„ openvpn_rules.sh

This example stores your loader files in:

  • /etc/csf/csfpre.sh
  • /etc/csf/csfpost.sh
πŸ“ etc
  πŸ“ csf
      πŸ“„ csfpre.sh
      πŸ“„ csfpost.sh
πŸ“ usr
  πŸ“ local
      πŸ“ include
        πŸ“ csf
            πŸ“ pre.d
              πŸ“„ my_rules_before.sh
            πŸ“ post.d
              πŸ“„ my_docker_rules.sh
              πŸ“„ openvpn_rules.sh




Writing Custom RulesΒΆ

As outlined earlier, the pre.d and post.d folders allow you to drop your own custom bash scripts inside the folders which will be responsible for any iptable rules you need to add to CSF every time CSF is started or restarted.

We will provide an example script below just to outline what can be done. In our example, we will create /usr/local/include/csf/post.d/ports-blacklist.sh. The script will do the following:

  • Defines a list of blacklisted ports using a JSON array in BLACKLIST_PORTS. Each port we want to block will include the port number and a comment describing what that port is used for.
  • Iterates over each port in the blacklist using jq to parse the JSON.
  • For each port:
    • Extract the port number ENTRY_PORT and its description/comment ENTRY_COMMENT.
    • Check if a UDP rule already exists in iptables for that port:
      • Sets DELETE_INPUT_UDP=1 if the rule does not exist.
    • Check if a TCP rule already exists in iptables for that port:
      • Sets DELETE_INPUT_TCP=1 if the rule does not exist.
    • Add a firewall rule if it isn't already present:
      • Inserts a rule to drop UDP traffic to the port.
      • Inserts a rule to drop TCP traffic to the port.


Add the code below to your new file /usr/local/include/csf/post.d/ports-blacklist.sh and save.

#!/bin/sh

# #
#   Settings > Ports
# #

BLACKLIST_PORTS=$(cat <<EOF
[
    {"port":"111", "comment":"used by sunrpc/rpcbind, has vulnerabilities"}
]
EOF
)

# #
#   Define > Iptables
# #

path_iptables4=$(which iptables)
path_iptables6=$(which ip6tables)

# #
#   Loop blacklists, create if missing
# #

printf "\n"
printf "  + RESTRICT      Blacklisting Ports\n"

echo "$BLACKLIST_PORTS" | jq -c '.[]' | while IFS= read -r row; do

    ENTRY_PORT=$(echo "$row" | jq -r '.port')
    ENTRY_COMMENT=$(echo "$row" | jq -r '.comment')

    # #
    #   See if ports already exist in iptables
    # #

    DELETE_INPUT_UDP=0
    DELETE_INPUT_TCP=0

    $path_iptables4 -C INPUT -p udp --dport "$ENTRY_PORT" -j DROP >/dev/null 2>&1 || DELETE_INPUT_UDP=1
    $path_iptables4 -C INPUT -p tcp --dport "$ENTRY_PORT" -j DROP >/dev/null 2>&1 || DELETE_INPUT_TCP=1

    # #
    #   Drop Port > UDP
    # #

    if [ "$DELETE_INPUT_UDP" = "0" ]; then
        printf "                   βœ“ Port already blacklisted\n"
    else
        sudo $path_iptables4 -I INPUT -p udp --dport "$ENTRY_PORT" -j DROP
        printf '%-17s %-50s %-55s\n' " " "β”œβ”€ Blacklisting $ENTRY_PORT (UDP)" "$ENTRY_COMMENT"
    fi

    # #
    #   Drop Port > TCP
    # #

    if [ "$DELETE_INPUT_TCP" = "0" ]; then
        printf "                   βœ“ Port already blacklisted\n"
    else
        sudo $path_iptables4 -I INPUT -p tcp --dport "$ENTRY_PORT" -j DROP
        printf '%-17s %-50s %-55s\n' " " "β”œβ”€ Blacklisting $ENTRY_PORT (TCP)" "$ENTRY_COMMENT"
    fi

done


The script itself is very easy to use. We make sure to edit the list BLACKLIST_PORTS and populate it with ports we do not want the outside world being able to access.

BLACKLIST_PORTS=$(cat <<EOF
[
    {"port":"111", "comment":"used by sunrpc/rpcbind, has vulnerabilities"}
    {"port":"21", "comment":"insecure ftp"}
]
EOF
)


After you edit the list of ports above, restart CSF and the script will be automatically re-loaded:

sudo csf -ra
LOGDROPOUT  all opt -- in * out !lo  0.0.0.0/0  -> 0.0.0.0/0  
LOGDROPIN  all opt -- in !lo out *  0.0.0.0/0  -> 0.0.0.0/0  
csf: FASTSTART loading DNS (IPv4)
LOCALOUTPUT  all opt -- in * out !lo  0.0.0.0/0  -> 0.0.0.0/0  
LOCALINPUT  all opt -- in !lo out *  0.0.0.0/0  -> 0.0.0.0/0  
Running /usr/local/csf/bin/csfpost.sh
Loading post-script: /usr/local/include/csf/post.d/ports-blacklist.sh

+ RESTRICT      Blacklisting Ports
                  β”œβ”€ Blacklisting 111 (UDP) used by sunrpc/rpcbind, has vulnerabilities
                  β”œβ”€ Blacklisting 111 (TCP) used by sunrpc/rpcbind, has vulnerabilities
                  β”œβ”€ Blacklisting 21 (UDP) insecure ftp
                  β”œβ”€ Blacklisting 21 (TCP) insecure ftp


We can now use the iptables command to confirm our rules were added. Iptables will resolve whatever service is associated with a port, which means port 111 will show as sunrpc. If you wish to show just the port number, append -n to your iptables command:

sudo iptables -L -n

If you use the command sudo iptables -L

Chain INPUT (policy DROP)
target     prot opt source               destination         
DROP       tcp  --  anywhere             anywhere             tcp dpt:sunrpc
DROP       udp  --  anywhere             anywhere             udp dpt:sunrpc

Chain LOGDROPIN (2 references)
target     prot opt source               destination         
DROP       tcp  --  anywhere             anywhere             tcp dpt:sunrpc
DROP       udp  --  anywhere             anywhere             udp dpt:sunrpc


If you use the command sudo iptables -L -n

Chain INPUT (policy DROP)
target     prot opt source               destination         
DROP       6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:111
DROP       17   --  0.0.0.0/0            0.0.0.0/0            udp dpt:111

Chain LOGDROPIN (2 references)
target     prot opt source               destination         
DROP       6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:111
DROP       17   --  0.0.0.0/0            0.0.0.0/0            udp dpt:111




ConclusionΒΆ

From this point forward, you can create any number of pre and post bash scripts for your firewall. Simply drop any bash scripts you wish to load with CSF inside the folders /usr/local/include/csf/pre.d/ and /usr/local/include/csf/post.d/.

For a quick reference to the file and folder names, you can view the section Location and Structure.




Next Steps ΒΆ

Select what documentation you would like to proceed with next ...

  •   Setting Up Blocklists


    Blocklists provide the foundation for blocking unwanted and malicious traffic in CSF. They allow you to automatically deny access from IP addresses that have been identified as abusive or high risk.

    This section introduces what blocklists are, how they work, and how to configure them using CSF’s official blocklist or trusted third-party sources.

    Once you are comfortable using blocklists, you can advance to IPSETs to handle larger lists more efficiently and improve performance as your ruleset grows.

  •   Introduction to IPSETs


    Blocklists and IPSETs are designed to work together. Blocklists provide a simple way to block unwanted traffic from reaching your server, but large blocklists can be inefficient and memory-intensive.

    If you plan to import blocklists containing more than a few thousand IP addresses, it is strongly recommended to enable CSF’s IPSET integration.

    IPSETs allow you to block significantly larger numbers of IP addresses in a far more efficient way, without the risk of excessive memory usage or performance degradation.