sysadmin checklist
disclaimer
just a personal checklist for "good enough" security on a new box, not a full hardening guide.
checklist
- system update
- install docker
- virtual memory overcommit
- firewall
- ssh config
- nonroot user
- fail2ban
- secure shared memory
- disable root login
- tailscale
system update
apt update -y
apt upgrade -y
apt install -y vim curl htop
# Configure 'needrestart' for auto-restart of services after upgrades
sed -i "/#\$nrconf{restart} = 'i';/s/.*/\$nrconf{restart} = 'a';/" /etc/needrestart/needrestart.conf
sed -i "s/#\$nrconf{kernelhints} = -1;/\$nrconf{kernelhints} = -1;/g" /etc/needrestart/needrestart.conf
install docker
# Update package list and install prerequisites
apt update -y
apt install -y ca-certificates curl gnupg
# Add Docker's official GPG key and set up repository
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker and Docker Compose plugins
apt update -y
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
virtual memory overcommit
sysctl vm.overcommit_memory=1
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
firewall
# Allow essential traffic for SSH, HTTP, and HTTPS
ufw allow ssh
ufw allow http
ufw allow https
# Uncomment to allow Redis and PostgreSQL traffic if needed
# ufw allow redis
# ufw allow postgres
# Enable UFW
ufw enable
ssh config
# Enable public key authentication, disable password-based login, and enforce other security settings
sed -i -e '/^\(#\|\)PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i -e '/^\(#\|\)PubkeyAuthentication/s/^.*$/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sed -i -e '/^\(#\|\)PermitEmptyPasswords/s/^.*$/PermitEmptyPasswords no/' /etc/ssh/sshd_config
if ! grep -q "^ChallengeResponseAuthentication" /etc/ssh/sshd_config; then
echo 'ChallengeResponseAuthentication no' >> /etc/ssh/sshd_config
else
sed -i -e '/^\(#\|\)ChallengeResponseAuthentication/s/^.*$/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config
fi
# Reload SSH service to apply configuration changes
echo 'Reloading ssh agent'
systemctl reload ssh
nonroot user
# Create a non-root user with sudo access
echo "Setup non-root user"
adduser --disabled-password --gecos "" nonroot
echo "nonroot ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# Configure SSH key authentication for the new user
AUTHORIZED_KEYS=$(cat ~/.ssh/authorized_keys)
sudo -H -u nonroot bash -c '
mkdir ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
'
sudo -H -u nonroot bash -c "echo '$AUTHORIZED_KEYS' >> ~/.ssh/authorized_keys"
# Add new user to Docker group
usermod -aG docker nonroot
fail2ban
# Install fail2ban to protect against brute-force attacks
echo "Setup fail2ban"
apt install -y fail2ban
# Configure fail2ban settings for SSH
cat <<EOF > /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 5
findtime = 600
bantime = 600
ignoreip = 127.0.0.1/8
logpath = /var/log/auth.log
EOF
# Restart fail2ban to apply configuration
systemctl restart fail2ban
secure shared memory
echo "Secure shared memory"
echo "tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0" >> /etc/fstab
disable root login
before disabling root login, copy your ssh pubkey from your workstation to the remote host, to not be locked out after next step :
ssh-copy-id -i ~/.ssh/id_rsa.pub root@remote
# Disable root login over SSH
echo "Disable root user login"
sed -i -e '/^\(#\|\)PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
# Reload SSH to apply root login restrictions
systemctl reload ssh