1#!/bin/bash
2
3# This script automates the initial setup and hardening of a new Debian-based server.
4# It must be run as root.
5#
6# The script will:
7# 1. Create a new sudo user.
8# 2. Move the root SSH key to the new user.
9# 3. Harden the SSH server configuration.
10# 4. Install bat, eza, Docker, Caddy, and chrony for time synchronization.
11
12# --- Configuration ---
13readonly USERNAME="finxol"
14# Define a temporary password. This will be immediately expired.
15# WARNING: This password will be stored in the script file and potentially
16# in your shell history. This is an acceptable risk for a brand new server
17# where the password will be changed upon first login.
18readonly TEMP_PASS="password"
19
20# --- Script Execution ---
21
22# Exit immediately if a command exits with a non-zero status.
23set -e
24# Treat unset variables as an error.
25set -u
26# Ensure that pipelines return the exit status of the last command to fail.
27set -o pipefail
28
29# --- Helper Functions ---
30log() {
31 echo
32 echo "▶ $1"
33 echo "--------------------------------------------------"
34}
35
36# --- Pre-flight Checks ---
37if [ "$(id -u)" -ne 0 ]; then
38 echo "This script must be run as root." >&2
39 exit 1
40fi
41
42# --- User and Sudo Setup ---
43log "Creating user '$USERNAME' and granting sudo privileges"
44
45# Create a new user without an interactive password prompt.
46adduser --disabled-password --gecos "" "$USERNAME"
47
48# Programmatically set the temporary password for the new user.
49echo "$USERNAME:$TEMP_PASS" | chpasswd
50echo "Temporary password has been set for '$USERNAME'."
51
52# Force the user to change their password on the next login.
53chage -d 0 "$USERNAME"
54
55# Add the new user to the 'sudo' group to grant administrative privileges.
56usermod -aG sudo "$USERNAME"
57echo "User '$USERNAME' created and added to the sudo group."
58# --- SSH Key Migration ---
59log "Migrating SSH key from root to '$USERNAME'"
60# Create the .ssh directory for the new user if it doesn't exist.
61mkdir -p "/home/$USERNAME/.ssh"
62
63# Move the root user's authorized_keys file to the new user's .ssh directory.
64mv /root/.ssh/authorized_keys "/home/$USERNAME/.ssh/authorized_keys"
65
66# Set the correct ownership and permissions for the .ssh directory and its contents.
67chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/.ssh"
68chmod 700 "/home/$USERNAME/.ssh"
69chmod 600 "/home/$USERNAME/.ssh/authorized_keys"
70echo "SSH key successfully migrated."
71
72# --- SSH Server Hardening ---
73log "Hardening SSH server configuration"
74readonly SSHD_CONFIG="/etc/ssh/sshd_config"
75
76# A function to safely set a parameter in sshd_config.
77# It comments out any existing instance of the key and appends the new setting.
78set_ssh_config() {
79 local key="$1"
80 local value="$2"
81
82 # Comment out any existing lines with the key to deactivate them.
83 # The -E flag enables extended regular expressions for the '+' quantifier.
84 sed -i -E "s/^[[:space:]]*#?[[:space:]]*($key)([[:space:]]+.*)?$/#\1\2/g" "$SSHD_CONFIG"
85
86 # Append the new, correct setting to the end of the file.
87 echo "$key $value" >> "$SSHD_CONFIG"
88}
89
90# --- Apply Hardening Rules ---
91# Note: We are now using a function to ensure settings are applied correctly,
92# preventing issues with duplicate or conflicting rules.
93
94set_ssh_config "UsePAM" "yes"
95set_ssh_config "PasswordAuthentication" "no"
96set_ssh_config "KbdInteractiveAuthentication" "no"
97
98set_ssh_config "PermitRootLogin" "no"
99set_ssh_config "PermitEmptyPasswords" "no"
100set_ssh_config "X11Forwarding" "no"
101set_ssh_config "AllowAgentForwarding" "no"
102
103# --- Custom Hardening Settings ---
104set_ssh_config "ClientAliveInterval" "300"
105set_ssh_config "ClientAliveCountMax" "2"
106set_ssh_config "LoginGraceTime" "60"
107set_ssh_config "MaxAuthTries" "3"
108set_ssh_config "MaxSessions" "4"
109
110# Validate the new sshd_config and restart the SSH service to apply changes.
111sshd -t && systemctl restart sshd
112echo "SSH server hardened and restarted."
113
114# --- Package Installation ---
115log "Updating package lists and installing applications"
116apt-get update
117
118# Install bat (a cat clone with syntax highlighting)
119apt-get install -y bat
120# On Debian/Ubuntu, the binary can be named 'batcat'. Create a symlink if needed.
121if ! command -v bat &>/dev/null && command -v batcat &>/dev/null; then
122 ln -s /usr/bin/batcat /usr/bin/bat
123fi
124
125# Install eza (a modern replacement for ls)
126apt-get install -y gpg
127mkdir -p /etc/apt/keyrings
128wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc |
129 gpg --dearmor -o /etc/apt/keyrings/gierens.gpg
130echo "deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main" |
131 tee /etc/apt/sources.list.d/gierens.list
132chmod 644 /etc/apt/keyrings/gierens.gpg /etc/apt/sources.list.d/gierens.list
133apt-get update
134apt-get install -y eza
135
136# Install Docker Engine
137apt-get install -y ca-certificates curl
138install -m 0755 -d /etc/apt/keyrings
139curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
140chmod a+r /etc/apt/keyrings/docker.asc
141
142echo \
143 "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
144 $(. /etc/os-release && echo "$VERSION_CODENAME") stable" |
145 tee /etc/apt/sources.list.d/docker.list >/dev/null
146apt-get update
147apt-get install -y docker-ce docker-ce-cli containerd.io \
148 docker-buildx-plugin docker-compose-plugin
149
150# Add the new user to the 'docker' group to allow running Docker without sudo.
151# The '|| true' prevents the script from failing if the group already exists.
152groupadd docker || true
153usermod -aG docker "$USERNAME"
154echo "Docker installed and '$USERNAME' added to the docker group."
155
156# Install Caddy server
157sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
158curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
159curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
160chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
161chmod o+r /etc/apt/sources.list.d/caddy-stable.list
162sudo apt update
163sudo apt install caddy
164
165# --- Time Synchronization ---
166log "Installing and configuring chrony for time synchronization"
167apt-get install -y chrony
168# Start and enable chrony service
169systemctl enable --now chronyd || true
170echo "chrony installed and configured for automatic time synchronization."
171
172# --- Finalization ---
173log "Server setup complete!"
174echo "You can now log out and reconnect as '$USERNAME' using your SSH key."
175echo "Root login and password authentication have been disabled."