|
#!/usr/bin/env bash |
|
# install.sh |
|
# Purpose: Install Docker on Debian 12 headless machines and configure IPv6 settings. |
|
# Author: Troy Kelly |
|
# Email: [email protected] |
|
# Date: Monday, 30 September 2024 |
|
# Description: This script performs validation, installs required packages, configures IPv6, |
|
# removes legacy files, installs Docker if not already installed, performs necessary configurations, |
|
# generates a markdown report, and restarts the server upon successful completion. |
|
# Version: 1.1 |
|
|
|
set -euo pipefail |
|
|
|
# Error handling function |
|
error_handler() { |
|
local EXIT_CODE=$? |
|
echo "An error occurred during the installation. Exit code: $EXIT_CODE" |
|
generate_report "Failed" |
|
exit $EXIT_CODE |
|
} |
|
|
|
trap error_handler ERR |
|
|
|
# Signal handling for interruption |
|
trap "echo 'Script interrupted.'; exit 1" INT TERM |
|
|
|
# Array to keep track of completed steps |
|
declare -a COMPLETED_STEPS=() |
|
|
|
# Function to generate installation report |
|
generate_report() { |
|
local STATUS="$1" |
|
local REPORT_FILE="install_report.md" |
|
echo "Generating installation report at $REPORT_FILE" |
|
|
|
{ |
|
echo "# Installation Report" |
|
echo |
|
echo "Date: $(date)" |
|
echo |
|
echo "Installation Status: **$STATUS**" |
|
echo |
|
echo "## Steps Completed:" |
|
echo |
|
for STEP in "${COMPLETED_STEPS[@]}"; do |
|
echo "- [x] $STEP" |
|
done |
|
echo |
|
if [[ "$STATUS" == "Failed" ]]; then |
|
echo "## Error Details:" |
|
echo |
|
echo "**An error occurred during the installation. Please check the console output for details.**" |
|
fi |
|
} >"$REPORT_FILE" |
|
|
|
echo "Installation report generated at $REPORT_FILE" |
|
} |
|
|
|
# Ensure the script is not running as root |
|
if [[ "$EUID" -eq 0 ]]; then |
|
echo "This script must not be run as root. Please run as a regular user with sudo privileges." |
|
exit 1 |
|
fi |
|
COMPLETED_STEPS+=("Verified the script is not running as root.") |
|
|
|
# Ensure the user has sudo privileges without password prompt |
|
if sudo -n true 2>/dev/null; then |
|
echo "User has sudo privileges." |
|
else |
|
echo "Sudo password is required. Please configure sudo to not require a password for this user to run this script unattended." |
|
exit 1 |
|
fi |
|
COMPLETED_STEPS+=("Confirmed user has sudo privileges without password prompt.") |
|
|
|
# Update package lists and perform full upgrade |
|
echo "Updating package lists..." |
|
sudo apt-get update |
|
COMPLETED_STEPS+=("Updated package lists.") |
|
|
|
echo "Performing full upgrade..." |
|
sudo DEBIAN_FRONTEND=noninteractive apt-get -y full-upgrade |
|
COMPLETED_STEPS+=("Performed full system upgrade.") |
|
|
|
# Ensure required packages are installed |
|
REQUIRED_PACKAGES=( |
|
sipcalc |
|
gpg |
|
ca-certificates |
|
curl |
|
wget |
|
vim |
|
jq |
|
) |
|
|
|
echo "Ensuring required packages are installed..." |
|
for pkg in "${REQUIRED_PACKAGES[@]}"; do |
|
if dpkg -s "$pkg" >/dev/null 2>&1; then |
|
echo "Package $pkg is already installed." |
|
else |
|
echo "Installing package $pkg..." |
|
sudo apt-get install -y "$pkg" |
|
fi |
|
done |
|
COMPLETED_STEPS+=("Installed required packages: ${REQUIRED_PACKAGES[*]}.") |
|
|
|
# Determine the default network interface |
|
DEFAULT_INTERFACE=$(ip route | awk '/default/ {print $5}' | head -n 1) |
|
|
|
if [[ -z "$DEFAULT_INTERFACE" ]]; then |
|
echo "Unable to determine default network interface." |
|
exit 1 |
|
else |
|
echo "Default network interface is $DEFAULT_INTERFACE." |
|
fi |
|
COMPLETED_STEPS+=("Identified default network interface: $DEFAULT_INTERFACE.") |
|
|
|
# Backup /etc/network/interfaces |
|
echo "Backing up /etc/network/interfaces to /etc/network/interfaces.bak..." |
|
sudo cp /etc/network/interfaces /etc/network/interfaces.bak |
|
COMPLETED_STEPS+=("Backed up /etc/network/interfaces.") |
|
|
|
# Configure IPv6 settings |
|
echo "Configuring IPv6 settings for $DEFAULT_INTERFACE..." |
|
INTERFACE_CONFIG_EXISTS=$(grep -A5 "iface $DEFAULT_INTERFACE inet6 dhcp" /etc/network/interfaces || true) |
|
|
|
if [[ -n "$INTERFACE_CONFIG_EXISTS" ]]; then |
|
echo "Existing IPv6 configuration found for $DEFAULT_INTERFACE. Updating configuration." |
|
sudo sed -i "/iface $DEFAULT_INTERFACE inet6 dhcp/,/^\s*$/d" /etc/network/interfaces |
|
else |
|
echo "No IPv6 configuration found for $DEFAULT_INTERFACE. Adding configuration." |
|
fi |
|
|
|
sudo tee -a /etc/network/interfaces >/dev/null <<EOF |
|
iface $DEFAULT_INTERFACE inet6 dhcp |
|
accept_ra 2 |
|
request_prefix 1 |
|
autoconf 1 # Enable automatic configuration of addresses from Router Advertisements |
|
forwarding 0 |
|
EOF |
|
COMPLETED_STEPS+=("Configured IPv6 settings for $DEFAULT_INTERFACE.") |
|
|
|
# Remove legacy files if they exist |
|
LEGACY_FILES=( |
|
"/etc/sysctl.d/99-ipv6.conf" |
|
"/etc/systemd/system/dhclient6-pd.service" |
|
"/etc/systemd/system/docker.service.d/ipv6.conf" |
|
"/etc/docker/ipv6.prefix" |
|
) |
|
|
|
echo "Checking for and removing legacy files if they exist..." |
|
for FILE in "${LEGACY_FILES[@]}"; do |
|
if [[ -f "$FILE" ]]; then |
|
echo "Removing legacy file $FILE..." |
|
sudo rm -f "$FILE" |
|
COMPLETED_STEPS+=("Removed legacy file $FILE.") |
|
else |
|
echo "Legacy file $FILE does not exist. Skipping." |
|
fi |
|
done |
|
|
|
# Check if Docker is already installed |
|
if command -v docker >/dev/null 2>&1; then |
|
echo "Docker is already installed. Skipping Docker installation steps." |
|
COMPLETED_STEPS+=("Docker is already installed. Skipped Docker installation.") |
|
else |
|
# Install Docker |
|
echo "Installing Docker..." |
|
|
|
echo "Creating /etc/apt/keyrings directory..." |
|
sudo install -m 0755 -d /etc/apt/keyrings |
|
|
|
echo "Downloading Docker GPG key..." |
|
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc |
|
|
|
echo "Setting permissions for Docker GPG key..." |
|
sudo chmod a+r /etc/apt/keyrings/docker.asc |
|
|
|
echo "Adding Docker repository..." |
|
OS_VERSION_CODENAME=$(source /etc/os-release && echo "$VERSION_CODENAME") |
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $OS_VERSION_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null |
|
|
|
echo "Updating package lists..." |
|
sudo apt-get update |
|
|
|
echo "Installing Docker packages..." |
|
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin |
|
COMPLETED_STEPS+=("Installed Docker packages.") |
|
|
|
# Ensure the current user is a member of the docker group |
|
if groups "$USER" | grep -q '\bdocker\b'; then |
|
echo "User $USER is already in the docker group." |
|
else |
|
echo "Adding user $USER to the docker group..." |
|
sudo usermod -aG docker "$USER" |
|
fi |
|
COMPLETED_STEPS+=("Ensured user $USER is in the docker group.") |
|
|
|
# Enable Docker services |
|
echo "Enabling Docker services..." |
|
sudo systemctl enable docker.service |
|
sudo systemctl enable containerd.service |
|
COMPLETED_STEPS+=("Enabled Docker services.") |
|
fi |
|
|
|
# Retrieve br_netfilter.conf |
|
echo "Retrieving br_netfilter.conf..." |
|
sudo curl -fsSL "https://gist.githubusercontent.com/troykelly/c9537a5cd381d4da6c21e1ae59cbecc9/raw/br_netfilter.conf" -o /etc/modules-load.d/br_netfilter.conf |
|
COMPLETED_STEPS+=("Retrieved br_netfilter.conf.") |
|
|
|
# Retrieve docker-ipv6 hook script |
|
echo "Retrieving docker-ipv6 hook script..." |
|
sudo curl -fsSL "https://gist.githubusercontent.com/troykelly/c9537a5cd381d4da6c21e1ae59cbecc9/raw/docker-ipv6" -o /etc/dhcp/dhclient-enter-hooks.d/docker-ipv6 |
|
COMPLETED_STEPS+=("Retrieved docker-ipv6 hook script.") |
|
|
|
# Make docker-ipv6 hook script executable |
|
echo "Making docker-ipv6 hook script executable..." |
|
sudo chmod +x /etc/dhcp/dhclient-enter-hooks.d/docker-ipv6 |
|
COMPLETED_STEPS+=("Made docker-ipv6 hook script executable.") |
|
|
|
# Retrieve Docker service override configuration |
|
echo "Retrieving Docker service override configuration..." |
|
sudo mkdir -p /etc/systemd/system/docker.service.d |
|
sudo curl -fsSL "https://gist.githubusercontent.com/troykelly/c9537a5cd381d4da6c21e1ae59cbecc9/raw/override.conf" -o /etc/systemd/system/docker.service.d/override.conf |
|
COMPLETED_STEPS+=("Retrieved Docker service override configuration.") |
|
|
|
# Generate installation report and restart the server |
|
echo "Installation completed successfully." |
|
generate_report "Successful" |
|
|
|
echo "The system will restart in 10 seconds..." |
|
sleep 10 |
|
sudo reboot |