Skip to content

Instantly share code, notes, and snippets.

@R0GGER
Last active January 20, 2026 20:55
Show Gist options
  • Select an option

  • Save R0GGER/9680bdb0e7d4d42ae3d37a80eb184a4d to your computer and use it in GitHub Desktop.

Select an option

Save R0GGER/9680bdb0e7d4d42ae3d37a80eb184a4d to your computer and use it in GitHub Desktop.
Upgrade Debian 12 to 13

Upgrade Debian 12 to 13

This script automates a safe upgrade from Debian 12 (Bookworm) to Debian 13 (Trixie). It backs up important configuration files, updates the system, adjusts APT sources, and runs the upgrade steps.

Requirements

  • Debian 12 (Bookworm)
  • Root/sudo privileges
  • At least 5 GB of free disk space

Download and run

Download the script with wget, make it executable, and run it:

wget https://gist.githubusercontent.com/R0GGER/9680bdb0e7d4d42ae3d37a80eb184a4d/raw/4fff69889a5bda0c493955dbf919312fade31358/debian12to13-upgrade.sh && \
chmod +x debian12to13-upgrade.sh && \
./debian12to13-upgrade.sh

The script asks for confirmation before starting the upgrade and shows the backup location and log file path.

#!/bin/bash
###############################################################################
# Script: Debian 12 (Bookworm) to Debian 13 (Trixie) Upgrade
# Description: Safe automatic upgrade from Debian 12 to Debian 13
# Author: Auto-generated
# Date: $(date +%Y-%m-%d)
###############################################################################
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging
LOG_FILE="/var/log/debian-upgrade-$(date +%Y%m%d-%H%M%S).log"
exec 1> >(tee -a "$LOG_FILE")
exec 2> >(tee -a "$LOG_FILE" >&2)
# Functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if script is run as root
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (use sudo)"
exit 1
fi
log_success "Root check passed"
}
# Check current Debian version
check_debian_version() {
if [[ ! -f /etc/debian_version ]]; then
log_error "This is not a Debian system"
exit 1
fi
DEBIAN_VERSION=$(cat /etc/debian_version)
log_info "Current Debian version: $DEBIAN_VERSION"
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot read /etc/os-release"
exit 1
fi
source /etc/os-release
if [[ "$VERSION_CODENAME" != "bookworm" ]]; then
log_error "This script is only for Debian 12 (Bookworm). Current version: $VERSION_CODENAME"
exit 1
fi
log_success "Debian 12 (Bookworm) detected"
}
# Check disk space
check_disk_space() {
log_info "Checking disk space..."
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
if [[ $AVAILABLE_SPACE -lt 5 ]]; then
log_error "Insufficient disk space. Minimum 5GB required, available: ${AVAILABLE_SPACE}GB"
exit 1
fi
log_success "Sufficient disk space available: ${AVAILABLE_SPACE}GB"
}
# Create backup of important files
backup_important_files() {
log_info "Creating backup of important configuration files..."
BACKUP_DIR="/root/debian-upgrade-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Backup sources.list
if [[ -f /etc/apt/sources.list ]]; then
cp /etc/apt/sources.list "$BACKUP_DIR/sources.list.backup"
fi
# Backup sources.list.d directory
if [[ -d /etc/apt/sources.list.d ]]; then
cp -r /etc/apt/sources.list.d "$BACKUP_DIR/"
fi
# Backup important configurations
IMPORTANT_FILES=(
"/etc/fstab"
"/etc/network/interfaces"
"/etc/hosts"
"/etc/hostname"
)
for file in "${IMPORTANT_FILES[@]}"; do
if [[ -f "$file" ]]; then
cp "$file" "$BACKUP_DIR/"
fi
done
log_success "Backup created in: $BACKUP_DIR"
echo "$BACKUP_DIR" > /tmp/debian-upgrade-backup-location.txt
}
# Update current system
update_current_system() {
log_info "Updating current system..."
apt-get update
apt-get upgrade -y
apt-get dist-upgrade -y
log_success "Current system updated"
}
# Clean up unnecessary packages
cleanup_packages() {
log_info "Cleaning up unnecessary packages..."
apt-get autoremove -y
apt-get autoclean
apt-get clean
log_success "System cleaned up"
}
# Update sources.list to Debian 13 (Trixie)
update_sources_list() {
log_info "Updating sources.list to Debian 13 (Trixie)..."
# Backup original sources.list
cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date +%Y%m%d)
# Replace bookworm with trixie in sources.list
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list
# Also update sources.list.d files
if [[ -d /etc/apt/sources.list.d ]]; then
find /etc/apt/sources.list.d -type f -name "*.list" -exec sed -i 's/bookworm/trixie/g' {} \;
fi
log_success "Sources.list updated to Debian 13 (Trixie)"
}
# Minimal upgrade (recommended Debian upgrade method)
minimal_upgrade() {
log_info "Performing minimal upgrade..."
apt-get update
# Minimal upgrade as recommended by Debian
apt-get upgrade --without-new-packages -y || true
apt-get full-upgrade -y
log_success "Minimal upgrade completed"
}
# Full upgrade
full_upgrade() {
log_info "Performing full upgrade..."
apt-get update
apt-get full-upgrade -y
log_success "Full upgrade completed"
}
# Handle configuration file changes
handle_config_changes() {
log_info "Processing configuration file changes..."
# Use 'yes' for default options, but ask for confirmation for important changes
# This can be interactive, so we use DEBIAN_FRONTEND=noninteractive
export DEBIAN_FRONTEND=noninteractive
# For important configurations, use the old version as default
# This prevents important configurations from being overwritten
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" full-upgrade -y || true
log_success "Configuration file changes processed"
}
# Final cleanup
final_cleanup() {
log_info "Performing final cleanup..."
apt-get autoremove -y
apt-get autoclean
apt-get clean
log_success "Final cleanup completed"
}
# Verify upgrade
verify_upgrade() {
log_info "Verifying upgrade..."
if [[ -f /etc/os-release ]]; then
source /etc/os-release
if [[ "$VERSION_CODENAME" == "trixie" ]]; then
log_success "Upgrade successful! Current version: Debian 13 (Trixie)"
return 0
else
log_warning "Version check: $VERSION_CODENAME (expected: trixie)"
return 1
fi
else
log_error "Cannot read /etc/os-release"
return 1
fi
}
# Main function
main() {
log_info "========================================="
log_info "Debian 12 to Debian 13 Upgrade Script"
log_info "========================================="
log_info "Log file: $LOG_FILE"
echo ""
# Pre-upgrade checks
check_root
check_debian_version
check_disk_space
# Ask for confirmation
echo ""
log_warning "WARNING: This script will upgrade your system from Debian 12 to Debian 13"
log_warning "Make sure you have a backup before proceeding!"
echo ""
read -p "Do you want to continue with the upgrade? (yes/no): " -r
echo ""
if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
log_info "Upgrade cancelled by user"
exit 0
fi
# Pre-upgrade steps
backup_important_files
update_current_system
cleanup_packages
# Upgrade steps
update_sources_list
minimal_upgrade
handle_config_changes
full_upgrade
# Post-upgrade steps
final_cleanup
verify_upgrade
echo ""
log_success "========================================="
log_success "Upgrade process completed!"
log_success "========================================="
echo ""
log_warning "IMPORTANT: Reboot your system to complete the upgrade:"
log_info " sudo reboot"
echo ""
log_info "Backup location: $(cat /tmp/debian-upgrade-backup-location.txt 2>/dev/null || echo 'Unknown')"
log_info "Log file: $LOG_FILE"
echo ""
}
# Execute script
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment