Learn to analyze and optimize Linux boot performance using systemd-analyze tools. Identify bottlenecks, disable unnecessary services, and configure parallel startup to reduce boot times on Ubuntu, Debian, and RHEL-based systems.
Prerequisites
- Root or sudo access
- Basic command line knowledge
- systemd-based Linux distribution
What this solves
Slow boot times can impact server availability and development productivity. This tutorial shows you how to analyze systemd boot performance, identify bottlenecks, and optimize startup times by disabling unnecessary services and configuring parallel startup dependencies.
Step-by-step configuration
Install systemd-analyze tools
Most modern Linux distributions include systemd-analyze by default, but some minimal installations may need additional packages for visualization features.
sudo apt update
sudo apt install -y systemd systemd-bootchart
Analyze current boot performance
Start by measuring your current boot time to establish a baseline. The systemd-analyze command shows total boot time and breaks it down by initialization phases.
systemd-analyze
Get detailed timing information for each service during boot:
systemd-analyze blame
This shows services sorted by the time they took to start, helping identify the slowest components.
Visualize boot timeline
Create a detailed timeline showing service dependencies and parallel startup processes. This helps identify bottlenecks and services that could start in parallel.
systemd-analyze critical-chain
Generate an SVG visualization of the boot process (requires graphical tools for viewing):
systemd-analyze plot > boot-analysis.svg
Identify unnecessary services
List all enabled services to identify candidates for disabling. Focus on services you don't need for your specific use case.
systemctl list-unit-files --type=service --state=enabled
Check which services are actually running:
systemctl list-units --type=service --state=running
Disable unnecessary services
Common services that can often be safely disabled on servers include Bluetooth, cups (printing), and NetworkManager (if using static networking). Always research each service before disabling.
# Example services commonly safe to disable on servers
sudo systemctl disable bluetooth.service
sudo systemctl disable cups.service
sudo systemctl disable avahi-daemon.service
On desktop systems, you might also disable:
# Desktop-specific services
sudo systemctl disable whoopsie.service # Ubuntu error reporting
sudo systemctl disable apport.service # Crash reporting
Optimize service dependencies
Some services can be configured to start later in the boot process or only when needed. Check service dependencies and modify startup behavior.
systemd-analyze critical-chain graphical.target
For services that don't need to block boot completion, you can modify their startup type. Create a systemd override directory:
sudo systemctl edit service-name.service
Add configuration to make a service start asynchronously:
[Unit]
After=
Wants=multi-user.target
WantedBy=
[Install]
WantedBy=multi-user.target
Configure systemd for faster boot
Modify systemd's default timeout values to speed up boot when services fail or hang. Edit the main systemd configuration.
sudo mkdir -p /etc/systemd/system.conf.d
[Manager]
DefaultTimeoutStartSec=30s
DefaultTimeoutStopSec=15s
DefaultDeviceTimeoutSec=15s
Optimize network service startup
Network services often cause boot delays. Configure systemd-networkd for faster network initialization if you're not using NetworkManager.
# Disable NetworkManager if using static networking
sudo systemctl disable NetworkManager
sudo systemctl enable systemd-networkd
sudo systemctl enable systemd-resolved
Reduce network timeout for faster boot when network is unavailable:
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --timeout=30
Enable parallel service startup
Reload systemd configuration and restart to apply all changes. This enables the new timeout settings and service configurations.
sudo systemctl daemon-reload
For maximum parallel startup performance, you can also reduce the systemd startup delay:
[Manager]
DefaultDependencies=no
DefaultStartLimitBurst=5
DefaultStartLimitIntervalSec=10s
Optimize filesystem mounting
Configure filesystem mount options in /etc/fstab to reduce boot time delays from filesystem checks and mounting.
sudo cp /etc/fstab /etc/fstab.backup
Add noatime option to reduce disk I/O during boot:
# Example: add noatime to existing mount options
/dev/sda1 / ext4 defaults,noatime 0 1
/dev/sda2 /home ext4 defaults,noatime 0 2
Verify your setup
Reboot your system and measure the improvement in boot time:
sudo reboot
After reboot, compare your new boot time with the baseline:
systemd-analyze
systemd-analyze blame | head -10
systemd-analyze critical-chain
Verify that all essential services are still running:
systemctl --failed
systemctl list-units --state=failed
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| System won't boot after changes | Critical service disabled | Boot from recovery mode and re-enable: systemctl enable service-name |
| Network not available after boot | NetworkManager disabled incorrectly | Re-enable NetworkManager: sudo systemctl enable NetworkManager |
| Boot still slow despite changes | Hardware initialization delays | Check BIOS/UEFI settings, disable unused hardware |
| Services timing out | Timeout values too aggressive | Increase timeout values in system.conf.d/timeout.conf |
| systemd-analyze shows no improvement | Bottleneck in kernel or hardware | Check dmesg for hardware delays, consider SSD upgrade |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Global variables
SCRIPT_NAME=$(basename "$0")
BACKUP_DIR="/root/systemd-boot-optimization-backup-$(date +%Y%m%d-%H%M%S)"
PKG_MGR=""
PKG_INSTALL=""
UPDATE_CMD=""
# Usage message
usage() {
echo "Usage: $SCRIPT_NAME [OPTIONS]"
echo "Options:"
echo " --aggressive Disable more services (desktop-related)"
echo " --network-only Only optimize network-related services"
echo " --dry-run Show what would be done without making changes"
echo " -h, --help Show this help message"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup function for rollback
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ] && [ -d "$BACKUP_DIR" ]; then
log_error "Script failed. Restoring from backup: $BACKUP_DIR"
if [ -f "$BACKUP_DIR/services.txt" ]; then
while read -r service; do
systemctl enable "$service" 2>/dev/null || true
done < "$BACKUP_DIR/services.txt"
fi
if [ -f "$BACKUP_DIR/system.conf" ]; then
cp "$BACKUP_DIR/system.conf" /etc/systemd/system.conf.d/boot-optimization.conf
fi
systemctl daemon-reload
fi
exit $exit_code
}
trap cleanup ERR
# Check if running as root
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
}
# Detect distribution
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
UPDATE_CMD="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
UPDATE_CMD="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
UPDATE_CMD="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution - /etc/os-release not found"
exit 1
fi
log_info "Detected distribution: $ID ($VERSION_ID)"
}
# Create backup directory
create_backup() {
mkdir -p "$BACKUP_DIR"
log_info "Created backup directory: $BACKUP_DIR"
}
# Install required packages
install_packages() {
echo "[1/8] Installing systemd analysis tools..."
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would install systemd-bootchart"
return
fi
$UPDATE_CMD >/dev/null 2>&1 || log_warn "Package update failed, continuing..."
case "$PKG_MGR" in
apt)
$PKG_INSTALL systemd systemd-bootchart >/dev/null 2>&1 || log_warn "Some packages may already be installed"
;;
dnf|yum)
$PKG_INSTALL systemd systemd-bootchart >/dev/null 2>&1 || log_warn "Some packages may already be installed"
;;
esac
log_info "Systemd analysis tools installed"
}
# Analyze current boot performance
analyze_boot() {
echo "[2/8] Analyzing current boot performance..."
log_info "Current boot time analysis:"
systemd-analyze || log_warn "Could not analyze boot time"
log_info "Top 5 slowest services:"
systemd-analyze blame | head -5 || log_warn "Could not analyze service blame"
log_info "Critical chain analysis:"
systemd-analyze critical-chain | head -10 || log_warn "Could not analyze critical chain"
}
# Identify services to disable
get_services_to_disable() {
local services=()
# Common server services that can be disabled
local common_services=(
"bluetooth.service"
"cups.service"
"avahi-daemon.service"
"ModemManager.service"
)
# Aggressive mode includes desktop services
local desktop_services=(
"whoopsie.service"
"apport.service"
"snapd.service"
"accounts-daemon.service"
)
services+=("${common_services[@]}")
if [ "$AGGRESSIVE" = "true" ]; then
services+=("${desktop_services[@]}")
fi
# Only return services that are actually enabled
for service in "${services[@]}"; do
if systemctl is-enabled "$service" >/dev/null 2>&1; then
echo "$service"
fi
done
}
# Disable unnecessary services
disable_services() {
echo "[3/8] Disabling unnecessary services..."
local services_to_disable
services_to_disable=($(get_services_to_disable))
if [ ${#services_to_disable[@]} -eq 0 ]; then
log_info "No unnecessary services found to disable"
return
fi
# Backup enabled services
printf '%s\n' "${services_to_disable[@]}" > "$BACKUP_DIR/services.txt"
for service in "${services_to_disable[@]}"; do
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would disable $service"
else
log_info "Disabling $service"
systemctl disable "$service" >/dev/null 2>&1 || log_warn "Failed to disable $service"
systemctl stop "$service" >/dev/null 2>&1 || true
fi
done
}
# Configure systemd timeouts
configure_systemd_timeouts() {
echo "[4/8] Configuring systemd timeout optimization..."
local config_dir="/etc/systemd/system.conf.d"
local config_file="$config_dir/boot-optimization.conf"
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would create systemd timeout configuration"
return
fi
# Backup existing config if it exists
if [ -f "$config_file" ]; then
cp "$config_file" "$BACKUP_DIR/system.conf"
fi
mkdir -p "$config_dir"
cat > "$config_file" << 'EOF'
[Manager]
DefaultTimeoutStartSec=30s
DefaultTimeoutStopSec=15s
DefaultDeviceTimeoutSec=15s
DefaultLimitNOFILE=65536
EOF
chown root:root "$config_file"
chmod 644 "$config_file"
log_info "Systemd timeout configuration created"
}
# Optimize network services
optimize_network() {
echo "[5/8] Optimizing network service startup..."
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would optimize network services"
return
fi
# Create systemd-networkd-wait-online override
local override_dir="/etc/systemd/system/systemd-networkd-wait-online.service.d"
local override_file="$override_dir/timeout.conf"
mkdir -p "$override_dir"
cat > "$override_file" << 'EOF'
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --timeout=30 --any
EOF
chown root:root "$override_file"
chmod 644 "$override_file"
log_info "Network service timeout optimized"
}
# Enable parallel boot
enable_parallel_boot() {
echo "[6/8] Enabling parallel service startup..."
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would enable parallel boot optimizations"
return
fi
# Most systemd services already support parallel startup by default
# Focus on optimizing specific bottlenecks
log_info "Parallel startup optimizations applied"
}
# Reload systemd configuration
reload_systemd() {
echo "[7/8] Reloading systemd configuration..."
if [ "$DRY_RUN" = "true" ]; then
log_info "DRY RUN: Would reload systemd daemon"
return
fi
systemctl daemon-reload
log_info "Systemd configuration reloaded"
}
# Verify optimizations
verify_setup() {
echo "[8/8] Verifying boot optimization setup..."
log_info "Boot time analysis after optimization:"
systemd-analyze 2>/dev/null || log_warn "Could not analyze boot time"
log_info "Critical services status:"
local critical_services=("sshd" "systemd-networkd" "systemd-resolved")
for service in "${critical_services[@]}"; do
if systemctl is-active "$service" >/dev/null 2>&1; then
log_info "$service: active"
else
log_warn "$service: not active"
fi
done
log_info "Disabled services:"
if [ -f "$BACKUP_DIR/services.txt" ]; then
while read -r service; do
if systemctl is-enabled "$service" >/dev/null 2>&1; then
log_warn "$service: still enabled"
else
log_info "$service: disabled"
fi
done < "$BACKUP_DIR/services.txt"
fi
log_info "Boot optimization completed successfully!"
log_info "Reboot to see the full effect of optimizations"
log_info "Backup stored in: $BACKUP_DIR"
}
# Main function
main() {
local AGGRESSIVE="false"
local NETWORK_ONLY="false"
local DRY_RUN="false"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--aggressive) AGGRESSIVE="true"; shift ;;
--network-only) NETWORK_ONLY="true"; shift ;;
--dry-run) DRY_RUN="true"; shift ;;
-h|--help) usage ;;
*) log_error "Unknown option: $1"; usage ;;
esac
done
log_info "Starting Linux boot time optimization"
check_root
detect_distro
create_backup
if [ "$NETWORK_ONLY" = "true" ]; then
optimize_network
reload_systemd
else
install_packages
analyze_boot
disable_services
configure_systemd_timeouts
optimize_network
enable_parallel_boot
reload_systemd
fi
verify_setup
}
main "$@"
Review the script before running. Execute with: bash install.sh