Skip to content

Instantly share code, notes, and snippets.

@yorickdowne
Last active August 22, 2025 17:35
Show Gist options
  • Save yorickdowne/3cecc7b424ce241b173510e36754af47 to your computer and use it in GitHub Desktop.
Save yorickdowne/3cecc7b424ce241b173510e36754af47 to your computer and use it in GitHub Desktop.
Debian 13 trixie upgrade

Debian 13

Caution Upgrading from Debian 12 to Debian 13 on machines with mdadm has intermittently failed for me; symptom is that grub EFI is not up to date and system boots into BIOS. Root cause under investigation; it might not be related to mdadm.

To start, read the official release notes.

If your install fits into "vanilla Debian plus maybe a handful of 3rd-party repos", then this guide for a simple upgrade to Debian 13 "trixie" from Debian 12 "bookworm" can be helpful. 3rd-party repos are handled with a find command.

Note upgrade is only supported from Debian 12 to Debian 13. If you are on Debian 11, upgrade to Debian 12 first. Then once on Debian 12, you can upgrade to Debian 13.

This guide is only for the OS itself. Applications are as plentiful as sand on the beach, and they may all require additional steps. Plan for that.

  • Check free disk space

df -h

5 GiB free is a conservative amount. sudo apt clean and sudo apt autoremove can be used to free some disk space.

On a server with only docker installed, even 1 GiB free was sufficient. Do err on the side of caution here, however.

  • Identify any 3rd-party repos that may need to be updated. They'll be changed with a find command, below.

ls /etc/apt/sources.list.d

  • Update current distribution

sudo apt update && sudo apt full-upgrade

If this brought in a new kernel, sudo reboot - otherwise continue

  • Change repo to trixie, from bookworm.
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list

non-free has been split since Debian 12 and if used, you should also use non-free-firmware. If you are unsure, check and adjust. More complete instructions are in the Debian release notes and the gist for Debian 12 upgrade

  • Change all 3rd-party repos

This assumes the repos have trixie versions. Run sudo apt update after the change to trixie to confirm, and deal with any repos that aren't available in trixie.

sudo find /etc/apt/sources.list.d -type f -exec sed -i 's/bookworm/trixie/g' {} \;
  • Optional: Start a screen session

So that an SSH disconnect doesn't stop your upgrade halfway through, you can run in screen: sudo apt install -y screen && screen

  • Hold mdadm if it's in use

If you use the mdadm package, as of Aug 22nd 2025, you'll want a workaround to avoid an issue where mdadm is updated before systemd and shows an error that it cannot find systemd. A bug report tracks this.

Hold mdadm, update Debian, then unhold mdadm and update again.

sudo apt-mark hold mdadm

  • Update Debian

For the following, say Yes to restarting services, and keep existing config files when prompted.

sudo apt update && sudo apt full-upgrade

  • Update mdadm if it's in use

This is a workaround for an order-of-operations issue, see above.

sudo apt-mark unhold mdadm

sudo apt update && sudo apt full-upgrade

mdadm should be updated without an error message about not finding systemd

  • Reboot

sudo reboot

  • Clean up old repos

sudo apt autoremove && sudo apt clean

  • Modernize Debian sources

Optional but recommended: Switch to deb822 format for the sources.list. This will write /etc/apt/sources.list.d/debian.sources and /etc/apt/sources.list.d/debian-backports.sources

sudo apt modernize-sources

Caveat that trixie-backports might not have a Signed-By on some 3rd-party mirrors. You can fix this by manually setting Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg in /etc/apt/sources.list.d/debian-backports.sources

Automated by Ansible

Config ansible.cfg:

[defaults]
interpreter_python = /usr/bin/python3

Playbook trixie.yml:

---
- name: Upgrade to Debian trixie
  hosts: all
  serial: 1
  gather_facts: false
  roles:
    - base/upgrade_trixie

Role base/upgrade_trixie/tasks/main.yml:

---
- name: Get distribution version
  setup:
    filter: ansible_distribution*
- name: Skip if not Debian 12
  meta: end_host
  when: ansible_distribution != 'Debian' or ansible_distribution_major_version != '12'
- name: apt clean
  apt:
    clean: yes
  become: yes
- name: Get filesystem facts
  setup:
    filter: ansible_mounts
- name: Fail if free space on / is below 5 GiB
  ansible.builtin.assert:
    that:
      - item.size_available > (5 * 1024 * 1024 * 1024)
    fail_msg: "Free disk space on {{ item.mount }} is below 5 GiB"
  loop: "{{ ansible_mounts }}"
  when: item.mount == "/"
- name: All apt packages up to date
  apt:
    upgrade: dist
    update_cache: yes
  become: yes
- name: apt autoremove
  apt:
    autoremove: yes
  become: yes
- name: apt clean
  apt:
    clean: yes
  become: yes
- name: Check if reboot required
  ansible.builtin.stat:
    path: /run/reboot-required
    get_checksum: no
  register: reboot_required_file
- name: Reboot if required
  ansible.builtin.reboot:
    msg: "Reboot initiated by Ansible"
    connect_timeout: 5
    reboot_timeout: 600
    pre_reboot_delay: 0
    post_reboot_delay: 60
    test_command: whoami
  when: reboot_required_file.stat.exists
  become: true
- name: Switch OS from bookworm to trixie
  ansible.builtin.replace:
    path: /etc/apt/sources.list
    regexp: 'bookworm'
    replace: 'trixie'
  become: yes
- name: Find all 3rd-party repos
  ansible.builtin.find:
    paths: /etc/apt/sources.list.d
    patterns: '*'
    recurse: no
  register: third_party_repos
- name: Switch 3rd-party repos from bookworm to trixie
  ansible.builtin.replace:
    path: "{{ item.path }}"
    regexp: 'bookworm'
    replace: 'trixie'
  loop: "{{ third_party_repos.files }}"
  loop_control:
    label: "{{ item.path }}"
  become: yes
- name: Use apt to move to trixie
  apt:
    upgrade: dist
    update_cache: yes
  become: yes
- name: Get distribution version
  setup:
    filter: ansible_distribution*
- name: Fail if not Debian 13
  assert:
    that:
      - ansible_distribution_major_version == '13'
    fail_msg: "Upgrade to Debian 13 failed"
- name: apt autoremove
  apt:
    autoremove: yes
  become: yes
- name: apt clean
  apt:
    clean: yes
  become: yes
- name: Reboot on trixie
  ansible.builtin.reboot:
    msg: "Reboot initiated by Ansible"
    connect_timeout: 5
    reboot_timeout: 600
    pre_reboot_delay: 0
    post_reboot_delay: 60
    test_command: whoami
  become: yes
- name: Modernize apt sources
  ansible.builtin.command:
    cmd: apt -y modernize-sources
  become: yes
- name: Pause for 5 minutes for staggered upgrades
  pause:
    minutes: 5
@WingettRun
Copy link

Some 3rd party repositiories were throwing "Skipping acquire of configured file...blah blah....stable InRelease doesn't support architecture 'i386'
If you have run the modernize-sources, there is a new format for setting an architecture....the old way arch=amd64 won't work.
You must put the line such as the following in the affected sources files:

Architectures: amd64

@thesirtaylor
Copy link

Thank you. This worked perfectly.

@dfurmans
Copy link

dfurmans commented Aug 12, 2025

Another one

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 13 (trixie)
Release:	13
Codename:	trixie

Works like expected

The number 13 ;)

@abbasEbadian
Copy link

It works.

$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"\
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.0
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

@linuxturtle
Copy link

That was awesome, thank you. I had a few machines with upstream sources.list which had the "bullseye" name in them, but couldn't be updated simply by doing a s/bullseye/trixie/ in the file (anything running a upstream haproxy stable stream, for example). So I had to go manually fix those machines, but generally, this was a huge timesaver! Thanks again!

@1Codealot
Copy link

1Codealot commented Aug 15, 2025

Pls help!!!!

Do I need to just re install os???

IMG_20250815_084443
I do have /home and /etc backed up

Also, why did you add auto remove into the update command, why didn't you put it after (maybe after rebooting)???

@1Codealot
Copy link

ok figured it out

I went into a recovery kernel, ctrl+alt+f3, apt fix broken install, apt update, apt upgrade
:)

@lrvl
Copy link

lrvl commented Aug 15, 2025

Thanks, worked fine.

As noted before by @uplg

Warning: https://deb.nodesource.com/node_20.x/dists/nodistro/InRelease: Policy will reject signature within a year, see --audit for details

Update after using trixie "Small issue due UX change in xfce4-terminal"

Pasting multi-line content now requires two actions ( https://gitlab.xfce.org/apps/xfce4-terminal/-/issues/347 ) that change has been reverted but the shipped package still contains the UX issue.

# dpkg-query -s xfce4-terminal
Package: xfce4-terminal
Status: purge ok installed
Priority: optional
Section: xfce
Installed-Size: 2212
Maintainer: Debian Xfce Maintainers <[email protected]>
Architecture: amd64
Version: 1.1.4-1
Provides: x-terminal-emulator
Depends: libatk1.0-0t64 (>= 1.12.4), libc6 (>= 2.38), libcairo2 (>= 1.14.0), libgdk-pixbuf-2.0-0 (>= 2.22.0), libglib2.0-0t64 (>= 2.44.0), libgtk-3-0t64 (>= 3.21.6), libpango-1.0-0 (>= 1.14.0), libpcre2-8-0 (>= 10.22), libutempter0 (>= 1.1.5), libvte-2.91-0 (>= 0.61.91), libx11-6, libxfce4ui-2-0 (>= 4.17.6), libxfce4util7 (>= 4.9.0), libxfconf-0-3 (>= 4.6.0), perl:any, exo-utils
Recommends: default-dbus-session-bus | dbus-session-bus
Description: Xfce terminal emulator
 This package contains Terminal, which is a lightweight and easy to use
 terminal emulator for X11. It was created to fit nicely into the Xfce
 desktop environment, but it also fits nice with other environments.
Homepage: https://docs.xfce.org/apps/terminal/start

@ojaha065
Copy link

Successfully upgraded my Jellyfin server from bookworm to trixie with these instructions. Thanks. The only issue I encountered was that the system booted into a black screen with nothing working after the first reboot. Forcing another reboot fixed the issue and thus I didn't look into any further.

@Lumipyry
Copy link

Lumipyry commented Aug 16, 2025 via email

@linuxturtle
Copy link

Debian Trixie was officially release at August 9th - so these instructions are not needed anymore.

Lol, are you trolling? Since Trixie's released, there's no longer any need to upgrade to it? ROTFLOL

@ojaha065
Copy link

Debian Trixie was officially release at August 9th - so these instructions are not needed anymore...

@Lumipyry Would you mind telling how to do the upgrade "the right way" then? This is/was one of the first results when googling "upgrading to Debian 13"...

@Lumipyry
Copy link

Lumipyry commented Aug 16, 2025 via email

@sscotth
Copy link

sscotth commented Aug 16, 2025

@ojaha065 Officially, follow section 4 of the release notes: https://www.debian.org/releases/trixie/release-notes/upgrading.en.html

@Lumipyry
Copy link

Lumipyry commented Aug 16, 2025 via email

@ojaha065
Copy link

Thanks. I did in fact see the release notes when I first googled this. While I appreciate the level of detail they provide, as a casual home user I much prefer simplified upgrade instructions like this Gist, rather than having to read through pages of information I mostly don't care about. If something had gone wrong during the upgrade while following these instructions, I would have just restored from backup or reinstalled the whole system without it being a big deal.

If anyone knows for certain that an upgrade made using the instructions in this Gist will cause issues later on, please let me know.

@Lumipyry
Copy link

Lumipyry commented Aug 16, 2025 via email

@Lumipyry
Copy link

Lumipyry commented Aug 16, 2025 via email

@Louisbuitton
Copy link

Hi,

How do I edit /etc/apt/sources.list.d/ ?

@DatShiGrey
Copy link

Hi,

How do I edit /etc/apt/sources.list.d/ ?

sudo nano /etc/apt/sources.list.d/debian.sources or sudo vim /etc/apt/sources.list.d/debian.sources for example.

@HanSyt
Copy link

HanSyt commented Aug 17, 2025

@Louisbuitton and don't forget... non-free is split in non-free and non-free-firmware in Trixie

@Louisbuitton
Copy link

Hi,
How do I edit /etc/apt/sources.list.d/ ?

sudo nano /etc/apt/sources.list.d/debian.sources or sudo vim /etc/apt/sources.list.d/debian.sources for example.

Thanks DatShiGrey

@Louisbuitton
Copy link

@Louisbuitton and don't forget... non-free is split in non-free and non-free-firmware in Trixie

Ok noted on that. Thanks

@yorickdowne
Copy link
Author

yorickdowne commented Aug 17, 2025

Non-free-firmware: Yep. I don’t call it out here because it’s covered when going to Debian 12, where this was first introduced.

bullseye to trixie directly: Not supported. Not a thing. Go bullseye to bookworm first, then trixie.

Follow official release notes: Absolutely. Which is why they are linked as the first thing. This gist scratches my own itch of having something I can use for a fleet of Debian servers with very little on them other than Docker CE. It’s grand if it’s helpful more broadly; the conservative move is to follow the official upgrade instructions.

This gist isn’t a support forum. Use r/debian or their discord for that.

@yorickdowne
Copy link
Author

Updated the gist to use apt and clean up after reboot. This makes it a bit less aggressive with autoremove and follows release notes more closely.

Release notes are still the go-to resource and cover backup strategies as well as corner cases like specific VPN packages, none of which this gist does.

@ghostersk
Copy link

There should be note to remove docker-compose as my upgrade failed because of it. I had to run sudo dpkg --remove docker-compose because it would not do anything with apt then i was able to update...

@Lure5134
Copy link

Same problem as @ghostersk.
As he said, running sudo dpkg --remove docker-compose fixes the issue.

You won't lose any data by removing it.
Note that docker-compose is obsolete. You should use docker compose instead (already included if you have Docker installed).

@yorickdowne
Copy link
Author

That’d be covered under “take care of your apps, this gist is for just the OS”. Indeed Compose V1 has been sunset for quite a while, and Compose V2 is the thing to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment