Compare commits

..

1 Commits

Author SHA1 Message Date
Nick Hepler
27237a866b Enhance UX and add error handling to the system setup script. 2024-11-04 21:48:28 -05:00

341
setup.sh
View File

@ -1,28 +1,23 @@
#!/bin/bash #!/bin/bash
#
# Script to perform system maintenance on a RHEL-based Linux system. # Script to update a RHEL-based Linux system, set the timezone, change the hostname,
# # add a limited user account, modify sshd_config settings, and optionally install Docker CE
# This script:
# - Updates package manager and installed packages
# - Sets the system timezone based on geolocation or user input
# - Changes the system hostname and updates /etc/hosts
# - Creates a limited user account and modifies SSH settings
# - Optionally installs Docker CE
#
# Prerequisites:
# - The script must be run as root or with sudo privileges
#
# Usage:
# - Run the script directly on the system or via SSH.
# - Respond to prompts as required during the script execution.
# Variables # Variables
timezone="America/New_York"
sshd_config="/etc/ssh/sshd_config" sshd_config="/etc/ssh/sshd_config"
docker_installed=false docker_installed=false
# Function to prompt for hostname # Function to prompt for hostname with validation
prompt_for_hostname() { prompt_for_hostname() {
read -p "Please enter the desired hostname: " hostname while true; do
read -p "Please enter the desired hostname: " hostname
if [[ -z "$hostname" ]]; then
echo "Hostname cannot be empty. Please try again."
else
break
fi
done
} }
# Function to add hostname and IP to /etc/hosts # Function to add hostname and IP to /etc/hosts
@ -30,7 +25,7 @@ update_hosts_file() {
local ip_address local ip_address
ip_address=$(hostname -I | awk '{print $1}') ip_address=$(hostname -I | awk '{print $1}')
echo "Updating /etc/hosts with IP $ip_address and hostname $hostname..." echo "Updating /etc/hosts with IP $ip_address and hostname $hostname..."
# Check if the entry already exists # Check if the entry already exists
if grep -q "$ip_address" /etc/hosts; then if grep -q "$ip_address" /etc/hosts; then
echo "Entry for $ip_address already exists in /etc/hosts." echo "Entry for $ip_address already exists in /etc/hosts."
@ -41,22 +36,33 @@ update_hosts_file() {
fi fi
} }
# Function to prompt for Docker installation # Function to prompt for Docker installation with validation
prompt_for_docker_install() { prompt_for_docker_install() {
read -p "Would you like to install Docker CE? (y/n): " install_docker while true; do
if [[ "$install_docker" =~ ^[Yy]$ ]]; then read -p "Would you like to install Docker CE? (y/n): " install_docker
install_docker case "$install_docker" in
else [Yy]*) install_docker ;;
echo "Skipping Docker installation." [Nn]*) echo "Skipping Docker installation."; break ;;
fi *) echo "Invalid input. Please enter 'y' or 'n'." ;;
esac
done
} }
# Function to install Docker # Function to install Docker
install_docker() { install_docker() {
echo "Installing Docker CE..." echo "Installing Docker CE..."
curl -fsSL https://get.docker.com -o get-docker.sh curl -fsSL https://get.docker.com -o get-docker.sh
if [ $? -ne 0 ]; then
echo "Error downloading Docker installation script."
exit 1
fi
sh get-docker.sh sh get-docker.sh
if [ $? -ne 0 ]; then
echo "Error installing Docker."
exit 1
fi
# Start and enable Docker service # Start and enable Docker service
systemctl start docker systemctl start docker
systemctl enable docker systemctl enable docker
@ -64,23 +70,21 @@ install_docker() {
usermod -aG docker "$username" usermod -aG docker "$username"
echo "User $username added to the docker group." echo "User $username added to the docker group."
# Clean up get-docker.sh
rm -f get-docker.sh
} }
# Function to create a limited user account # Function to create a limited user account with validation
create_user_account() { create_user_account() {
read -p "Please enter the username for the new user account: " username while true; do
read -p "Please enter the username for the new user account: " username
if [[ -z "$username" ]]; then
echo "Username cannot be empty. Please try again."
else
break
fi
done
read -sp "Please enter the password for the new user account: " password read -sp "Please enter the password for the new user account: " password
echo echo
read -sp "Please confirm the password: " password_confirm
echo
if [ "$password" != "$password_confirm" ]; then
echo "Passwords do not match. Exiting."
exit 1
fi
# Create the user and add to the wheel group # Create the user and add to the wheel group
if id "$username" &>/dev/null; then if id "$username" &>/dev/null; then
@ -92,177 +96,116 @@ create_user_account() {
fi fi
} }
# Check if the script is run as root # Function to check if running as root
if [ "$(id -u)" -ne 0 ]; then check_root() {
echo "This script must be run as root. Please use sudo or switch to root." if [ "$(id -u)" -ne 0 ]; then
exit 1 echo "This script must be run as root. Please use sudo or switch to root."
fi exit 1
fi
# Update the package manager
echo "Updating package manager..."
if command -v dnf &> /dev/null; then
dnf -y makecache
elif command -v yum &> /dev/null; then
yum -y makecache
else
echo "Neither dnf nor yum found. This script only works on RHEL-based distributions."
exit 1
fi
# Upgrade installed packages
echo "Upgrading installed packages..."
if command -v dnf &> /dev/null; then
dnf -y upgrade
elif command -v yum &> /dev/null; then
yum -y update
fi
# Change the timezone
# Function to set the timezone to UTC in case of an error
set_utc_timezone() {
echo "Error occurred while determining the timezone. Falling back to UTC."
timedatectl set-timezone UTC
} }
# Function to get the timezone from the ipinfo.io API # Function to update package manager cache
get_timezone_from_api() { update_package_manager() {
# Fetch geolocation information using the ipinfo.io API echo "Updating package manager..."
response=$(curl -s https://ipinfo.io) if command -v dnf &> /dev/null; then
dnf -y makecache
# Check if the curl command succeeded and the response contains the 'timezone' field elif command -v yum &> /dev/null; then
if [ $? -eq 0 ] && echo "$response" | grep -q "timezone"; then yum -y makecache
# Extract the timezone directly from the JSON response else
timezone=$(echo "$response" | jq -r '.timezone') echo "Neither dnf nor yum found. This script only works on RHEL-based distributions."
exit 1
echo "Detected timezone: $timezone" fi
return 0
else
set_utc_timezone
return 1
fi
} }
# Function to prompt the user to choose a timezone # Function to upgrade installed packages
prompt_for_timezone() { upgrade_packages() {
echo "" echo "Upgrading installed packages..."
echo "Choose a timezone option:" if command -v dnf &> /dev/null; then
echo "1) Use the detected timezone ($1)" dnf -y upgrade
echo "2) Use UTC" elif command -v yum &> /dev/null; then
echo "3) Enter a custom timezone" yum -y update
fi
# Read user choice
read -p "Enter the number corresponding to your choice: " choice
case "$choice" in
1)
echo "You chose to use the detected timezone: $1"
timedatectl set-timezone "$1"
;;
2)
echo "You chose to use UTC."
timedatectl set-timezone UTC
;;
3)
# Ask for a custom timezone
read -p "Enter your preferred timezone (e.g., Europe/London, America/New_York): " custom_timezone
if timedatectl list-timezones | grep -q "$custom_timezone"; then
timedatectl set-timezone "$custom_timezone"
else
echo "Invalid timezone. Falling back to UTC."
timedatectl set-timezone UTC
fi
;;
*)
echo "Invalid choice. Falling back to UTC."
timedatectl set-timezone UTC
;;
esac
} }
# Main script execution starts here # Function to change the timezone
echo "Attempting to detect and set the timezone..." set_timezone() {
echo "Setting timezone to $timezone..."
timedatectl set-timezone "$timezone"
}
# Try to get the detected timezone from the API # Function to change the hostname
if get_timezone_from_api; then set_hostname() {
# If the timezone was successfully detected, prompt the user for their choice prompt_for_hostname
prompt_for_timezone "$timezone" echo "Setting hostname to $hostname..."
else hostnamectl set-hostname "$hostname"
# If no timezone was detected, ask the user to fall back to UTC }
echo "Unable to detect timezone. Falling back to UTC."
timedatectl set-timezone UTC
fi
# Change the hostname # Function to modify sshd_config
prompt_for_hostname modify_sshd_config() {
echo "Setting hostname to $hostname..." echo "Modifying SSH configuration..."
hostnamectl set-hostname "$hostname" if [ -f "$sshd_config" ]; then
# Set PermitRootLogin to no
sed -i 's/^PermitRootLogin .*/PermitRootLogin no/' "$sshd_config" || echo "PermitRootLogin no" >> "$sshd_config"
# Update /etc/hosts # Set PasswordAuthentication to no
if grep -q '^#PasswordAuthentication' "$sshd_config"; then
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' "$sshd_config"
else
sed -i 's/^PasswordAuthentication .*/PasswordAuthentication no/' "$sshd_config" || echo "PasswordAuthentication no" >> "$sshd_config"
fi
# Ensure AddressFamily inet is set
if grep -q '^#AddressFamily' "$sshd_config"; then
sed -i 's/^#AddressFamily.*/AddressFamily inet/' "$sshd_config"
else
sed -i 's/^AddressFamily .*/AddressFamily inet/' "$sshd_config" || echo "AddressFamily inet" >> "$sshd_config"
fi
else
echo "sshd_config file not found. Exiting."
exit 1
fi
}
# Function to restart SSH service
restart_ssh() {
echo "Restarting SSH service..."
systemctl restart sshd
}
# Function to wait for SSH key copy
wait_for_key_copy() {
echo "Waiting for your public key to be copied..."
while true; do
if [ -s "/home/$username/.ssh/authorized_keys" ]; then
echo "Public key has been successfully copied."
break
fi
sleep 2
done
}
# Function to clean up unused packages
cleanup() {
echo "Cleaning up..."
if command -v dnf &> /dev/null; then
dnf -y autoremove
elif command -v yum &> /dev/null; then
yum -y autoremove
fi
}
# Main execution
check_root
update_package_manager
upgrade_packages
set_timezone
set_hostname
update_hosts_file update_hosts_file
# Create a limited user account
create_user_account create_user_account
modify_sshd_config
# Modify sshd_config restart_ssh
echo "Modifying SSH configuration..." wait_for_key_copy
if [ -f "$sshd_config" ]; then
# Set PermitRootLogin to no
if ! grep -q "^PermitRootLogin" "$sshd_config"; then
echo "PermitRootLogin no" >> "$sshd_config"
else
sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' "$sshd_config"
fi
# Set PasswordAuthentication to no
if grep -q '^#PasswordAuthentication' "$sshd_config"; then
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' "$sshd_config"
else
sed -i 's/^PasswordAuthentication .*/PasswordAuthentication no/' "$sshd_config" || echo "PasswordAuthentication no" >> "$sshd_config"
fi
# Ensure AddressFamily inet is set
if grep -q '^#AddressFamily' "$sshd_config"; then
sed -i 's/^#AddressFamily.*/AddressFamily inet/' "$sshd_config"
else
sed -i 's/^AddressFamily .*/AddressFamily inet/' "$sshd_config" || echo "AddressFamily inet" >> "$sshd_config"
fi
else
echo "sshd_config file not found. Exiting."
exit 1
fi
# Get the IP address of the machine
ip_address=$(hostname -I | awk '{print $1}')
# Prompt the user to copy their public key
echo "Please copy your public SSH key to the server using the following command:"
echo "ssh-copy-id $username@$ip_address"
# Wait until the authorized_keys file is no longer empty
echo "Waiting for your public key to be copied..."
while true; do
if [ -s "/home/$username/.ssh/authorized_keys" ]; then
echo "Public key has been successfully copied."
break
fi
sleep 2
done
# Restart SSH service to apply changes
echo "Restarting SSH service..."
systemctl restart sshd
# Prompt for Docker installation
prompt_for_docker_install prompt_for_docker_install
cleanup
# Clean up echo "System update complete! Timezone set to $timezone, hostname set to $hostname, limited user created, sshd_config modified, and Docker installation completed if selected."
echo "Cleaning up..."
if command -v dnf &> /dev/null; then
dnf -y autoremove
elif command -v yum &> /dev/null; then
yum -y autoremove
fi
echo "System update complete! Timezone set to ${timezone:-UTC}, hostname set to $hostname, limited user created, sshd_config modified, and Docker installation completed if selected."