Sometimes you feel the requirement to replace an installed operating system in-band, which means while the old system is running and providing you access to the hardware. Say you’ve got a “less desired” Linux distribution on a server and you want to replace it by Debian, but you have no physical access to it and neither the possibility to install a bootable installation media (CD, USB, …) through a KVM switch or similar.
In this tutorial I’m going to replace a running Fedora Linux installed on a single hard disk by Debian Squeeze, only by using a remote SSH connection and its swap partition.
Prerequisites
To apply my hints to your particular use case, it is not required to have a special hard disk layout or a special Linux distribution installed. Every recent Linux distributions might suit the purpose of being replaced by Debian, if it works at least partially as expected by several Debian tools. Note it must be some flavor of Linux though: You can’t bootstrap Debian over an existing Windows for instance, neither Solaris will. FreeBSD with the Linux compatibility layer enabled could eventually work, but I didn’t tried. I would happily like to hear about your failure oder success with FreeBSD. Problem is, you need the ability to execute Linux binaries and to install a boot loader which requires /dev access.
For my setup I used Fedora 14, which was installed into a single partition altogether with 2 GiB swap space. Note, it is important to understand the order of partitions do make a difference! If you installed your swap partition in the beginning of the hard disk, this eases your life a lot. This is, however, a very unlikely setting, therefore I didn’t assume you need. On the other hand I won’t cover a Linux installation spanning over several partitions (although this is does not fundamentally change the procedure). My partitioning looks like this:
/dev/sda1(ext4, used as root file system “/”)/dev/sda2(swap, used as swap space)
You will need some spare disk space which can be overwritten: Swap is fine, unpartitioned or unallocated space is fine, a mounted partition which is relinquishable is fine (think of /home among others may work, /var probably not. Be careful you will lose data in this case!). In total you won’t need much space, something around 512 MiB is ok (but you might need some cleanups in between then), a bit more won’t hurt. I used a 2 GiB swap partition, but I never required more than 523 MiB during the migration process.
Outline
This is a brief outline how I’m going to replace the existing Fedora installation by Debian. My assumption is, as said, you don’t have BIOS access and your only possibility to access the installation is remote through SSH. Don’t worry if you need more explanation, I will step through in detail afterwards:
- Claim some unused space, something around 512+ MiB is enough
- Format unused space
- Bootstrap Debian into the unused space
- Do the post installation setup (setup /etc/network/interfaces,
/etc/fstab, …) - Install the Debian grub boot loader into the master boot record (replace the boot loader from the original distribution)
- Boot into the new Debian installation
- Format the former root partition where the original Linux distribution is installed
- Shift the Debian installation to the fresh formatted root partition, (which was previously containing Fedora in my case)
- Reinstall boot loader again
- Boot into the new, shifted system
- Format swap partition, use it as swap partition again
Some random thoughts you may want to consider:
- This procedure is risky. It may result in an un-bootable system. If something gos wrong there is no recovery procedure you could use from remote.
- If you use LVM things are slightly more complicated, but the big picture is still the same.
- My goal is to replace a distribution in place without changing actual partition layout. An alternative approach would replace partitions by growing the Debian partition after the first boot. Note this is not possible if there is no unclaimed or unused space after the root partition. You can not easily expand a partition with new space available in front. This means for a common partitioning like mine, where I install Debian into
/dev/sda2, no free space is available after that partition, only before. This won’t allow you to grow such a partition.
Prepare installation disk
I already explained my partitioning before. Besides my starting position is a standard Fedora 14 installation, not having anything special in it. My Fedora installation has its root partition in and swap in /dev/sda2. Obviously I also enabled the SSH server.
[root@bootstrap arno]# fdisk -l Disk /dev/sda: 21.5 GB, 21474836480 bytes 255 heads, 63 sectors/track, 2610 cylinders, total 41943040 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x000ae12b Device Boot Start End Blocks Id System /dev/sda1 * 2048 36866047 18432000 83 Linux /dev/sda2 36866048 41943039 2538496 82 Linux swap / Solaris [root@bootstrap arno]# cat /etc/fedora-release Fedora release 14 (Laughlin)
Swap space is not essential for Linux and can be detached from a running system, so I’m going to use that partition to install Debian in it. This is a temporary solution, since swap space usually tends to be small, when compared to data disks. I will show how to shift data from this swap partition to the actual root file system later. First use swapoff /dev/sda2 to disable the swap partition and do a mkfs.ext4 /dev/sda2 to create a ext4 file system on it.
[root@bootstrap arno]# cat /proc/swaps
Filename Type Size Used Priority
/dev/sda2 partition 2538492 0 -1
[root@bootstrap arno]# swapo
swapoff swapon
[root@bootstrap arno]# swapoff /dev/sda2
[root@bootstrap arno]# mkfs.ext4 /dev/sda2
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
158720 inodes, 634624 blocks
31731 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=650117120
20 block groups
32768 blocks per group, 32768 fragments per group
7936 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 26 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.Bootstrap Debian
One of Debian’s greatest features is its bootstrap ability. You need very little to install a minimal but (almost) complete Debian installation into a single directory on an existing file system without much fuss. All you need is the debootstrap utility, which is a set of helper scripts, doing a Debian base install into a directory of your choice.
It requires a network connection and a Perl interpreter to run and a POSIX compliant shell. If you are already on a Debian system, you can simply install deboostrap through apt, package name is deboostrap (in reality you probably want to use apt-get dist-upgrade on such a system instead). If your distribution does not offer bootstrap, you can get the source package. You don’t need to compile anything, just run it straight out of the extracted tar ball. Chances are, your distribution offers debootstrap as package, Fedora for example does. Unfortunately Fedora won’t include perl in the default installation, so chances are you need to install both:
[root@bootstrap arno]# yum install debootstrap.noarch perl ... Complete!
Now you need to mount the ext4 file system you created previously. Use the mount point to bootstrap Debian into it. Don’t create any subdirectories! Fortunately this isn’t really complicated:
[root@bootstrap arno]# mount /dev/sda2 /mnt [root@bootstrap arno]# debootstrap --arch amd64 squeeze /mnt http://ftp.debian.org/debian I: Retrieving Release I: Retrieving Packages I: Validating Packages I: Resolving dependencies of required packages... I: Resolving dependencies of base packages... I: Found additional required dependencies: insserv libbz2-1.0 libdb4.8 libslang2 I: Found additional base dependencies: libnfnetlink0 libsqlite3-0 I: Checking component main on http://ftp.debian.org/debian... ... I: Base system installed successfully.
You will see quite a lot of output about packages being downloaded and installed. The procedure should result in a directory structure representing a Debian root file system. The “debootstrap output ends with I: Base system installed successfully., look for it to find out whether the procedure was successful.
As next step you have to mount /dev, /proc and /sys into the file Debian system. Strictly speaking /sys is not required, but it won’t hurt. Use a bind mount to clone the /dev tree. You need those pseudo file systems and the device drivers to complete the installation within the Debian chroot. You can run apt-get within the chroot, therefore you can install whatever you want, to get your system up and running in the next reboot. Note deboostrap won’t install a complete system, most notably boot loader and kernel is missing. Also some essential configuration is not realized by it. Moreover, if you need some special configuration, think of firmware packages for example, a WiFi network, or a VLAN setup, you are supposed to install all required packages by hand. By default, only simple wired network connections are supported out of the box.
Within the upcoming command sequence the chroot call is most essential. It runs an interactive shell within a special root directory. The resulting shell looks and feels pretty much like every other Debian system. Note there are some limitations and most notably you still run the Fedora kernel and its network configuration implicitly and /dev is from the host system’s kernel.
[root@bootstrap arno]# mount proc /mnt/proc -t proc [root@bootstrap arno]# mount sys /mnt/sys -t sysfs [root@bootstrap arno]# mount --bind /dev /mnt/dev/ [root@bootstrap arno]# chroot /mnt/ root@bootstrap:/# apt-get update Get:1 http://ftp.debian.org squeeze Release.gpg [1671 B] Ign http://ftp.debian.org/debian/ squeeze/main Translation-en Hit http://ftp.debian.org squeeze Release Hit http://ftp.debian.org squeeze/main amd64 Packages Fetched 1671 B in 10s (159 B/s) Reading package lists... Done
Make sure you still are in the chroot as explained above. You should install a kernel and the grub2 boot loader now. The editor vim in my command line below is purely optional, feel free to choose your personal preference instead. During installation of the kernel you might see some warnings: It is safe to ignore “Can not write log, openpty() failed (/dev/pts not mounted?)” and “df: Warning: cannot read table of mounted file systems: No such file or directory” there.
Install kernel and remaining bits
Afterwards build a minimal /etc/fstab file, suitable to boot your system. To avoid any confusion I prefer to use disk UUIDs instead of device names, as does the Debian installer for new installed systems as well. Use the blkid command to determine the disk UUID of your former swap partition, and add it as root file system to your /etc/fstab file:
root@bootstrap:/# apt-get install linux-image-2.6-amd64 grub2 vim root@bootstrap:/# echo "proc /proc proc defaults 0 0" >> /etc/fstab root@bootstrap:/# blkid /dev/sda2 /dev/sda2: UUID="8e5a4870-6f4f-481c-b36e-3b5735c19b18" TYPE="ext4" root@bootstrap:/# echo "UUID=8e5a4870-6f4f-481c-b36e-3b5735c19b18 / ext4 defaults 0 2" >> /etc/fstab
Next configure your network. If you connect from remote this is crucial! You need to know yourself how to configure your network and adapt network configuration to match your requirements. Open /etc/network/interfaces in your favorite editor. Mine looks like this for a DHCP auto configuration. Note again, this might not suite your needs.
# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or # /usr/share/doc/ifupdown/examples for more information. # The loopback network interface auto lo iface lo inet loopback allow-hotplug eth0 iface eth0 inet dhcp
See the referenced man pages for more examples. Now set up a system host name and verify if your name server configuration looks suitable. debootstrap copies your existing /etc/resolv.conf file from the host system if found.
root@bootstrap:/# echo "bootstrap" > /etc/hostname
root@bootstrap:/# vi /etc/resolv.conf # copied over
Now, as you have created a
/etc/fstab file, you might need to change the initial ram disk to reflect your changes in the initial ram disk. To do so, use update-initramfs. Once more it is safe again to ignore warnings about the inability to read mounted file systems (which is, by the way, because /etc/mtab is missing – don’t worry, you don’t need it). Furthermore don’t forget to set a root password with passwd!
root@bootstrap:/# update-initramfs -u -k all update-initramfs: Generating /boot/initrd.img-2.6.32-5-amd64 df: Warning: cannot read table of mounted file systems: No such file or directory root@bootstrap:/# passwd Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
A random side note: If you switch from Fedora, CentOS or RHEL the passwd command might fail like this:
root@bootstrap:/# passwd passwd: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 is not authorized to change the password of root
This is because those distributions enable SELinux by default, which prevents to set a root password. However /etc/shadow within the chroot does not carry a SELinux context, as Debian does not enable or enforce SELinux policies unless explicitly installed. To solve this issue leave the chroot for a moment (just type exit) and mount
/selinux
into it, since passwd will read in
/selinux
whether the caller is authorized to change the password file on a SELinux enabled system. Afterwards switch again into the Debian chroot and try again:
[root@bootstrap arno]# mount --bind /selinux /mnt/selinux/ [root@bootstrap arno]# chroot /mnt root@bootstrap:/# passwd ...
Once you did, you are almost done. Maybe you want to install the SSH server as well:
root@bootstrap:/# apt-get install ssh Setting up openssh-server (1:5.5p1-6) ... Creating SSH2 RSA key; this may take some time ... Creating SSH2 DSA key; this may take some time ... Restarting OpenBSD Secure Shell server: sshd. Setting up xauth (1:1.0.4-1) ... Setting up ssh (1:5.5p1-6) ... ...
As last step you need to install the boot loader on your disk. Be careful, upon completion of this step you won’t be able to boot into your original system anymore. You need to replace the boot loader from the original operating system since that one would boot you into Fedora. Therefore, for my setup I need to replace Fedora’s bootloader by Debian’s grub.
If you want to be more careful, you might want to consider to install Debian’s grub into the partition boot record /dev/sda2 instead of the master boot record, and chain load it from the original (i.e. Fedora’s) boot loader instead. This needs additional tuning though, I won’t cover this here.
root@bootstrap:/# update-grub Generating grub.cfg ... Found linux image: /boot/vmlinuz-2.6.32-5-amd64 Found initrd image: /boot/initrd.img-2.6.32-5-amd64 done root@bootstrap:/# grub-install /dev/sda Installation finished. No error reported.
Reboot into the temporary system
That was it. Leave the chroot and reboot your machine. If everything went good you are booted into Debian which hopefully brings up your network interface. Note the RSA host key changed, therefore you will see a nasty SSH warning. In this particular case you are safe to ignore it.
[arno@snowball:~]$ ssh 192.168.2.22 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! [arno@snowball:~]$ ssh 192.168.2.22 -lroot root@192.168.2.22's password: Linux bootstrap 2.6.32-5-amd64 #1 SMP Mon Mar 7 21:35:22 UTC 2011 x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. ...
Log in and verify whether you actually booted into your new system. You should have booted into your former swap partition, which is /dev/sda2 in my case. Until now the actual data partition, which contains your former operating system, is kept as is. Now, as the data partition is not being actively used anymore you can start working with it. Therefore you can format it now and prepare it to be used as root file system for Debian afterwards:
root@bootstrap:~# mkfs.ext4 /dev/sda1
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
1152816 inodes, 4608000 blocks
230400 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
141 block groups
32768 blocks per group, 32768 fragments per group
8176 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 23 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.Prepare data partition
You can simply copy everything from your existing and previously installed Debian installation and purge the old copy afterwards. However make sure you keep file permissions, owener and perhaps time stamps. I suggest you to use find in combination with cpio. See the full command below. The -xdev argument makes sure, find won’t cross file system boundaries which is required to avoid copy loops, since /mnt must be skipped while copying data (moreover /proc, /dev will cause problems as well, if you don’t skip them). The cpio command looks rather cryptic but basically I enable ‘copy-pass mode‘ (read more about cpio in the corresponding man page) and make sure you preserve modification times. The -V will print a dot for every file being copied over.
root@bootstrap:~# mount /dev/sda1 /mnt/ root@bootstrap:~# cd / root@bootstrap:/# find . -xdev -print0 | cpio -pamd0V /mnt ........................................................................................................................ 854050 blocks
Make sure you didn’t forget anything. Don’t worry about temporary files like /etc/mtab, files in /var/run and so on. Fortunately Debian won’t care upon next boot for most of them. Nonetheless you need to change some things before you can actually boot this copied data. Therefore mount pseudo file systems (/dev, /proc, /sys) again and chroot into the copied data partition. Change /etc/fstab once again, but this time make sure you choose the data partition as future root file system.
root@bootstrap:~# mount /dev/sda1 /mnt root@bootstrap:~# mount --bind /sys /mnt/sys root@bootstrap:~# mount --bind /proc /mnt/proc/ root@bootstrap:~# mount --bind /dev /mnt/dev root@bootstrap:~# chroot /mnt/ root@bootstrap:/# blkid /dev/sda1 /dev/sda1: UUID="44b02850-daf9-4401-985a-a1b2211bd3fb" TYPE="ext4" root@bootstrap:/# vi /etc/fstab root@bootstrap:/# cat /etc/fstab # UNCONFIGURED FSTAB FOR BASE SYSTEM proc /proc proc defaults 0 0 UUID=44b02850-daf9-4401-985a-a1b2211bd3fb / ext4 defaults 0 2
Once again you need to rebuild the grub configuration, this time you will update the file system you want to boot from, as /boot/grub, being copied, still points to the swap partition in /dev/sda2. Fortunately Debian will take care about those things if you call update-grub within the chroot. Again: Call it from the chroot with /etc/fstab already being updated. Same holds for grub-install which will update the master boot record to point to /dev/sda1 to lookup for /boot.
root@bootstrap:/# update-grub Generating grub.cfg ... Found linux image: /boot/vmlinuz-2.6.32-5-amd64 Found initrd image: /boot/initrd.img-2.6.32-5-amd64 done root@bootstrap:/# grub-install /dev/sda Installation finished. No error reported.
As soon as you did, leave the chroot and reboot. You should be boot into the same system as before, but this time booted from /dev/sda1 where, in my case, Fedora was originally installed. This leaves /dev/sda2 available for swap usage again.
root@bootstrap:~# mount /dev/sda1 on / type ext4 (rw) tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) root@bootstrap:~# mkswap /dev/sda2 Setting up swapspace version 1, size = 2538492 KiB no label, UUID=1858a22d-e622-4744-8930-4214b0907f4b root@bootstrap:~# swapon /dev/sda2 You can verify, everything looks good by using <code>free</code> or querying <code>/proc/swaps</code>:
root@bootstrap:~# free
total used free shared buffers cached
Mem: 1027264 38812 988452 0 2972 14356
-/+ buffers/cache: 21484 1005780
Swap: 0 0 0
root@bootstrap:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 18G 627M 16G 4% /
tmpfs 502M 0 502M 0% /lib/init/rw
udev 497M 108K 497M 1% /dev
tmpfs 502M 4.0K 502M 1% /dev/shmRemaining Bits
That was it. You successfully replaced your former Linux distribution by Debian if you reached this step. Your Debian installation might behave like every other upon this point. You might tweak your /etc/fstab again to take care about pseudo file system you need and aren’t mounted automatically.















2 comments
3 pings
Jim says:
April 22, 2012 at 13:11 (UTC 1)
This is great. I used it to put Debian stable on my mother’s (Arkansas) and mother-in-law’s (California) machines from Atlanta. Thank you!
Lawrence says:
June 27, 2012 at 08:01 (UTC 1)
It enhances my Linux concepts. Thanks for such a good article.
debootstrap can't cd to /mnt/debinst says:
September 21, 2012 at 23:50 (UTC 1)
[...] up & running using these 2 threads: http://www.debian.org/releases/stable/i386/apds03.html http://daemonkeeper.net/668/how-to-b…-linux-system/ The system is an active running desktop, I do have a few minor issues to resolve, but they don't [...]
Installing from a hard drive partition using grub. says:
September 22, 2012 at 17:42 (UTC 1)
[...] you running commands as root? This post has all of the mounts with the exception of devpts http://daemonkeeper.net/668/how-to-b…-linux-system/ You have to configure devpts the same way that you do inpost above this line [...]
FHS related question - '/dev' Using Lubuntu says:
September 24, 2012 at 19:03 (UTC 1)
[...] http://daemonkeeper.net/668/how-to-b…-linux-system/ http://sdn.vlsm.org/share/LDP/lfs/chapter06/proc.html [...]