Skip to content

Commit 29ebe38

Browse files
authored
Merge pull request #91 from buildplan/crowdsec
feat: Add CrowdSec as optional alternative to fail2Ban
2 parents b7de5a9 + d2aaedc commit 29ebe38

3 files changed

Lines changed: 170 additions & 17 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
-----
99

10-
**Version:** v0.78.5
10+
**Version:** v0.79.0
1111

12-
**Last Updated:** 2025-12-31
12+
**Last Updated:** 2026-01-13
1313

1414
**Compatible With:**
1515

@@ -87,12 +87,12 @@ sha256sum du_setup.sh
8787

8888
Compare the output hash to the one below. They must match exactly.
8989

90-
`efd2359032942499d8f59551ded16b0a9e45bda1c8748e0e17db0bc32c0a013b`
90+
`8f0af0da824395de5a2fac26144ec0d255209ba84c60ea1a9a72f8e6c8f6c039`
9191

9292
Or echo the hash to check, it should output: `du_setup.sh: OK`
9393

9494
```bash
95-
echo efd2359032942499d8f59551ded16b0a9e45bda1c8748e0e17db0bc32c0a013b du_setup.sh | sha256sum --check
95+
echo 8f0af0da824395de5a2fac26144ec0d255209ba84c60ea1a9a72f8e6c8f6c039 du_setup.sh | sha256sum --check
9696
```
9797

9898
### 3. Run the Script
@@ -362,6 +362,7 @@ This setup script leverages the following excellent open-source projects and too
362362

363363
* **Git** - Version control system
364364
* **jq** - JSON query processor for data manipulation
365+
* **make** - Utility for building and maintaining programmes from source code
365366
* **rsync** - Efficient file synchronization
366367
* **curl** - Data transfer tool
367368
* **wget** - File download utility

du_setup.sh

Lines changed: 164 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#!/bin/bash
22

33
# Debian and Ubuntu Server Hardening Interactive Script
4-
# Version: 0.78.5 | 2025-12-31
4+
# Version: 0.79.0 | 2026-01-13
55
# Changelog:
6+
# - v0.79.0: Added CrowdSec, now you can choose between fail2ban and CrowdSec for system level firewall.
67
# - v0.78.5: Switched to using nano as the default editor in .bashrc.
78
# - v0.78.4: Improved configure_swap to detect swap partitions vs files.
89
# Prevents 'fallocate' crashes on physical partitions by offering to disable them or skip.
910
# - v0.78.3: Update the summary to try to show the right environment detection based on finding personal VMs and cloud VPS.
1011
# Run update & upgrade in the final step to ensure system is fully updated after restart.
11-
# - v0.78.2: In configure_system set choosen hostname from collect_config in the /etc/hosts
12+
# - v0.78.2: In configure_system set chosen hostname from collect_config in the /etc/hosts
1213
# - v0.78.1: Collect config failure fixed on IPv6 only VPS.
1314
# - v0.78: Script tries to handles different environments: Direct Public IP, NAT/Router and Local VM only
1415
# The configure_ssh function provides context-aware instructions based on different environments.
@@ -34,7 +35,7 @@
3435
# - v0.68: Enable UFW IPv6 support if available
3536
# - v0.67: Do not log taiscale auth key in log file
3637
# - v0.66: While configuring and in the summary, display both IPv6 and IPv4.
37-
# - v0.65: If reconfigure locales - appy newly configured locale to the current environment.
38+
# - v0.65: If reconfigure locales - apply newly configured locale to the current environment.
3839
# - v0.64: Tested at Debian 13 to confirm it works as expected
3940
# - v0.63: Added ssh install in key packages
4041
# - v0.62: Added fix for fail2ban by creating empty ufw log file
@@ -96,7 +97,7 @@
9697
set -euo pipefail
9798

9899
# --- Update Configuration ---
99-
CURRENT_VERSION="0.78.5"
100+
CURRENT_VERSION="0.79.0"
100101
SCRIPT_URL="https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh"
101102
CHECKSUM_URL="${SCRIPT_URL}.sha256"
102103

