If you’re reading this and you’re reading it on ki6uoc.com, it means that the upgrade is complete and successful. Read on to see more about the process. While this isn’t that technically interesting, perhaps it’s useful to anyone else who might be in this situation of having to update a old and unsupported version of Debian to latest stable.

Overall Strategy

I currently have this VPS hosted on Atlantic.net. Most advice would say “Just reprovision the serve with a new instance with an updated operating system”. This is how anyone who manages large fleets of machines deals with this: You have a base OS image and when it’s time to upgrade you spin up a new instance with a new version of the Base OS image, set up whatever application its supposed to serve on it, cut over the DNS or point the load balancer at the new instance and remove the old one. And this was an option here: Given that I’m only hosting a static website there would be no technical functional bar to doing this. Just upload a copy of my website to the new server, get it working, cut over the DNS and update any certificates.

My problem is that I’m grandfathered into a very low cost very low memory plan on Atlantic.net. My server costs are a couple of bucks every month. The next cheapest plan is $4 a month. This tradeoff makes exactly zero sense in the real world because the engineering time of manually upgrading an old Debian machine would to save around $2 a month would never come out ahead. But since this my machine used for my own personal purposes and I’m having fun I went ahead tried to do this the old fashioned way.

Step 0: Prep work

Before beginning, I made sure to take a backup of Apache2 server configs, the website contents, and anything that happened to be in my home directory. I also verified that Atlantic.net had a snapshot of the server I could recover to if needed. And I took a look at the uptime:

14:38:15 up 1232 days,  5:44,  1 user,  load average: 0.43, 0.29, 0.21

No reboots in 3 years! There was a time that was praised for stability. But these days it usually (but not always ) means you’re running an older Kernel. So, yes, this upgrade was much needed.

Step 1: Debian 10 Buster to Debian 11 Bullseye

For this step I more or less followed these instructions. It was mostly as simple as bumping the version in the sources.list file. My sources.list file was pointed at a mirror that was no longer hosting this version of Debian, so I had to point it to the Debian archives, like this:

deb http://archive.debian.org/debian/ bullseye main
deb-src http://archive.debian.org/debian/ bullseye main

Then running the apt commands: sudo apt update and sudo apt full-upgrade. Note that the latter updated and restarted sshd, but I didn’t get disconnected. The install stopped and prompted me on a couple of config deltas. One was about the swappiness where it appears that my VPS provider had set it to zero at some point. I retained this config. The other was around the SSHD config where I had disabled root login over SSH in order to dissuade the kind of port-scanning bots that try common passwords on exposed SSH logins around the Internet.

Once the apt commands finished, I rebooted the machine and logged in again:

root@box:/# lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

But I have many more versions to go.

Debian 11 (bullseye) to Debian 12 (bookworm)

Since Debian 12 is officially supported, we have detailed upgrade release notes straight from the Debian project. Since these are the (lower case c, not to be confused with the folks who make Ubuntu) canonical instructions, I’m following them. These are much more in-depth than the previous step, having me remove obsolete packages and clean up some of the config file diffs and backups that the previous upgrade left behind.

Amusingly the release notes included this bit from Debian’s CLI user management tools:

  deluser's --no-preserve-root option is deprecated, and it will be
  removed after Debian bookworm. deluser will in the future completely
  refuse to delete the root user. If you want to delete root, you need
  to use other tools.

I’m not quire sure who wanted to delete the root user in the first place, apparently Debian will not support such uses with their tools.

This time I did manage to get disconnected when it restarted sshd, and dpkg complained the next time I ran it. This was easily fixed with dpkg configure -a. After another reboot and I’m now running Debian Bookworm, which technically is LTS supported.

root@hostname:/home/user# lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm
root@hostname:/home/user# uname -a
Linux hostname 6.1.0-50-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64 GNU/Linux

But since I’ve come this far, on to lucky Debian 13.

Debian 12 (Bookworm) to Debian 13 (Trixie)

Ah, we’re finally upgrading to a modern version of Debian! Checking the release notes showed one possible issue:

An issue in OpenSSH in bookworm can lead to inaccessible remote systems if an upgrade being supervised over an SSH connection is interrupted. Users may be unable to re-connect to the remote system to resume the upgrade.

That is a possible issue for me. So I check the version of OpenSSH first:

root@yagi:~# dpkg -l openssh-server
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version            Architecture Description
+++-==============-==================-============-=================================================================
ii  openssh-server 1:9.2p1-2+deb12u10 amd64        secure shell (SSH) server, for secure access from remote machines

With this resolved, I move on to doing the upgrade. Notably the format for package sources has changed with this release of Debian. As mentioned in the release notes I had to remove the traditional sources.list file and create a debian.sources file.

While upgrading, I came across this note in the patch notes:

  • The mesg(1) and write(1) programs are no longer provided. It is believed chatting between users is nowadays done using more secure facilities.

I still remember actually using this for its intended purposes back in college. While I get that this isn’t used all that often anymore, I’m still a little sad to see it go.

After a bit of wrangling with dpkg, I finally have it updated to Debian 13:

root@box:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 13 (trixie)
Release:	13
Codename:	trixie
root@box:~# uname -a
Linux box 6.1.0-50-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64 GNU/Linux

What’s next?

All and all it wasn’t too painful. I’ve got some minor shell locale issues to work out, other than some warning messages it’s not breaking anything that I’m aware of. Not bad knocking out this chore before breakfast!