Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active February 5, 2024 18:34
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Potherca/fbfc656f62a91e67820019bc0aa64256 to your computer and use it in GitHub Desktop.
Save Potherca/fbfc656f62a91e67820019bc0aa64256 to your computer and use it in GitHub Desktop.
BASH scripts to go through all the steps to make a (VPS) server more secure.
📝️ This document is part of several gists related to installing things on OVH VPS:
All steps to a clean OVH VPS install
Script to make a VPS more secure(This Gist)
Scripts to install Potherca projects on OVH VPS

Securing a (Virtual Private) Server

In 2019 I moved various web-apps I have created to a VPS (hosted by OVH).

I strongly believe in automating things and making virtual setups easy to throw away/start again.

This project contains script(s) and files that make a fresh VPS more secure.

The script is meant to be run once directly after first login (as root) in a clean VPS.

⚠️ Please be aware that after the script has run it is impossible to log in as root! ⚠️

Quickstart

  1. Log in to the VPS
  2. Clone this repository
  3. Run the main script
git clone https://gist.github.com/fbfc656f62a91e67820019bc0aa64256.git secure-server
bash ./secure-server/secure-server.sh 'potherca' 'My $3cr3t P@$$w0rd'

Installation

To install this project, clone the repository:

git clone https://gist.github.com/fbfc656f62a91e67820019bc0aa64256.git secure-server

Usage

To use this project, run the main script.

The script requires one parameter, the name of the user to create.

Example:

bash ./secure-server/secure-server.sh 'potherca' 'My $3cr3t P@$$w0rd'

Details

To make the server more secure, the script does the following:

  1. Create a regular user (with restricted rights)
  2. Add the new user to the (newly created) group specifically for ssh-users
  3. Add the new user to the (already existing) group specifically for sudo users
  4. Setup SSH Daemon configuration (as advised by various reputable online sources)
  5. Regenerate Diffie-Hellman Moduli (used by SSH server for key exchange) and remove small (potentially unsafe) moduli
  6. Setup 2FA (Two Factor Authentication) using Google Authenticator PAM module
  7. Setup fail2ban to help mitigate DDOS attacks
  8. Remove the password associated with the "root" user

For fun it also adds a SSH banner.

The following advice was specifically not followed:

  • Re-generate the RSA and ED25519 keys
    Not needed as the script is run on a freshly installed VPS. This means the keys have just been generated. Re-generating does not have much benefit.

  • Remove /etc/ssh/ssh_host_* keys
    Instead, the HostKey setting is used to explicitly set which keys to use

  • Change the password associated with the "root" user
    The password is removed entirely, rather than changed.

  • Change the port for SSH
    The argument for changing the SSH port is to lessen the amount of hits to the standard port 22. However, from personal experience, I don't see any less port scans on the chnaged port. Also, changing the port means one has to remember which port SSH was changed to.

Sources

The following sources (in no particular order) were used to create this project:

My thanks also goes out to @mjrider for sanity checks.

License

This project has been created by Potherca and is licensed under a GPL-3.0+ License. (GNU General Public License v3.0 or later).

Copyright (C) 2019 Potherca

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

██▓███ ▒█████ ▄▄▄█████▓ ██░ ██ ▓█████ ██▀███ ▄████▄ ▄▄▄
▓██░ ██▒▒██▒ ██▒▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ▓██ ▒ ██▒▒██▀ ▀█ ▒████▄
▓██░ ██▓▒▒██░ ██▒▒ ▓██░ ▒░▒██▀▀██░▒███ ▓██ ░▄█ ▒▒▓█ ▄ ▒██ ▀█▄
▒██▄█▓▒ ▒▒██ ██░░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▒██▀▀█▄ ▒▓▓▄ ▄██▒░██▄▄▄▄██
▒██▒ ░ ░░ ████▓▒░ ▒██▒ ░ ░▓█▒░██▓░▒████▒░██▓ ▒██▒▒ ▓███▀ ░ ▓█ ▓██▒
▒▓▒░ ░ ░░ ▒░▒░▒░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░░ ▒▓ ░▒▓░░ ░▒ ▒ ░ ▒▒ ▓▒█░
░▒ ░ ░ ▒ ▒░ ░ ▒ ░▒░ ░ ░ ░ ░ ░▒ ░ ▒░ ░ ▒ ▒ ▒▒ ░
░░ ░ ░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░ ░ ░ ▒
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
# ==============================================================================
# This file makes use of version 0.9 config. It overrides settings from the
# default configuration in /etc/fail2ban/jail.conf
# ------------------------------------------------------------------------------
[default]
bantime = 900
findtime = 600
maxfailures = 3
[sshd]
enabled = true
maxretry = 3
[apache-noscript]
bantime = 43200
enabled = true
maxretry = 3
# ==============================================================================
#!/usr/bin/env bash
# ==============================================================================
# secure-server.sh
# ------------------------------------------------------------------------------
# Copyright (C) 2019 Potherca
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
# ==============================================================================
set -o errexit -o errtrace -o nounset -o pipefail
secure_server(){
if [ "$(id -u)" != 0 ]; then
echo "This script needs to be run as root." >&2
exit 1
fi
sUserName="${1?Two parameters required: <user-name> <password>}"
sPassword="${2?Two parameters required: <user-name> <password>}"
sPath="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
# ==========================================================================
# Setup users and user-groups
# ==========================================================================
# --------------------------------------------------------------------------
# Create a group for ssh-users
groupadd ssh-user
# --------------------------------------------------------------------------
# Create a regular user and add them to the sudo and ssh-user groups
useradd \
--create-home \
--comment '' \
--groups 'ssh-user,sudo' \
--password "$(openssl passwd -1 "${sPassword}")" \
"${sUserName}"
# ==========================================================================
# Install Applications
# ==========================================================================
# --------------------------------------------------------------------------
# Update the system
# --------------------------------------------------------------------------
apt-get update
apt-get upgrade
# --------------------------------------------------------------------------
# Install Fail2Ban as it protects against sshd brute-force attacks
# --------------------------------------------------------------------------
# Install google-authenticator to enable using 2FA (Two Factor Authentication)
# --------------------------------------------------------------------------
apt-get install \
-y \
sudo \
fail2ban \
libpam-google-authenticator
# --------------------------------------------------------------------------
# Setup 2FA (Two Factor Authentication) for provided user
sudo -u "${sUserName}" \
google-authenticator \
--disallow-reuse \
--emergency-codes=10 \
--force \
--qr-mode=none \
--rate-limit=3 \
--rate-time=30 \
--time-based \
--window-size=5
# ==========================================================================
# Copy/Create/Remove files
# ==========================================================================
# --------------------------------------------------------------------------
# Set up SSH banner
cp "${sPath}/banner.txt" /etc/motd
# --------------------------------------------------------------------------
# Setup sshd configuration
# --------------------------------------------------------------------------
# Backup the original sshd settings
mv /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
# Use the suggested sshd settings instead
cp "${sPath}/sshd.conf" /etc/ssh/sshd_config
# Make sure nothing is wrong with the changed SSH settings
sshd -t || {
echo "Please fix the problem stated above and run $0 again" >&2
exit 64
}
# --------------------------------------------------------------------------
# Setup Fail2Ban configuration
cp "${sPath}/fail2ban.conf" /etc/fail2ban/jail.local
# --------------------------------------------------------------------------
# Add the Google Authenticator to the PAM rule file for SSH
echo 'auth required pam_google_authenticator.so' >> /etc/pam.d/sshd
# --------------------------------------------------------------------------
# Regenerate Moduli used by SSH server for key exchange
ssh-keygen -G moduli-2048.candidates -b 2048
ssh-keygen -T moduli-2048 -f moduli-2048.candidates
mv moduli-2048 /etc/ssh/moduli
# --------------------------------------------------------------------------
# Remove small Diffie-Hellman moduli
awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe
mv /etc/ssh/moduli.safe /etc/ssh/moduli
# ==============================================================================
# Load the changed configuration by restarting services
# ==============================================================================
sudo service fail2ban restart
sudo service ssh restart
sudo systemctl reload sshd
# ==============================================================================
# If everything went well, lock the door behind us
# ==============================================================================
# --------------------------------------------------------------------------
# Clear the history
cat /dev/null > ~/.bash_history && history -c
# --------------------------------------------------------------------------
# Remove the password associated with the "root" user
echo 'root:*' | chpasswd -e
}
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
export -f secure_server
else
secure_server "${@}"
exit $?
fi
# ==============================================================================
# ==============================================================================
# For all config settings see: https://man.openbsd.org/sshd_config
# ==============================================================================
# ------------------------------------------------------------------------------
# Set to newest protocol
# ------------------------------------------------------------------------------
Protocol 2
# ------------------------------------------------------------------------------
# Disable Root
# ------------------------------------------------------------------------------
PermitRootLogin no
# ------------------------------------------------------------------------------
# Disconnect Idle Sessions
# ------------------------------------------------------------------------------
# Number of times to check before disconnecting
ClientAliveCountMax 2
# ------------------------------------------------------------------------------
# Number of seconds of inactivity after which to check client session
ClientAliveInterval 300
# ------------------------------------------------------------------------------
# Whitelist Users
# ------------------------------------------------------------------------------
AllowGroups ssh-user
# ------------------------------------------------------------------------------
# Limit number of login attempts
# ------------------------------------------------------------------------------
MaxAuthTries 3
# ------------------------------------------------------------------------------
# Check if the client connecting maps back to the same hostname and IP address.
# ------------------------------------------------------------------------------
# Only use this when you are sure your internal DNS is properly configured (HOW TO KNOW?)
# ------------------------------------------------------------------------------
# UseDNS yes
# ------------------------------------------------------------------------------
# Disable Password Authentication to force users to use SSH keys
# ------------------------------------------------------------------------------
# This will not work for Chromebook without extra work. It should also only be
# used AFTER the user has logged in with SSH only. HOW TO CHECK THIS?
# ------------------------------------------------------------------------------
# PasswordAuthentication no
# PubkeyAuthentication yes
# ------------------------------------------------------------------------------
# Use Google Authenticator for 2FA
# ------------------------------------------------------------------------------
ChallengeResponseAuthentication yes
UsePAM yes
# ------------------------------------------------------------------------------
# Banners
#
# Banner is shown before login (default is `/etc/issue.net`, path can be changed)
# PrintMotd (Message of the Day) is shown after login (from `/etc/motd`)
# ------------------------------------------------------------------------------
# Banner none
PrintMotd yes
# ------------------------------------------------------------------------------
# Change Hostkey Preference
# ------------------------------------------------------------------------------
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
# ------------------------------------------------------------------------------
# Restrict supported key exchange, cipher, and MAC algorithms
#
# The first two KexAlgorithms entries should be enough but some servers like
# Github and Heroku (sometimes) require SHA
# ------------------------------------------------------------------------------
# There are some contradicting instructions in online sources regarding these:
#
# KexAlgorithms (?) curve25519-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,
# MACs (?) hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
# ------------------------------------------------------------------------------
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com
#EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment