papyri/md/debian_server_setup.md
2024-03-20 11:40:22 -05:00

7.8 KiB

Debian Server Setup

Contents

Server Installation

Install Debian using the Minimal setup method, add the SSH server option during the final steps on the installation. This is the default image delivered from many cloud providers; it may use the default hostname localhost - if desired, set a new one:

hostnamectl set-hostname myhostname

Ensure the hostname resolves locally - it does not have to be 127.0.0.1 (localhost) nor a FQDN, for example this works:

127.0.0.1  localhost
127.0.1.1  myhostname

Adjust as needed based on how /etc/hosts is already configured from the installation.

Server User Setup

Use a very secure password - at a minimum use pwgen -sB 15, strong password security encouraged!

Set up a non-root user and add to the sudo group, then add a password. Use this user for SSH access and become root once logged in with sudo; if you have used SSH keys to log in as root, copy to this new user's setup as well if needed:

apt-get update
apt-get install sudo

export MYUSER="frankthetank"
useradd -m -d /home/${MYUSER} -s /bin/bash -g users -G sudo ${MYUSER}
passwd ${MYUSER}

If you are unable to use ssh-copy-id from your workstation to add a new SSH key, perform the work manually:

mkdir /home/${MYUSER}/.ssh
cp /root/.ssh/authorized_keys /home/${MYUSER}/.ssh/
chmod 0700 /home/${MYUSER}/.ssh
chmod 0600 /home/${MYUSER}/.ssh/authorized_keys
chown -R ${MYUSER}:users /home/${MYUSER}/.ssh

SSH in as this user and test sudo several times - log out completely between tests

Disable root Login

If the above is successful and you are capable of gaining full root privileges via the non-root SSH session using sudo, now disable root logins in SSH from the outside world for an additional security layer. The root account still remains usable, just not via direct SSH access.

The task is to set PermitRootLogin no - the setting varies from one provider to another, sometimes it's already set (either yes or no), sometimes it's commented out. This small scriptlet should handle these 2 most common cases, be careful and investigate for yourself:

_SCFG="/etc/ssh/sshd_config"
if $(grep -iEq '^PermitRootLogin[[:space:]]+yes' "${_SCFG}"); then
  sed -i.bak -e 's/^PermitRootLogin.*/PermitRootLogin no/gi' "${_SCFG}"
else
  sed -i.bak -e 's/^#PermitRootLogin.*/PermitRootLogin no/gi' "${_SCFG}"
fi

After confirming the change is correct, restart the SSH core daemon (it will not log you out):

systemctl restart sshd

Test logging in again to ensure the changes are as expected. Do not log out of the active, working SSH session as root until you've confirmed in another session you can log in as your non-root user and still gain sudo to root.

Server Hardening

1. The Debian default vimrc (set mouse=a, /usr/share/vim/vim80/defaults.vim) messes up middle-mouse click paste when remote via SSH, override the setting to just disable the mouse:

echo 'set mouse=' >> ~/.vimrc

2. Install a few basic packages to make life a little nicer; typically the minimal install / cloud instances are stripped down and need a few things added, both for security and ease of use. Adjust as desired:

apt-get update
echo "iptables-persistent iptables-persistent/autosave_v4 boolean true" | debconf-set-selections
echo "iptables-persistent iptables-persistent/autosave_v6 boolean true" | debconf-set-selections
echo "unattended-upgrades unattended-upgrades/enable_auto_updates boolean true" | debconf-set-selections
apt-get install sysstat unattended-upgrades iptables-persistent man less vim rsync bc net-tools git strace

The smem package will pull in a lot of X dependencies due to an embedded recommendation, install it while disabling that feature. This utility can be used to quickly query memory usage (including swap) on the memory constrained cloud server:

apt-get install smem --no-install-recommends

3. Enable journald to store logs on disk instead of just RAM. By default, the journald system is in automatic mode - on boot it will create the ephemeral tmpfs /run out of RAM, but will only transition to storing the journal on disk (out of RAM) if this directory exists. (done in Debian 11+ by the installer)

# Debian 10 and earlier
mkdir /var/log/journal

4. Enable sysstat for ongoing statistics capture of your instance (use sar to view):

sed -i.bak -e 's|^ENABLED=".*"|ENABLED="true"|g' /etc/default/sysstat

5. Enable unattended-upgrades to ensure that all Security updates are applied:

cat << 'EOF' > /etc/apt/apt.conf.d/02periodic
APT::Periodic::Enable "1";
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "5";
APT::Periodic::Unattended-Upgrade "1";
EOF

6. Enable the basic iptables rules to allow only port 22:

cat << 'EOF' > /etc/iptables/rules.v4
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
EOF

cat << 'EOF' > /etc/iptables/rules.v6
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
COMMIT
EOF

7. Add a bit of swap if needed - using swap is not bad in and of itself, the Linux kernel will attempt to cache it's small bits of data if available. A cloud instance may not be delivered with any swap configured.

# 128M swap file
dd if=/dev/zero of=/swap.file bs=1024 count=128000
chmod 0600 /swap.file
mkswap /swap.file
echo '/swap.file none swap defaults 0 0' >> /etc/fstab
swapon /swap.file

8. Finally, ensure all the services are enabled and apply all outstanding updates; reboot as needed for a new kernel. If you don't reboot here, you'll need to service foo restart each one individually (just reboot, it's easier):

systemctl disable remote-fs.target rsync.service
systemctl enable sysstat unattended-upgrades netfilter-persistent

apt-get full-upgrade -y

reboot

fail2ban Setup

Recommended: configure fail2ban to keep an eye on the SSH port for brute force attacks.

Note

: fail2ban tends to consume a fair amount of memory the longer it runs; if the cloud server is memory constrained, you may wish to skip this step or disable the service later. Use smem to monitor it periodically.

apt-get install fail2ban sqlite3

cat << 'EOF' > /etc/fail2ban/jail.local
[DEFAULT]
ignoreip  = 127.0.0.1/8
bantime   = 3600
maxretry  = 3
backend   = auto
destemail = root@localhost
EOF

systemctl enable --now fail2ban

Additionally, add a weekly cron task to purge the database of old IPs (bug in 0.9.x series) and to restart the daemon to free up it's RAM usage:

cat << 'EOF' > /etc/fail2ban/dbpurge.sql
delete from bans where timeofban <= strftime('%s', date('now', '-7 days'));
vacuum;
.quit
EOF

cat << 'EOF' > /etc/cron.weekly/f2b-cleanup
#!/bin/sh
if [ -x /usr/bin/sqlite3 ]; then
  sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 < /etc/fail2ban/dbpurge.sql
fi
systemctl restart fail2ban.service
EOF

chown root:root /etc/cron.weekly/f2b-cleanup
chmod 0755 /etc/cron.weekly/f2b-cleanup