Skip to content

Instantly share code, notes, and snippets.

@lucabased
Last active January 7, 2025 16:02
Show Gist options
  • Select an option

  • Save lucabased/5cf84f106e0a52ee661e6cc192bb27ba to your computer and use it in GitHub Desktop.

Select an option

Save lucabased/5cf84f106e0a52ee661e6cc192bb27ba to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Secure Server Setup & Hardening Script (Prompt Before Each Function)
#
# Description:
# This script updates the system, installs useful packages, configures
# security enhancements (UFW, Fail2Ban, SSH hardening, sysctl tweaks),
# blacklists known bad IPs, restricts some ICMP types, adds a non-root user,
# and performs basic system audits—now prompting the user to confirm (y/n)
# before each function executes.
set -euo pipefail
#--- 1) HELPER FUNCTIONS ---------------------------------------------#
info() { echo -e "\e[32m[INFO]\e[0m $*"; }
warning() { echo -e "\e[33m[WARN]\e[0m $*"; }
error() { echo -e "\e[31m[ERROR]\e[0m $*" >&2; }
confirm_exec() {
local func="$1"
read -r -p "Execute function '$func'? (y/n): " response
case "$response" in
[yY][eE][sS]|[yY])
return 0 # "Yes" -> proceed
;;
*)
return 1 # "No" -> skip
;;
esac
}
check_root() {
if [[ "$EUID" -ne 0 ]]; then
error "This script must be run as root. Please use sudo or log in as root."
exit 1
fi
}
backup_file() {
local file="$1"
if [[ -f "$file" ]]; then
cp -v "$file" "${file}.bak.$(date +%F_%T)"
info "Backup created for $file"
else
warning "$file not found. Skipping backup."
fi
}
#--- 2) UPDATE & INSTALL PACKAGES ------------------------------------#
update_system() {
info "Updating and upgrading system packages..."
apt update
apt -y upgrade
}
install_packages() {
info "Installing essential and security-related packages..."
apt install -y \
sudo neofetch htop ripgrep fail2ban neovim git curl wget \
unzip gnupg gnupg2 ufw tmux net-tools dnsutils software-properties-common \
build-essential zip jq tree python3-pip aptitude rsync \
rkhunter chkrootkit unattended-upgrades apt-listchanges lynis \
auditd audispd-plugins aide apparmor apparmor-profiles apparmor-utils \
cryptsetup fzf exa bat
}
#--- 3) SSH & KEY SETUP ----------------------------------------------#
setup_ssh_keys() {
info "Configuring SSH keys..."
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Replace with your actual public key if needed
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAgdyGRBJ4PypN2+jCWLmXTuvXdIQoxPGMh0DLyOxZ4r" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
}
harden_ssh() {
info "Hardening SSH configuration..."
local ssh_config="/etc/ssh/sshd_config"
backup_file "$ssh_config"
# Disable password auth, root login, X11 forwarding, and DNS lookups
sed -i 's/^#\?Port .*/Port 2222/' "$ssh_config"
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' "$ssh_config"
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' "$ssh_config"
sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' "$ssh_config"
sed -i 's/^#\?X11Forwarding.*/X11Forwarding no/' "$ssh_config"
sed -i 's/^#\?UseDNS.*/UseDNS no/' "$ssh_config"
# Restrict SSH access to the current user (optional; you can specify others)
echo "AllowUsers $(whoami)" >> "$ssh_config"
systemctl reload sshd
}
#--- 4) CONFIGURE SECURITY -------------------------------------------#
configure_fail2ban() {
info "Configuring Fail2Ban..."
backup_file "/etc/fail2ban/jail.local"
cat <<EOF >/etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
ignoreip = 127.0.0.1/8 ::1
destemail = root@localhost
sender = fail2ban@\$(hostname -f)
action = %(action_mwl)s
[sshd]
enabled = true
EOF
systemctl enable fail2ban
systemctl restart fail2ban
}
configure_sysctl() {
info "Hardening sysctl settings..."
local sysctl_file="/etc/sysctl.d/99-custom.conf"
backup_file "$sysctl_file"
cat <<EOF >"$sysctl_file"
###############################################################################
# IPv4 security settings
###############################################################################
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
###############################################################################
# ICMP restrictions
###############################################################################
# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Optionally ignore all inbound pings (0=respond, 1=ignore)
# net.ipv4.icmp_echo_ignore_all = 1
# Rate limit ICMP to avoid ping floods (tweak as needed)
net.ipv4.icmp_ratelimit = 100
net.ipv4.icmp_ratemask = 88089
EOF
sysctl --system
}
configure_firewall() {
info "Configuring UFW firewall..."
ufw default deny incoming
ufw default allow outgoing
# Allow incoming SSH, HTTP, HTTPS (adjust as needed)
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
# Example: Blacklisting known bad IPs
KNOWN_BAD_IPS=(
"203.0.113.123"
"198.51.100.250"
"192.0.2.5"
)
for ip in "${KNOWN_BAD_IPS[@]}"; do
ufw deny from "$ip"
done
ufw --force enable
}
configure_unattended_upgrades() {
info "Configuring unattended upgrades..."
dpkg-reconfigure --priority=low unattended-upgrades
}
configure_apparmor() {
info "Enabling and starting AppArmor..."
systemctl enable apparmor
systemctl start apparmor
}
configure_auditd() {
info "Enabling and starting auditd..."
systemctl enable auditd
systemctl start auditd
}
#--- 5) SYSTEM SCANS & LOGGING ---------------------------------------#
run_malware_scans() {
info "Updating and running rkhunter checks..."
# Fix WEB_CMD configuration in rkhunter
local rkhunter_conf="/etc/rkhunter.conf"
if [[ -f "$rkhunter_conf" ]]; then
backup_file "$rkhunter_conf"
# Use /usr/bin/links -dump or comment out WEB_CMD if not needed
if command -v links >/dev/null 2>&1; then
sed -i 's|^WEB_CMD=.*|WEB_CMD="/usr/bin/links -dump"|' "$rkhunter_conf"
else
sed -i 's|^WEB_CMD=.*|# WEB_CMD disabled, no valid renderer|' "$rkhunter_conf"
fi
fi
# Update and initialize rkhunter
rkhunter --update
rkhunter --propupd # Save current system state as baseline
rkhunter --check
}
run_lynis() {
info "Running Lynis security audit..."
lynis audit system || true
}
configure_aide() {
info "Initializing AIDE (file integrity monitoring)..."
aideinit
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
}
#--- 6) USER & PERMISSIONS -------------------------------------------#
create_sudo_user() {
read -r -p "Enter new username: " new_user
if id "$new_user" &>/dev/null; then
warning "User '$new_user' already exists. Skipping creation."
else
adduser "$new_user"
usermod -aG sudo "$new_user"
info "New user '$new_user' added and granted sudo privileges."
fi
}
secure_file_permissions() {
info "Hardening file system permissions..."
chmod 700 /root
chmod -R go-rwx /etc/ssh
}
#--- 7) WRAP-UP ------------------------------------------------------#
display_system_info() {
info "Displaying system information..."
neofetch || true
}
cleanup() {
info "Cleaning up unnecessary packages..."
apt -y autoremove
apt clean
}
#--- MAIN ------------------------------------------------------------#
main() {
check_root # This one is mandatory to ensure the script runs as root
if confirm_exec "update_system"; then
update_system
fi
if confirm_exec "install_packages"; then
install_packages
fi
if confirm_exec "setup_ssh_keys"; then
setup_ssh_keys
fi
if confirm_exec "harden_ssh"; then
harden_ssh
fi
if confirm_exec "configure_fail2ban"; then
configure_fail2ban
fi
if confirm_exec "configure_sysctl"; then
configure_sysctl
fi
if confirm_exec "configure_firewall"; then
configure_firewall
fi
if confirm_exec "configure_unattended_upgrades"; then
configure_unattended_upgrades
fi
if confirm_exec "configure_apparmor"; then
configure_apparmor
fi
if confirm_exec "configure_auditd"; then
configure_auditd
fi
if confirm_exec "run_malware_scans"; then
run_malware_scans
fi
if confirm_exec "run_lynis"; then
run_lynis
fi
if confirm_exec "configure_aide"; then
configure_aide
fi
if confirm_exec "create_sudo_user"; then
create_sudo_user
fi
if confirm_exec "secure_file_permissions"; then
secure_file_permissions
fi
if confirm_exec "display_system_info"; then
display_system_info
fi
if confirm_exec "cleanup"; then
cleanup
fi
info "Setup complete. A system reboot is recommended."
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment