How to upgrade our Debian 11 (Bullseye) based system to Debian 12 (Bookworm) major release

botond published 2025/12/12, p - 18:30 time

Content

 

The 1. page content

 

Introductory

One of the most exciting and at the same time most meticulous tasks in server operation and Linux system maintenance is upgrading the major version of the operating system. This operation should never be done casually, as it replaces the "heart" of the system, the kernel, and all the essential services and applications.

In this tutorial, we will upgrade a Debian 11 (Bullseye) system to Debian 12 (Bookworm) (oldstable). The machine in the tutorial is a "hybrid" system: it serves both as a home workstation (with a graphical desktop environment) and ISPConfig as a web server for developers. This unique setup provides an excellent opportunity to present changes, conflicts, and solutions affecting both the desktop environment (e.g. multimedia, graphics programs) and server-side services (web server, database, mail) in a single comprehensive guide.

Since this description is therefore extremely complex and detailed, we recommend that our readers select the relevant parts according to their own system. Those who operate a dedicated server can skip the steps related to the graphical interface, while home users can refer to server-specific configuration issues (e.g. ISPConfig, Postfix, etc.) can choose the easier way.

 

 

News and changes of the Debian 12 (Bookworm) operating system

Before we dive into the technical implementation, it's worth placing Debian 12, codenamed "Bookworm", on the distribution timeline. At the time of writing (December 2025), Debian's development cycle is well underway, so Bookworm's status is now official. Debian Releases on the page already oldstable (old stable) designation.

But what exactly do these statuses mean, and why is it important for us when updating?

  • Stable: This is the current, recommended release for production environments. It receives the latest security patches and its package repositories are available from the main mirrors.
  • Oldstable: The previous stable release. Although it is no longer the latest, it still enjoys full security support (LTS - Long Term Support). Many server operators (like us now) consciously choose this for stability, or are just catching up to this version.
  • Archived: When a version reaches End of Life, it is moved to archived status. At this point, the package repositories are removed from the main servers, and only the archive.debian.org are available at . If you are trying to update such a system, first go to sources.list we need to modify the file to access the archive.

A life cycle chart of the Debian GNU/Linux operating system releases on the official website, showing versions, codenames, and support statuses (stable, oldstable, testing).

The image above shows the current state. Although Debian 12 is no longer the latest, migrating to it is a critical step to keep your system secure and up-to-date, and to provide a foundation for future (Trixie) updates.

Debian 12 brought many technical innovations compared to its predecessor, Bullseye (new Kernel, desktop environments, and the introduction of non-free-firmware repository). You can learn more about them in the description below:

News and changes of the Debian 12 (Bookworm) operating system

 

Prerequisites and system preparation

Backup

The most important rule: Never attempt a distribution upgrade without a reliable, recoverable backup! Although Debian's package manager (APT) and upgrade process are extremely stable, an unexpected power outage, a hidden hardware failure, or a bad configuration decision can lead to data loss or a "stuck" system at any time.

