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.
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 starter files
/usr/local/csf/bin/csfpre.shand/usr/local/csf/bin/csfpost.share automatically created on your system (only if they don’t already exist). These serve as base loader scripts, giving you a foundation to add your own custom logic later on.- You must create your own pre/post loader folders
/usr/local/include/csf/pre.d/and/usr/local/include/csf/post.d/
- You must create your own pre/post loader folders
- If you already have existing pre/post loader files in place, CSF will respect your current setup and skip creating the starter versions — allowing you to continue using your existing scripts without interruption.
-
csfpre.sh -
- The file
csfpre.shiterates over the loader folderpre.dand runs any scripts found there. - There are two allowed locations for this loader 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.
- The file
-
csfpost.sh -
- The file
post.shiterates over the loader folderpost.dand runs any scripts found there. - There are two allowed locations for this loader 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.
- The file
pre/post.sh: Multiple Allowed Locations
By default, installing CSF will create your loader files pre.d and post.d in the folder /usr/local/csf/bin/.
However, this location is not required—you can place these loader files in any of the following acceptable paths:
- csfpre.sh
/usr/local/csf/bin/csfpre.sh/etc/csf/csfpre.sh
- csfpost.sh
/usr/local/csf/bin/csfpost.sh/etc/csf/csfpost.sh
All folders above are automatically scanned when you start or restart CSF. You can add scripts to both locations if you choose.
You can also add your bash commands directly into the files csfpre.sh and csfpost.sh themselves.
Loader Folders¶
When the loader scripts run, they check their designated folders for any custom scripts you’ve added. By placing your scripts in these folders, you can create firewall rules that are automatically applied every time CSF starts or restarts, ensuring your custom rules persist.
-
/usr/local/include/csf/pre.d/ -
- Stores bash scripts that run before CSF applies its default iptables rules.
- Scripts placed here run automatically every time CSF starts or restarts.
-
/usr/local/include/csf/post.d/ -
- Stores bash scripts that run after CSF applies its default iptables rules.
- Scripts placed here run automatically every time CSF starts or restarts.
Defining A New Loader Folder
The CSF loader folder which is scanned is defined within the loader files themselves. To change the folder that the loader uses, open csfpre.sh and csfpost.sh and change the following lines:
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
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 the service 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 entry includes a port number and a comment describing it. - Iterates over each port in the blacklist using
jqto parse the JSON. - For each port:
- Extracts the port number
ENTRY_PORTand its description/commentENTRY_COMMENT. - Checks if a UDP rule already exists in iptables for that port:
- Sets
DELETE_INPUT_UDP=1if the rule does not exist.
- Sets
- Checks if a TCP rule already exists in iptables for that port:
- Sets
DELETE_INPUT_TCP=1if the rule does not exist.
- Sets
- Adds the firewall rules if they are not already present:
- Inserts a rule to drop UDP traffic to the port.
- Inserts a rule to drop TCP traffic to the port.
- Extracts the port number
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 absolutely do not want giving access to:
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, simply restart CSF's services and the script will be automatically re-loaded:
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 view iptables 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:
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
Conclusion¶
From this point forward, you can create any number of pre and post scripts for your own firewall setup. Simply drop the scripts in the folders specified in the section Location and Structure.
Next Steps ¶
Select what documentation you would like to proceed with next ...
-
Improve firewall efficiency in CSF by enabling IPSET integration to manage large blocklists.
This chapter covers installing the IPSET package and configuring CSF to use it for handling blocklists.
Using IPSET allows CSF to group IP addresses into sets, reducing the number of iptables rules and improving overall performance.
-
Blocklists in CSF allow you to automatically block connections from known malicious IP addresses, helping to protect your server from abusive traffic.
This chapter explains how to configure and use blocklists, including CSF’s official blocklist and third-party sources.
You’ll also learn how to enable blocklists with or without IPSET, ensuring they work efficiently no matter the size of the list.