Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Rovel/3dfffe212708f8498fa30f24363ee573 to your computer and use it in GitHub Desktop.
Save Rovel/3dfffe212708f8498fa30f24363ee573 to your computer and use it in GitHub Desktop.
Set up a Ubuntu server to deploy Kamal 2.x Docker containers to, hardened security and production ready
#!/bin/bash
# Ubuntu 24.04 Server Hardening Script
set -euo pipefail
IFS=$'\n\t'
# --- Constants ---
REQUIRED_OS="Ubuntu"
REQUIRED_VERSION="24.04"
MIN_RAM_MB=1024
MIN_DISK_GB=20
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
print_message() { echo -e "${1}${2}${NC}"; }
print_error() { print_message "${RED}" "ERROR: $1"; }
print_success() { print_message "${GREEN}" "SUCCESS: $1"; }
check_root() { [[ $EUID -eq 0 ]] || { print_error "Run as root"; exit 1; }; }
check_os() {
[[ "$(lsb_release -is)" == "$REQUIRED_OS" ]] || { print_error "Requires $REQUIRED_OS"; exit 1; }
[[ "$(lsb_release -rs)" == "$REQUIRED_VERSION" ]] || { print_error "Requires $REQUIRED_VERSION"; exit 1; }
}
check_resources() {
(( $(free -m | awk '/^Mem:/{print $2}') >= MIN_RAM_MB )) || { print_error "Insufficient RAM"; exit 1; }
(( $(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//') >= MIN_DISK_GB )) || { print_error "Insufficient disk"; exit 1; }
}
trap 'print_error "Failed at line $LINENO"; exit 1' ERR
print_message "${YELLOW}" "Pre-flight checks..."
check_root
check_os
check_resources
print_message "${YELLOW}" "Updating system..."
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
print_message "${YELLOW}" "Installing security packages..."
DEBIAN_FRONTEND=noninteractive apt-get install -y \
ufw fail2ban auditd apparmor apparmor-utils aide rkhunter logwatch unattended-upgrades
print_message "${YELLOW}" "Configuring AppArmor..."
systemctl enable --now apparmor
print_message "${YELLOW}" "Initializing AIDE..."
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
print_message "${YELLOW}" "Configuring kernel parameters..."
cat <<EOF > /etc/sysctl.d/99-hardening.conf
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv4.tcp_syncookies = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.suid_dumpable = 0
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.perf_event_paranoid = 3
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2
kernel.yama.ptrace_scope = 2
EOF
sysctl --system
print_message "${YELLOW}" "Configuring SSH..."
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
systemctl reload ssh
print_message "${YELLOW}" "Configuring firewall..."
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw --force enable
print_message "${YELLOW}" "Configuring fail2ban..."
systemctl enable --now fail2ban
print_message "${YELLOW}" "Configuring auditd..."
systemctl enable --now auditd
print_message "${YELLOW}" "Configuring unattended-upgrades..."
cat <<EOF > /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"\${distro_id}:\${distro_codename}-security";
};
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
EOF
apt-get autoremove -y
apt-get clean
print_success "Hardening complete. Please reboot to apply all settings."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment