Linux: How to Migrate Users to a New Host


Linux systems are mostly compatible with one another, even when their kernel versions are different. Hence, it is possible to migrate local user accounts from one system to the next with relative efficiency.

Although this can be procedural activities that Linux admins may sleep through with one eye open, one must stress the point of making backups prior to any system changes. Here’s an illustration of the ‘checkpoints’ taken to the test machine during this operation. Please perform due diligence as missteps can lead to dysfunctional target systems.

Moreover, the process of copying files from Source to Destination machines can vary. Option (a) is to copy .bak files as well as .tar.gz; and option (b) is to to perform raw copy of /home, /spool/mail, /spool/cron directories without dealing with tarballs. Both methods are given here, and one should only follow one path while ignoring the other.

  1. A complete system BACK UP is expected prior to performing this procedure.
  2. Thorough understanding of Linux users and permissions is required prior to attempting this migration.
  3.  The admin is advised to ascertain that there is sufficient disk space at the source to store migrating files
  4. The destination machine is assumed to be a clean Linux OS, without any apps or users created prior
  5. The users database is not Active Directory or OpenLDAP integrated.
  6. There are no guarantees that this migration procedure will work on all systems. This information is provided only as educational materials. The author will not be liable for possible damages and adverse effects of executing these scripts.
Step 1:

Check the existing server to determine whether there’s enough space to store migrating files

coco@test-box:~# df -h | grep '^[/|F]'
Filesystem Size Used Avail Use% Mounted on
/dev/sdb1 380G 210G 150G 60% /
/dev/sda1 236M 100M 124M 45% /boot
Step 2:

Create export files (while login to Source machine)

# Optional: check for proftpd status and stop its daemon
service proftpd status
sudo service proftpd stop

# Check Linux version
lsb_release -a # case Debian/Ubuntu
cat /etc/redhat-release # case Redhat/Centos

### Extract source system users to generate 4 files: passwd.bak, group.bak, shadow.bak, gshadow.bak ###

sudo su # masquerade as root
### input root password ###

uidLowerBound=500 # set User IDs to exclude (500 for RHEL, 1000 for Debian)
exportDirectory=/root/export # set migration directory
mkdir $exportDirectory;
cd $exportDirectory;
# rm $exportDirectory/* # Optional: remove files inside export directory

# Use awk to filter out system accounts and exclude lower bound UIDs
for f in /etc/{passwd,group}; do awk -F: -vID=$uidLowerBound '$3>=ID && $1!="nfsnobody"' $f |sort -nt: -k3 > ${f#/etc/}.bak; done
while read line; do grep -w "^${line%%:*}" /etc/shadow; done <passwd.bak >shadow.bak
while read line; do grep -w "^${line%%:*}" /etc/gshadow; done <group.bak >gshadow.bak

Source: this snippet was retrieved from

# Create tarballs of users' directories
tar -zcvpf $exportDirectory/home.tar.gz /home # backup home - this is always necessary
tar -zcvpf $exportDirectory/mail.tar.gz /var/spool/mail # run ls /var/spool/mail to see if there are contents to export
tar -zcvpf $exportDirectory/cron.tar.gz /var/spool/cron # this is optional as cron should be out of scope of users migration

Create Import Directory (while login to Destination machine)

# While SSH into Destination machine
# Create import folder
sudo mkdir $importFolder
cd $importFolder
rm $importFolder/*
ip a # get IP address
Step 3:

Copy files over to destination

# Test ssh connections (While SSH into Source machine)
ssh $adminUser@$remoteMachine -p$sshPort "echo 2>&1" && echo $remoteMachine SSH-SUCCESSFUL! || echo $remoteMachine SSH-FAILED!

# Don't use this command as it will yield false positives
# nc -zv $remoteMachine $sshPort

# Expected results
[coco@test-box home]# ssh $adminUser@$remoteMachine -p$sshPort "echo 2>&1" && echo $remoteMachine SSH-SUCCESSFUL! || echo $remoteMachine SSH-FAILED!
The authenticity of host '500.500.500.500 (500.500.500.500)' can't be established.
ECDSA key fingerprint is SHA256:...
Are you sure you want to continue connecting (yes/no/[fingerprint])? y
Please type 'yes', 'no' or the fingerprint: yes
Warning: Permanently added '500.500.500.500' (ECDSA) to the list of known hosts.
# masquerade as root
sudo su
### input root password ###

# Recommended: use scp to copy compressed files
# Use this method if the source files are all inside the /root/export folder
destinationDirectory=/root/import/ # the trailing slash is important!
scp -P $sshPort -r $sourceDirectory/* $adminUser@$remoteMachine:$destinationDirectory
# Optional: Use this method if there's a direct connection between old and new server without compressing any files to save disk space
# Raw copy /home, /var/spool/mail, /var/spool/cron directories
#scp -P $sshPort -r /home/* $adminUser@$remoteMachine:/home
#scp -P $sshPort -r /var/spool/mail/* $adminUser@$remoteMachine:/var/spool/mail
#scp -P $sshPort -r /var/spool/cron/* $adminUser@$remoteMachine:/var/spool/cron

Example: using WinSCP

Step 4:

Import users to destination Linux host (while SSH onto Destination)

Warning: these commands will over-write any users already present at the destination machine. It is highly advisable that this shall only be performed on a non-production machine. Again, backup, backup, and backup are three pervasive reminders.

sudo su # masquerade as root
### input root password ###

# Create a snapshot, checkpoint, or backup of the machine.
# Here’s an example in Hyper-V Manager: select the correct Host > pick correct VM Name > right-click > Checkpoint > OK

Hyper-V Snapshot

VMware Snapshot




# Extract the home directory contents
# format: tar -czvf name-of-archive.tar.gz /path/to/directory-or-file
# Read this:
importDirectory=/root/import # this should match the import directory in "Step 3"
cd $importDirectory;
tar -zxvf $importDirectory/home.tar.gz -C / # extract the tarball into intended destinations
tar -zxvf $importDirectory/mail.tar.gz -C / # z=call gunzip, x=extract, v=verbose, f=follow paths, -C=change directory and place extracted files there
tar -zxvf $importDirectory/cron.tar.gz -C /
# Make a backup of new server's users database
for f in /etc/{passwd,group,shadow,gshadow}; do cp $f $f.bak; done

# Import user accounts
for f in {passwd,group,shadow,gshadow}.bak; do cat $f >>/etc/${f%.bak}; done
# Undo users database changes (requires that the .bak files exist)
for f in /etc/{passwd,group,shadow,gshadow}.bak;
echo changing $originalName.bak to $originalName ...;
mv $originalName $originalName.bad; # change current file name to .bad
mv $f $originalName; # rename .bak file to its original name
# WARNING: this statement DELETES everything in the /home directory!
# How to purge all folders inside /home, except one
# find /home -mindepth 1 ! -regex $regexException -delete
### Reset root password if it has been overwritten incidentally ###

# Case LILO
Boot: linux single

# Case GRUB
Reboot > select correct kernel > press 'e' to edit > locate line starting with 'kernel' > append 'S' or 'Single' a the end of that line > press ENTER > press b to boot > type these commands:
mount -t proc proc /proc
mount -o remount,rw /
Posted on Categories Linux

Leave a Reply

Your email address will not be published. Required fields are marked *