@@ -155,6 +156,8 @@ ID="" # This will be populated from /etc/os-release
155156
FAILED_SERVICES=()
156157
PREVIOUS_SSH_PORT=""
157158

159+
IDS_INSTALLED=""
160+
158161
# --- --help ---
159162
show_usage() {
160163
printf "\n"
@@ -252,7 +255,7 @@ print_header() {
252255
printf '%s\n' "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
253256
printf '%s\n' "${CYAN}║ ║${NC}"
254257
printf '%s\n' "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
255-
printf '%s\n' "${CYAN}║ v0.78.5 | 2025-12-31${NC}"
258+
printf '%s\n' "${CYAN}║ v0.79.0 | 2026-01-13${NC}"
256259
printf '%s\n' "${CYAN}║ ║${NC}"
257260
printf '%s\n' "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
258261
printf '\n'
@@ -2912,10 +2915,10 @@ install_packages() {
29122915
fi
29132916
print_info "Installing essential packages..."
29142917
if ! apt-get install -y -qq \
2915-
ufw fail2ban unattended-upgrades chrony \
2916-
rsync wget vim htop iotop nethogs netcat-traditional ncdu \
2918+
ufw unattended-upgrades chrony rsync wget \
2919+
vim htop iotop nethogs netcat-traditional ncdu \
29172920
tree rsyslog cron jq gawk coreutils perl skopeo git \
2918-
apt-listchanges ca-certificates gnupg logrotate \
2921+
apt-listchanges ca-certificates gnupg logrotate make \
29192922
ssh openssh-client openssh-server; then
29202923
print_error "Failed to install one or more essential packages."
29212924
exit 1
@@ -3801,6 +3804,15 @@ configure_firewall() {
38013804
configure_fail2ban() {
38023805
print_section "Fail2Ban Configuration"
38033806

3807+
# Install Fail2Ban if not present
3808+
if ! dpkg -l fail2ban | grep -q ^ii; then
3809+
print_info "Installing Fail2Ban..."
3810+
if ! apt-get install -y -qq fail2ban; then
3811+
print_error "Failed to install Fail2Ban."
3812+
return 1
3813+
fi
3814+
fi
3815+
38043816
# --- Collect User IPs to Ignore ---
38053817
local -a IGNORE_IPS=("127.0.0.1/8" "::1") # Array for easier dedup.
38063818
local -a INVALID_IPS=()
@@ -3987,6 +3999,92 @@ EOF
39873999
log "Fail2Ban configuration completed."
39884000
}
39894001

4002+
configure_crowdsec() {
4003+
print_section "CrowdSec Configuration"
4004+
4005+
# Check if already installed
4006+
if command -v crowdsec >/dev/null 2>&1; then
4007+
print_info "CrowdSec is already installed."
4008+
else
4009+
print_info "Setting up CrowdSec repository..."
4010+
if ! curl -s https://install.crowdsec.net | sh >> "$LOG_FILE" 2>&1; then
4011+
print_error "Failed to setup CrowdSec repository."
4012+
return 1
4013+
fi
4014+
4015+
print_info "Installing CrowdSec agent..."
4016+
if ! apt-get update -qq || ! apt-get install -y -qq crowdsec; then
4017+
print_error "Failed to install CrowdSec."
4018+
return 1
4019+
fi
4020+
print_success "CrowdSec agent installed."
4021+
fi
4022+
4023+
# Install Firewall Bouncer
4024+
if ! dpkg -l crowdsec-firewall-bouncer-iptables | grep -q ^ii; then
4025+
print_info "Installing CrowdSec Firewall Bouncer (iptables/UFW support)..."
4026+
if ! apt-get install -y -qq crowdsec-firewall-bouncer-iptables; then
4027+
print_warning "Failed to install firewall bouncer. CrowdSec will detect but NOT block attacks."
4028+
else
4029+
print_success "CrowdSec Firewall Bouncer installed."
4030+
fi
4031+
else
4032+
print_info "CrowdSec Firewall Bouncer already installed."
4033+
fi
4034+
# UFW Log Acquisition (Parity with Fail2Ban)
4035+
if [[ -d /etc/crowdsec/acquis.d ]]; then
4036+
print_info "Configuring UFW log acquisition..."
4037+
if [[ ! -f /var/log/ufw.log ]]; then
4038+
touch /var/log/ufw.log
4039+
print_info "Created empty /var/log/ufw.log for monitoring."
4040+
fi
4041+
cat <<EOF > /etc/crowdsec/acquis.d/ufw.yaml
4042+
filenames:
4043+
- /var/log/ufw.log
4044+
labels:
4045+
type: syslog
4046+
EOF
4047+
print_success "Added /var/log/ufw.log to CrowdSec acquisition."
4048+
fi
4049+
4050+
# Enrollment
4051+
if confirm "Enroll this instance in the CrowdSec Console (optional)?" "n"; then
4052+
local ENROLL_KEY
4053+
while true; do
4054+
read -rp "$(printf '%s' "${CYAN}Enter your CrowdSec Enrollment Key: ${NC}")" ENROLL_KEY
4055+
if [[ -n "$ENROLL_KEY" ]]; then
4056+
print_info "Enrolling instance..."
4057+
if cscli console enroll "$ENROLL_KEY" 2>&1 | tee -a "$LOG_FILE"; then
4058+
print_success "Instance enrolled successfully."
4059+
break
4060+
else
4061+
print_error "Enrollment failed. Check the key and try again."
4062+
if confirm "Skip enrollment?" "n"; then break; fi
4063+
fi
4064+
else
4065+
print_error "Key cannot be empty."
4066+
fi
4067+
done
4068+
fi
4069+
4070+
# Reload to ensure everything is active
4071+
systemctl restart crowdsec
4072+
print_success "CrowdSec configuration completed."
4073+
4074+
# Help Section
4075+
printf '\n%s\n' "${YELLOW}CrowdSec Quick Reference:${NC}"
4076+
printf " %-30s %s\n" "sudo cscli metrics" "View local metrics"
4077+
printf " %-30s %s\n" "sudo cscli decisions list" "View active bans/decisions"
4078+
printf " %-30s %s\n" "sudo cscli bouncers list" "Check bouncer status"
4079+
printf " %-30s %s\n" "sudo cscli collections list" "View installed collections"
4080+
printf " %-30s %s\n" "sudo cscli parsers list" "View installed parsers"
4081+
printf " %-30s %s\n" "sudo cscli scenarios list" "View active scenarios"
4082+
printf " %-30s %s\n" "sudo cscli alerts list" "View recent alerts"
4083+
printf " %-30s %s\n" "sudo cscli hub update && sudo cscli hub upgrade" "Update CrowdSec scenarios"
4084+
printf '\n'
4085+
log "CrowdSec configuration completed."
4086+
}
4087+
39904088
configure_auto_updates() {
39914089
print_section "Automatic Security Updates"
39924090
if confirm "Enable automatic security updates via unattended-upgrades?"; then
@@ -5253,14 +5351,39 @@ generate_summary() {
52535351
printf '\n'
52545352

52555353
print_separator "Final Service Status Check:"
5256-
for service in "$SSH_SERVICE" fail2ban chrony; do
5354+
for service in "$SSH_SERVICE" chrony; do
52575355
if systemctl is-active --quiet "$service"; then
52585356
printf " %-20s ${GREEN}✓ Active${NC}\n" "$service"
52595357
else
52605358
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "$service"
52615359
FAILED_SERVICES+=("$service")
52625360
fi
52635361
done
5362+
if [[ "$IDS_INSTALLED" == "fail2ban" ]] || systemctl is-active --quiet fail2ban; then
5363+
if systemctl is-active --quiet fail2ban; then
5364+
printf " %-20s ${GREEN}✓ Active${NC}\n" "Fail2Ban"
5365+
else
5366+
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "Fail2Ban"
5367+
FAILED_SERVICES+=("fail2ban")
5368+
fi
5369+
fi
5370+
5371+
if [[ "$IDS_INSTALLED" == "crowdsec" ]] || systemctl is-active --quiet crowdsec; then
5372+
if systemctl is-active --quiet crowdsec; then
5373+
printf " %-20s ${GREEN}✓ Active${NC}\n" "CrowdSec"
5374+
# Check bouncer
5375+
if command -v cscli >/dev/null; then
5376+
if cscli bouncers list -o json | grep -q "firewall-bouncer"; then
5377+
printf " %-20s ${GREEN}✓ Active${NC}\n" "CrowdSec Firewall"
5378+
else
5379+
printf " %-20s ${YELLOW}⚠ Bouncer Missing${NC}\n" "CrowdSec Firewall"
5380+
fi
5381+
fi
5382+
else
5383+
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "CrowdSec"
5384+
FAILED_SERVICES+=("crowdsec")
5385+
fi
5386+
fi
52645387
if ufw status | grep -q "Status: active"; then
52655388
printf " %-20s ${GREEN}✓ Active${NC}\n" "ufw (firewall)"
52665389
else
@@ -5455,8 +5578,13 @@ generate_summary() {
54555578
# Other verification commands
54565579
printf " %-28s ${CYAN}%s${NC}\n" "- Firewall rules:" "sudo ufw status verbose"
54575580
printf " %-28s ${CYAN}%s${NC}\n" "- Time sync:" "chronyc tracking"
5458-
printf " %-28s ${CYAN}%s${NC}\n" "- Fail2Ban sshd jail:" "sudo fail2ban-client status sshd"
5459-
printf " %-28s ${CYAN}%s${NC}\n" "- Fail2Ban ufw jail:" "sudo fail2ban-client status ufw-probes"
5581+
# Adjust verification commands based on selection
5582+
if [[ "$IDS_INSTALLED" == "fail2ban" ]]; then
5583+
printf " %-28s ${CYAN}%s${NC}\n" "- Fail2Ban sshd jail:" "sudo fail2ban-client status sshd"
5584+
elif [[ "$IDS_INSTALLED" == "crowdsec" ]]; then
5585+
printf " %-28s ${CYAN}%s${NC}\n" "- CrowdSec status:" "sudo cscli metrics"
5586+
printf " %-28s ${CYAN}%s${NC}\n" "- CrowdSec bans:" "sudo cscli decisions list"
5587+
fi
54605588
printf " %-28s ${CYAN}%s${NC}\n" "- Swap status:" "sudo swapon --show && free -h"
54615589
printf " %-28s ${CYAN}%s${NC}\n" "- Kernel settings:" "sudo sysctl fs.protected_hardlinks kernel.yama.ptrace_scope"
54625590
if command -v docker >/dev/null 2>&1; then
@@ -5562,7 +5690,31 @@ main() {
55625690
setup_user
55635691
configure_system
55645692
configure_firewall
5565-
configure_fail2ban
5693+
# --- Choose Firewall fail2ban/CrowdSec ---
5694+
print_section "Intrusion Detection System (IDS)"
5695+
printf '%s\n' "${CYAN}Choose an Intrusion Detection/Prevention System:${NC}"
5696+
printf ' 1) Fail2Ban (Classic, simple log parsing, standalone)\n'
5697+
printf ' 2) CrowdSec (Modern, collaborative reputation database, highly recommended)\n'
5698+
printf ' 3) Skip IDS setup\n'
5699+
5700+
local IDS_CHOICE
5701+
read -rp "$(printf '%s' "${CYAN}Enter choice [1]: ${NC}")" IDS_CHOICE
5702+
IDS_CHOICE=${IDS_CHOICE:-1}
5703+
5704+
case "$IDS_CHOICE" in
5705+
1)
5706+
configure_fail2ban
5707+
IDS_INSTALLED="fail2ban"
5708+
;;
5709+
2)
5710+
configure_crowdsec
5711+
IDS_INSTALLED="crowdsec"
5712+
;;
5713+
*)
5714+
print_info "Skipping Intrusion Detection System setup."
5715+
IDS_INSTALLED="none"
5716+
;;
5717+
esac
55665718
configure_ssh
55675719
configure_auto_updates
55685720
configure_time_sync

du_setup.sh.sha256

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
efd2359032942499d8f59551ded16b0a9e45bda1c8748e0e17db0bc32c0a013b du_setup.sh
1+
8f0af0da824395de5a2fac26144ec0d255209ba84c60ea1a9a72f8e6c8f6c039 du_setup.sh

0 commit comments

Comments
 (0)