Since we have already written several detailed descriptions of different backup strategies (whether it's simple home data or complete server disk images), we won't go into them here. You can see them in the previous distribution update tutorials:

SSH access control (Critical!)

If you have remote access, SSH When updating the server via a connection, there is a technical detail in Debian 12 that can easily lock us out of our own machine after rebooting.

Attention: The OpenSSH server in Debian 12 (Bookworm) has deprecated the old, default, for security reasons. ssh-rsa (RSA SHA-1) algorithm keys support. If we access the server with an RSA key generated years ago, after the update the system may refuse access ("Refused our key").

Before starting the process, check your keys and, if necessary, generate new ones (e.g. ED25519 or ECDSA type), or temporarily set up password access in /etc/ssh/sshd_config file so that we don't exclude ourselves from the updated system!

 

Things to do before upgrading

System overview

The work is done root with authority, or sudo We do this using . The first step is to check the exact version of our current system and the type of kernel we are running. This will help ensure that we are in the right starting state.

uname -a
lsb_release -a
cat /etc/os-release
cat /etc/debian_version

From the output of the commands, we can see that Debian 11 (Bullseye) is currently running on the machine, with kernel 5.10.

Querying the Debian 11 (Bullseye) system version and the running kernel type in a terminal using the uname, lsb_release, and cat commands.

Update current system

As a "clean slate" principle, never start a major version upgrade with outdated packages on your current system. Bring Debian 11 to the latest state possible to minimize the difference (delta) between the two versions and avoid unnecessary dependency errors.

First, let's update the package lists with apt-get command:

apt-get update

Then install the available updates:

apt-get upgrade

Update repositories and packages

And the output of the upgrade operation is at the end:

End of upgrade output, with some warnings

In the above output (which is upgrade (showing the end of the process) we may see some red warning messages that need explanation, but in this case they do not require intervention:

  • Samba password warning: WARNING: The "encrypt passwords" option is deprecatedThis simply informs you that the setting in our old configuration file is now considered deprecated in the new Samba version. It does not affect operation at this time, and we can remove it from the config later during a cleanup.
  • Masked service error: Failed to preset unit... samba-ad-dc.service is masked. This is a common "false positive" alarm. Since our server is not running as an Active Directory domain controller (AD DC), but as a standalone file server, the system intentionally disables (masks) this service so that it does not conflict with plain file sharing.

Tip: Although there are methods for to manually unblock masked services, however, in this specific case, masking serves the stability of the system, so we ignore the error message if We use Samba shares, and we encounter this output during the update.

Finally, perform a full distribution upgrade within the current version to get the kernel and other dependencies in place. This ensures that your Bullseye system is in its final, most up-to-date state before the switch.

apt-get dist-upgrade

If our system was maintained, then ideally we would get the following output: "0 updated, 0 newly installed, 0 to be removed, and 0 not updated."

Running the apt-get dist-upgrade command on Debian 11 shows that there are no packages to upgrade, the system is up to date.

Checking packages

Before starting the upgrade, it is advisable to remove packages that are no longer used and installed as dependencies so as not to impose unnecessary burden on the new system.

apt-get autoremove
apt-get clean

Removing unnecessary packages with the apt-get autoremove command and cleaning the package repository.

Also, although it is not shown in the pictures, it is good practice to run the dpkg --audit command. If the output of the command is empty, that's the best news: your system's package database is consistent and ready to move forward.

 

 

Luggage storage and package preparation

Managing third-party package repositories

On an average Linux desktop, server, or development machine, we often use software from external sources (e.g. Google Chrome, TeamViewer, VirtualBox, etc.), which as a first step in their installation create their own list files in the /etc/apt/sources.list.d/ in the directory - or we create them based on the suggestion of the given software, where there is no automated installation script. When upgrading the main version, these repositories often cause conflicts, as they still refer to the old system (Bullseye), or do not yet support the new one; or package dependencies that change due to the upgrade can cause confusion, so the safest procedure is to we turn it off completely these external sources, so that APT can focus exclusively on official Debian packages. And then, after the upgrade is complete, when the final package dependencies have been established, we will rebind them. Let's see what lists we have:

cd /etc/apt/sources.list.d/
l

(the l I have the command ls --color=auto --group-directories-first -lAh means alias)

Listing the contents of the /etc/apt/sources.list.d/ directory, which shows list files for many third-party package repositories (e.g. google-chrome.list, teamviewer.list, virtualbox.list).

Tip: Instead of opening each file one by one and commenting out the lines (which is time-consuming and error-prone), use the "parking lot" method! Create a temporary directory (e.g. disabled) and move all the .list file. This way APT won't see them, but the files will remain and restoring them later will be just a single command.

mkdir disabled
mv *.list disabled/
l

In the picture we can see that the directory has been emptied, the files are safe in the subfolder.

Moving external package repositories to a temporary directory named 'disabled' using the mkdir and mv commands for safe upgrades.

Modifying APT source list files for Debian 12

Now that we have eliminated external distractions, let's edit the main configuration file, /etc/apt/sources.listBut first – just to be safe – let's make a copy of it:

cp /etc/apt/sources.list /etc/apt/sources.list.bak_bullseye

Make a backup copy of the original sources.list file using the cp command before starting editing.

Now let's open it for editing:

nano /etc/apt/sources.list

In the editor we can see the current status. It is worth noting that the list sury.org (PHP) storage is already modern [signed-by=...] I have also set a directive for during previous update.

Opening the original sources.list file for Debian 11 (Bullseye) in the nano editor, showing the use of the signed-by directive for the Sury.org PHP repository.

This security solution is now essential for managing external keys in newer versions of Debian. I have previously written in detail about this topic and how to prevent "Missing signed-by" errors:

What should we do if APT gives the warning "Missing signed-by=" while updating our repositories?

Since we are only using the pure Debian repos during the update, we also comment out the Sury.org line during editing (or if it is in a separate list file, we move it to the disabled folder along with the others using the previous method).

Editing steps:

  1. We replace everywhere bullseye reference bookwormrespectively.
  2. NOVELTY: Add to the end of the lines: non-free-firmware component!

Important change: In Debian 12, closed source firmware (e.g. WiFi drivers, microcode) has been removed from the public domain. non-free section, and a separate non-free-firmware If we don't add this, some of our hardware (especially laptops and wifi cards) may become inoperable after the update!

The modified file should look like this (excluding comments):

deb http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware

deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware

deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware

The modified sources.list file for Debian 12, where bullseye was replaced with bookworm and the non-free-firmware repository was added.

Update packing lists

After saving the file, update the database to download the list of new Bookworm repositories:

apt-get update

If everything went well, the command will run without errors and you will see the bookworm repositories in the output. Since we have disabled external repos, you should not see any GPG errors or 404 messages now.

Running the apt-get update command after modifying the source list will now load the bookworm repositories without any error messages.

 

 

Update simulation and minimal update

Before we put the system into production to exchange thousands of packets, it is worth running a simulation. This will show whether there would be any immediate, fatal packet collisions.

apt-get upgrade --simulate

Start a system upgrade simulation with the apt-get upgrade --simulate command.

Interestingly, we can count how many packages are waiting to be updated. In my case, this number was nearly 3000:

echo $?
apt-get upgrade --simulate | wc -l

Summarize the simulation results and check the number of packages to be updated with the wc -l command.

After a successful simulation, we choose the safer two-step upgrade strategy. First, we only upgrade packages that do not require installing new dependencies or removing existing ones. This "minimal upgrade" creates a stable foundation for the big leap later.

apt-get upgrade --without-new-pkgs

In the output of the command, we can see the list of packages to be updated.

To start a safe, minimal upgrade, run apt-get upgrade --without-new-pkgs, which will not install any new dependencies, only update existing ones.

To start the process, please respond. Yes(or press Enter).

apt-get-upgrade-without-new-pkgs-minimalist-freshsites

 

Interactions during minimal refresh

During the update process, the system may occasionally stop and request user intervention. These interactions may be different for everyone, as they depend greatly on the installed software and individual settings. Below we will review the typical cases we have encountered on such "hybrid" (ISPConfig + Desktop environment) systems.

List of changes (apt-listchanges)

At the beginning of the process, almost everyone may experience apt-listchanges window. This useful little tool is designed to display important changes (changelogs) and news written by package developers before (or during) installation.

A text interface for the apt-listchanges tool in the terminal, which displays major package changes and news before installation

From the list, q You can exit by pressing the key, after which the update will automatically continue by unpacking and installing the packages.

The package update process is running, lines indicating Unpacking and Preparing packages are visible in the terminal.

Logrotate and Awstats configuration

As the installer progresses, configuration conflicts may occur. This happens when a package maintainer has updated the default configuration file for the package, but the system detects that it has already been modified on our machine (or has been created by another program).

In our case, the system indicated the following when setting up the logrotate function of the Awstats web statistics software:

Indication of a configuration file conflict at the /etc/logrotate.d/httpd-prerotate/awstats file, where the system offers options (install, keep, show differences).

In such cases, it is always worth looking at the differences between D by pressing the key (show the differences). In the diff view we can see exactly what has changed.

Since we did not create this configuration manually, but rather it is managed by the ISPConfig installer, and at the end of the update we will run the ISPConfig update script anyway (which will restore its own settings), we can safely choose the new version of the package maintainer here.

Press the Y (install the package maintainer's version) button.

The "diff" view for Awstats configuration file conflicts, showing the differences between the old and new versions in the terminal.

Closing the minimal update

There were no other questions or conflicts during this phase. After the command was executed, we got the prompt back. To be on the safe side, we can query the return value of the last command with echo $? command. The 0 The output indicates that everything completed without errors.

The minimal system update completes successfully, the command prompt returns, and the error code (echo $?) is checked for a zero value.

 

With this, we have successfully passed the first, critical step. The basic packages of our system have been updated, and the package database is consistent. The next page We move on to the most exciting part of the process: the full system upgrade (dist-upgrade) and dealing with more complex configuration issues.

 

 

 

Navigation

This description consists of several pages: