Automating Your Ubuntu Server Setup: A Standardised Approach to Configuration
Automating Your Ubuntu Server Setup: A Standardised Approach to Configuration
In the world of system administration, consistency and efficiency are paramount. Manually configuring a new server is not only time-consuming but also prone to human error, leading to inconsistent setups and potential security oversights. This article introduces a bash script designed to automate the initial configuration of a minimal Ubuntu 24.04 LTS server, ensuring a standardised baseline.
The catalyst for creating this script was the setup of a new home lab environment hosted on an Intel N100 Mini PC. These compact, low-power systems are excellent for reducing energy consumption while delivering adequate performance for various server applications. However, a significant performance issue was identified during the initial build on Ubuntu Server: the CPU was aggressively throttled down to its 800MHz base clock due to default power-saving mechanisms. Addressing this required a two-pronged approach. The first step was to disable the “Intel Speed Step” feature within the system’s BIOS. The second, and crucial, step on Linux was to install and configure the cpufrequtils
package to permanently enforce the “performance” CPU governor. To ensure this solution could be applied consistently and efficiently across future server rebuilds or deployments, this automation script was developed.
Purpose
The primary purpose of this script is to streamline the post-installation setup of an Ubuntu server. After a minimal OS installation, numerous packages and configurations are required to make the system functional, secure, and ready for specific workloads.
Modern cybersecurity frameworks emphasise the importance of secure baselines. A standardised deployment script helps achieve this by programmatically enforcing security settings, such as strengthening cryptographic protocols. Disabling older TLS versions, like TLS 1.0 and 1.1, is a critical step in mitigating known vulnerabilities. The U.S. National Institute of Standards and Technology (NIST) has deprecated their use for government systems, a best practice widely adopted across the industry [1]. This script shows a method automate such configurations, ensuring the deployment of server adheres to a defined security posture from the outset.
TL;DR: Here’s a bash script to automate the setup of a Ubuntu Server: https://gist.github.com/CraigWilsonOZ/da0a3bc321791938e5ad88d0b8d1ced8
Use Cases
This script adds value across several common scenarios:
- Automation: For developers and system administrators who frequently deploy new virtual machines or bare-metal servers, this script reduces setup time from hours to minutes. It is particularly useful in environments like a home lab, where a user might be testing various applications on a fresh instance.
- Standardisation: In a team environment, it ensures every server starts with the same set of tools and configurations, simplifying management and reducing the “it works on my machine” problem.
- Compliance: While not exhaustive, the script provides a foundational layer of security hardening (e.g., SSH banner, OpenSSL configuration) that can be a starting point for meeting compliance requirements under frameworks like ISO 27001 or the CIS Benchmarks. The use of a login banner, for instance, is a common requirement to inform users of monitoring and acceptable use policies.
- Incident Response: A known, consistent state simplifies forensic analysis. If a compromise occurs, investigators can quickly differentiate between the standard baseline and unauthorised changes made by an attacker.
Prerequisites
To ensure successful execution, the following requirements must be met:
- Operating System: Ubuntu Server 24.04 LTS (minimal installation). The script is designed for Debian-based distributions but has only been tested on this specific version.
- Permissions: The script must be executed with root privileges (
sudo
). - Network Access: An active internet connection is required to download packages from Ubuntu repositories and a Personal Package Archive (PPA). Outbound access over TCP port 443 (HTTPS) and TCP port 80 (HTTP) to
archive.ubuntu.com
,ppa.launchpad.net
, and other repository mirrors is necessary. - Software Versions: The script is designed for the package versions available in the Ubuntu 24.04 repositories as of July 2025.
How The Script Works
The script executes a sequence of functions in a logical order to configure the system. Its workflow is designed to be idempotent where possible, meaning it can be run multiple times without causing adverse effects.
- Initial Checks: The script first verifies it is being run with root privileges. If not, it exits immediately to prevent errors.
- Package Management: It adds a PPA to source the
fastfetch
utility, updates the local package index, and then installs a comprehensive list of system administration, networking, and development tools in a singleapt-get
command to improve efficiency. - Performance Tuning: The CPU governor is set to
performance
. This forces the CPU to operate at its maximum frequency, which can be beneficial for latency-sensitive or compute-intensive server workloads. - Security Hardening:
- An SSH banner is created and enabled to display a legal notice to users upon login.
- The OpenSSL configuration is hardened by setting the minimum accepted TLS protocol to TLSv1.2 and enforcing secure cipher suites, aligning with modern cryptographic standards.
- User Experience:
- The default Message of the Day (MOTD) is disabled.
fastfetch
is configured to run on login, presenting a clean, detailed summary of system hardware and software information.
- System Configuration: The system’s timezone is set to
Australia/Melbourne
. - Service Restarts: Key services like
ssh
andcpufrequtils
are restarted to apply the new configurations. - Cleanup: To prevent a user’s command history from revealing sensitive information used during setup, the script concludes by clearing the history files for all users.
The Script
#!/bin/bash
#==============================================================================
# Streamlined System Initialization and Configuration Script
#
# Author: Craig Wilson
# Version: 0.1
# Last Modified: 2025-06-20
#
# Description:
# This script automates the initial setup of a Debian-based server by:
# - Installing a consolidated list of essential tools and utilities.
# - Configuring system settings for performance and security.
# - Customizing the login experience with a legal banner and system info.
#
# Tested on:
# - Ubuntu 24.04 (Lunar Lobster)
#
#==============================================================================
# --- Script Configuration and Preamble ---
# Exit immediately if a command exits with a non-zero status.
set -e
# Set DEBIAN_FRONTEND to noninteractive to prevent prompts.
export DEBIAN_FRONTEND=noninteractive
# --- Function Definitions ---
#
# Performs initial checks to ensure script can run successfully.
#
initial_checks() {
echo "▶ Performing initial checks..."
# Check for root privileges
if [ "$EUID" -ne 0 ]; then
echo "ERROR: Please run this script as root or using sudo." >&2
exit 1
fi
}
#
# Updates package lists and installs all required packages in one go.
#
install_packages() {
echo "▶ Updating package repositories..."
# Add the PPA for fastfetch
echo "▶ Adding PPA for fastfetch..."
add-apt-repository -y ppa:zhangsongcui3371/fastfetch 2>&1 | grep -v "WARNING: apt does not have a stable CLI interface"
echo "▶ Updating package lists..."
apt-get update -y 2>&1 | grep -v "WARNING: apt does not have a stable CLI interface"
echo "▶ Installing all required packages..."
apt-get install -y \
btop \
cmatrix \
curl \
wget \
vim \
nano \
unzip \
net-tools \
build-essential \
speedtest-cli \
python3 \
python3-pip \
python3-venv \
git \
openvpn \
linux-tools-common \
smartmontools \
nvme-cli \
"linux-tools-$(uname -r)" \
cpufrequtils \
fastfetch \
2>&1 | grep -v "WARNING: apt does not have a stable CLI interface"
echo "✔ Package installation complete."
}
#
# Configures the CPU governor for maximum performance.
#
configure_cpu_governor() {
echo "▶ Configuring CPU governor to 'performance'..."
# Set the governor in the configuration file
echo 'GOVERNOR="performance"' > /etc/default/cpufrequtils
echo "✔ CPU governor configured."
}
#
# Sets a legal disclaimer banner for SSH sessions.
#
configure_ssh() {
echo "▶ Configuring SSH banner..."
local banner_file="/etc/ssh/banner"
local ssh_config="/etc/ssh/sshd_config"
# Create the SSH banner file
cat << EOF > "$banner_file"
*******************************************************************************
** NOTICE TO USERS OF THIS SYSTEM **
** **
** This computer system is for authorized use only. **
** **
** By using this system, the user consents to such interception, monitoring, **
** recording, copying, auditing, inspection, and disclosure at the **
** discretion of authorized site or personnel. **
** **
** By continuing to use this system, you indicate your awareness of and **
** consent to these terms and conditions of use. **
*******************************************************************************
EOF
# Add the banner configuration to sshd_config if it doesn't exist
if ! grep -q "^Banner $banner_file" "$ssh_config"; then
echo "Banner $banner_file" >> "$ssh_config"
fi
echo "✔ SSH banner configured."
}
#
# Configures fastfetch to display on login and disables default MOTD.
#
configure_motd() {
echo "▶ Configuring fastfetch as the login banner..."
# Create a script to run fastfetch on login for all users
cat << EOF > /etc/profile.d/00-fastfetch.sh
#!/bin/bash
# Display system information using fastfetch
fastfetch
EOF
chmod +x /etc/profile.d/00-fastfetch.sh
# Disable default MOTD files by renaming them with a .disabled extension
echo "▶ Disabling default MOTD..."
for file in /etc/update-motd.d/*; do
# Check if it's a file and not already disabled
if [[ -f "$file" && ! "$file" == *.disabled ]]; then
mv "$file" "$file.disabled" 2>/dev/null || true
fi
done
echo "✔ MOTD configured to show fastfetch."
}
#
# Hardens OpenSSL configuration to modern standards.
#
configure_openssl() {
echo "▶ Configuring OpenSSL security settings..."
local openssl_config="/etc/ssl/openssl.cnf"
# Backup the original configuration file
cp "$openssl_config" "$openssl_config.bak"
# Add MinProtocol and CipherString if they don't already exist
if ! grep -q "^MinProtocol" "$openssl_config"; then
sed -i '/^\[system_default_sect\]$/a MinProtocol = TLSv1.2' "$openssl_config"
fi
if ! grep -q "^CipherString" "$openssl_config"; then
sed -i '/^\[system_default_sect\]$/a CipherString = DEFAULT@SECLEVEL=2' "$openssl_config"
fi
echo "✔ OpenSSL security settings applied."
}
#
# Enables and restarts all necessary services.
#
restart_services() {
echo "▶ Enabling and restarting services..."
# Enable and start cpufrequtils
systemctl enable cpufrequtils
systemctl start cpufrequtils
# Restart services that use SSH or OpenSSL
local services_to_restart=("ssh" "apache2" "nginx")
for service in "${services_to_restart[@]}"; do
if systemctl list-units --full --all | grep -q "${service}.service"; then
echo " - Restarting ${service}..."
systemctl restart "${service}"
else
echo " - Service ${service} not found, skipping restart."
fi
done
echo "✔ Services have been restarted."
}
#
# Configure the system timezone to Melbourne, Australia.
#
configure_timezone() {
echo "▶ Configuring system timezone to Melbourne, Australia..."
# Set the timezone to Melbourne
sudo timedatectl set-timezone Australia/Melbourne
echo "✔ Timezone configured to Melbourne, Australia."
}
#
# Clears on-disk history for all users and the root account.
#
clean_history() {
echo "▶ Clearing on-disk command history files..."
# Unset HISTFILE for the script's session to prevent its own commands from being logged.
unset HISTFILE
# Define the common history filenames to clear.
local history_files=(".bash_history" ".zsh_history" ".fish_history")
# Clear history for the root user.
echo " - Clearing history for root user..."
for hist_file in "${history_files[@]}"; do
# Check if the history file exists for root before trying to clear it.
if [ -f "/root/${hist_file}" ]; then
cat /dev/null > "/root/${hist_file}"
fi
done
# Iterate over user directories in /home.
for user_dir in /home/*; do
# Ensure it is a directory.
if [ -d "$user_dir" ]; then
local user
user=$(basename "$user_dir")
echo " - Clearing history for user: $user"
for hist_file in "${history_files[@]}"; do
local full_path="${user_dir}/${hist_file}"
# Check if the history file exists before trying to clear it.
if [ -f "$full_path" ]; then
cat /dev/null > "$full_path"
fi
done
fi
done
echo "✔ On-disk history files cleared."
echo "ℹ NOTE: To clear the history of your CURRENT terminal session, please run 'history -c' after this script completes."
}
# --- Main Execution ---
main() {
initial_checks
install_packages
configure_cpu_governor
configure_ssh
configure_motd
configure_openssl
configure_timezone
restart_services
clean_history
echo -e "\n✔ System setup and configuration are complete."
}
main "$@"
# --- End of Script ---
Security Considerations
- Privileged Operations: This script requires root access to install packages and modify system-wide configuration files. Running scripts from untrusted sources with root privileges is extremely dangerous. Always review the script’s content before execution.
- Sensitive Data Handling: The
clean_history
function is included to clear command history, which might inadvertently contain passwords or other sensitive data entered during the setup process. However, it does not clear history from the active terminal session; the user must do this manually by runninghistory -c
. - External Repositories: The script adds a third-party PPA (
ppa:zhangsongcui3371/fastfetch
). While PPAs are a common way to access newer software on Ubuntu, they introduce a level of risk as the packages are not maintained by Canonical. The integrity of the system depends on the trustworthiness of the PPA maintainer.
Limitations
- Distribution Specific: The script is written for Debian-based systems using
apt
and has only been validated on Ubuntu 24.04. It will fail on distributions that use different package managers (e.g.,yum
,dnf
,pacman
). - Environment Assumptions: The script assumes a minimal server installation. Running it on a system with a desktop environment or other pre-existing configurations might lead to unintended consequences.
- CPU Governor: Setting the CPU governor to
performance
disables power-saving states. On battery-powered devices like laptops or in energy-conscious environments, this will lead to significantly higher power consumption. This setting is intended for servers where performance is prioritised over power efficiency.
Future Work / Enhancement Ideas
- Parameterisation: Convert hard-coded values (e.g., timezone, CPU governor setting) into command-line arguments or variables at the top of the script for easier customisation without editing the core logic.
- Enhanced Security: Integrate more advanced security controls, such as configuring
fail2ban
for brute-force protection, setting up unattended upgrades for security patches, or applying a more comprehensive set of CIS Benchmark recommendations.
Conclusion
Automating server setup with a configuration script provides substantial benefits in efficiency, consistency, and security. This script serves as a foundation for deploying my Ubuntu 24.04 servers, ensuring that I have essential tools and the start of a secure baseline is established from the moment of creation.
For further reading on security best practices, consult the official CIS Benchmarks and NIST publications.
References
[1] T. A. Polk, T. P. Grassi, and K. A. Venti, NIST Special Publication 800-52 Revision 2: Guidelines for the Selection, Configuration, and Use of Transport Layer Security (TLS) Implementations, National Institute of Standards and Technology, Gaithersburg, MD, Aug. 2019. doi: 10.6028/NIST.SP.800-52r2.