Unattended Install of CentOS 6.3 with a USB Key

Here are the steps to create a bootable USB KEY that performs unattended installation of CentOS 6.3


  • I expect that you know what you are doing. Some of the commands provided can destroy your system if they are not used wisely!
  • A USB Key with at least 512MB capacity. It will be formatted during the process. Don’t forget to set USBKEY variable correctly. This is very important that you make sure you don’t execute the commands on another disk since it can destroy the data on  your system.
  • Download CentOS-6.3-x86_64-minimal.iso (I assume you have downloaded it in ~/Downloads)
  • Make sure you have the following commands installed on your system :
    • sfdisk
    • mkfs.vfat
    • grub-install
    • sudo (or root login)
  • If you want to add driver disk to the initrd.img you will also need :
    • cpio
    • xz
    • sudo
  • This procedure have been tested on Ubuntu 12.04 LTS

Initialize the USB key

In order to be able to boot from the USB key you need to make a bootable partition of type 0xB (FAT 32 C/H/S), other types might work as well, I haven’t tried.

The quickest way to do it is using sfdisk like this :
# modify the variable to suit your situation. BEWARE this is very important, 
# if you put the wrong device it can make your system unusable.
printf ";;b;*\n" | sudo sfdisk  ${USBKEY}

You can use -uM with sfdisk to specify the size in megabytes. It’s not relevant here since we are creating only one partition that fills the USB key.

After repartitioning your USB key, you will format it :
sudo mkfs.vfat -F 32 -n INSTALL ${USBKEY}1

Install Grub to your USB Key

Create mount point
sudo mkdir /tmp/INSTALL

Mount your USB key
sudo mount ${USBKEY}1 /tmp/INSTALL

Install grub on your USB key
sudo grub-install --force --root-directory=/tmp/INSTALL ${USBKEY}

Create a grub.cfg file

With your favorite editor create /tmp/INSTALL/boot/grub/grub.cfg
set timeout=5
set default=0

menuentry "Install CentOS 6.3" {
 linux /vmlinuz ksdevice=eth0 ks=hd:sda1:/ks.cfg --
 initrd /initrd.img

Create a Kickstart file

Create the file /tmp/INSTALL/ks.cfg
This is an example. You should customize your ks.cfg to suit your needs.
Keep in mind that the first harddisk will be sdb, since sda is the usbkey when you are booting.
lang en_US
keyboard us
timezone America/Montreal

rootpw --iscrypted  $1$bZB2mB8q$msVgTjbsA.RSvwiQjmr9R0
auth  --useshadow  --enablemd5
selinux --disabled
network --bootproto=dhcp --device=eth0
firewall --disabled

harddrive --dir=/ --partition=sda1

# Add some repo if you want (uncomment if needed)
#repo --name="EPEL6-x86_64" --baseurl=http://fedora.mirror.nexicom.net/epel/6/x86_64/
#repo --name="PuppetLabs" --baseurl=http://yum.puppetlabs.com/el/6/products/x86_64/

url --url http://less.cogeco.net/CentOS/6.3/os/x86_64/

zerombr yes
clearpart --all --initlabel
bootloader --location=mbr

# this is VERY IMPORTANT otherwise your USBKEY will be wiped during install process!
ignoredisk --drives=sda

# I’ve added fsoptions because I’m installing CentOS on SSD drives.
part swap --size 2048 --ondisk=sdb
part / --fstype ext4 --size 4096 --ondisk=sdb --fsoptions=discard,noatime,nodiratime
part /boot --fstype ext4 --size 512 --ondisk=sdb --fsoptions=discard,noatime,nodiratime
part /var --fstype ext4 --size 2048 --grow  --ondisk=sdb --fsoptions=discard,noatime,nodiratime

#customize the packages you want

You can change the password hash used in ks.cfg using this command :
openssl passwd -1

Copy files from the ISO

Create mount point

sudo mkdir /tmp/ISO

Mount the iso file
sudo mount -o loop ~/Downloads/CentOS-6.3-x86_64-minimal.iso  /tmp/ISO
Copy the kernel and initrd from the iso
sudo cp /tmp/ISO/isolinux/initrd.img /tmp/INSTALL/
sudo cp /tmp/ISO/isolinux/vmlinuz /tmp/INSTALL/

Copy the images directory from the iso
sudo cp -r /tmp/ISO/images/ /tmp/INSTALL/

Unmount the iso and the usb key
sudo umount /tmp/INSTALL/
sudo umount /tmp/ISO/

Your USB Key is now ready to boot and install CentOS 6.3!

OPTIONAL - Add a driver disk

If  you have specialized hardware, you probably need to add a driver disk during the installation process. The best way to add a driver disk to make an unattended installation is to add it to the root of initrd image with the name dd.img.

Anaconda will load automatically the driver disk during the installation process. Here are the steps recreate the initrd.img with the dd.img

sudo mount -o loop ~/Downloads/CentOS-6.3-x86_64-minimal.iso  /tmp/ISO
cd  /tmp/INSTALL/
# the directory should be empty if you followed the instructions. If it's not empty, make sure # you unmounted the /tmp/INSTALL directory.
# decompress initrd.img
xzcat --force /tmp/ISO/isolinux/initrd.img | cpio -ivdum
# recompress initrd.img in /tmp
find . -print |cpio -o -H newc | xz --format=lzma > /tmp/initrd.img
# clean the directory rm -rf /tmp/INSTALL/*
cd /tmp
# mount the USBKEY and copy the new initrd.img sudo mount ${USBKEY}1 /tmp/INSTALL
sudo cp  /tmp/initrd.img  /tmp/INSTALL
# unmount the CD and the USBKEY
sudo umount /tmp/INSTALL
sudo umount /tmp/ISO


How to sync svn repositories

Here's a simple receipe on how to sync a svn repository using svnsync.

First, create two variables. One to specify where is the source repository, the other to specify where is the target directory


Prepare the target directory

#Create the bare svn repository
svnadmin create .
#create a dummy pre-revprop-change hook
echo '#!/bin/bash' > hooks/pre-revprop-change
chmod +x hooks/pre-revprop-change
#prepare the target for the sync
svnsync initialize file://$(readlink -f $TARGET_SVN) $SOURCE_SVN

readlink makes sure that the path is in a canonized form.


svnsync sync file://$(readlink -f $TARGET_SVN) 

That's it!

You can repeat this part periodically to sync with the remote repository.


OpenVZ Centos/RedHat templates creation

I've recently found this article which is a good start on how to start to create a OpenVZ template from RPM based distribution such as RHEL, Fedora or Centos.

I'm working with Proxmox and there was some modification to do. 

So I decided to rewrite the tutorial, but it is highly inspired from the article. I recommend you to read the article before starting the following steps.


First I've installed on a VM Centos 6 using the netinstall.iso
I've chosen only the minimum installation.
The disk partitioning was done without LVM, only two partition 1GB swap, 9GB for / (formatted as ext4)

The only packages I've installed after the installation are openssh and openssh-server.
I've also ran an yum update and yum upgrade.

I've installed the Proxmox hypervisor (2.0RC), on a different VM using the ISO.

After the installation I've connected the hard disk of the Centos VM to the Hypervisor VM.

On the hypervisor, I suggest you to make a symbolic link to /vz so that you won't have to modify most of the scripts
ln -s /var/lib/vz /vz

Transferring to OpenVZ

Create a variable to identify the container ID
Make sure it is well assigned
echo $CTID

The following step will erase any existing container that use the $CTID number
rm -rf /vz/private/$CTID
mkdir /vz/private/$CTID 

For the rsync part, I was working on an hypervisor installed in a VM, I decided to connect the virtual hard drive of my newly installed minimal Centos 6 installation to the hypervisor instead of invoking rsync remotely 

I've mounted the Centos VM hard disk on the hypervisor on /media/centos6 and I've used this command to copy the file to the oz machine :
rsync -arvpz --numeric-ids --exclude=/dev --exclude=/mnt --exclude=/proc --exclude=/sys --exclude=/tmp  /media/centos6/ /vz/private/$CTID/

ftab modification
echo "none /dev/pts devpts rw 0 0" >  /vz/private/$CTID/etc/fstab
echo "proc /proc proc defaults 0 0" >> /vz/private/$CTID/etc/fstab

create directories
mkdir /vz/private/$CTID/dev
mkdir /vz/private/$CTID/mnt
mkdir /vz/private/$CTID/proc
mkdir /vz/private/$CTID/sys
mkdir /vz/private/$CTID/tmp
chmod 1777 /vz/private/$CTID/tmp 

I had a problem with the MAKEDEV command, the one provided by debian 6.0.4 (Used by Proxmox Hypervisor) does not work as the one described in the original HOWTO.
mkdir /vz/private/$CTID/dev/pts
mknod -m 600 /vz/private/$CTID/dev/console c 5 1
mknod -m 666 /vz/private/$CTID/dev/tty c 5 0
mknod -m 666 /vz/private/$CTID/dev/full c 1 7
mknod -m 600 /vz/private/$CTID/dev/initctl p
mknod -m 666 /vz/private/$CTID/dev/null c 1 3
mknod -m 666 /vz/private/$CTID/dev/ptmx c 5 2 
mknod -m 666 /vz/private/$CTID/dev/random c 1 8
mknod -m 444 /vz/private/$CTID/dev/urandom c 1 9 
mknod -m 666 /vz/private/$CTID/dev/zero c 1 5
mknod -m 660 /vz/private/$CTID/dev/pts/0 c 136 0
mknod -m 660 /vz/private/$CTID/dev/pts/1 c 136 1
mknod -m 000 /vz/private/$CTID/dev/pts/ptmx c 5 2
chown root.tty /vz/private/$CTID/dev/pts/0
chown root.tty /vz/private/$CTID/dev/pts/1

If you need to, set the interfaces to ONBOOT="no"
sed -i -e 's/ONBOOT="yes"/ONBOOT="no"/g'  /vz/private/$CTID/etc/sysconfig/network-scripts/ifcfg-eth*

remove HWADDR from the interfaces files
sed -i -e 's/^\(HWADDR=.*\)$//g' /vz/private/$CTID/etc/sysconfig/network-scripts/ifcfg-eth*

Change PROMPT=yes to PROMPT=no in sysconfig/init
sed -i -e 's/PROMPT=yes/PROMPT=no/g' /vz/private/$CTID/etc/sysconfig/init

Commenting out console from rc.conf
sed -i -e 's/^\(console.*\)$/#\1/g' /vz/private/$CTID/etc/init/rc.conf 

Making a default container configuration

(change centos-6-x86_64 for whatever distro you are creating a template for)
echo OSTEMPLATE=\"centos-6-x86_64\" > /etc/vz/conf/$CTID.conf
vzctl set $CTID --save --kmemsize 256M
vzctl set $CTID --save --lockedpages 256M
vzctl set $CTID --save --privvmpages unlimited
vzctl set $CTID --save --shmpages unlimited
vzctl set $CTID --save --numproc unlimited
vzctl set $CTID --save --physpages 512M
vzctl set $CTID --save --vmguarpages 0:unlimited
vzctl set $CTID --save --oomguarpages 0:unlimited
vzctl set $CTID --save --numtcpsock unlimited
vzctl set $CTID --save --numflock unlimited
vzctl set $CTID --save --numpty unlimited
vzctl set $CTID --save --numsiginfo unlimited
vzctl set $CTID --save --tcpsndbuf  unlimited
vzctl set $CTID --save --tcprcvbuf unlimited
vzctl set $CTID --save --othersockbuf unlimited
vzctl set $CTID --save --dgramrcvbuf unlimited
vzctl set $CTID --save --numothersock unlimited
vzctl set $CTID --save --numfile unlimited
vzctl set $CTID --save --dcachesize 116M:128M
vzctl set $CTID --save --numiptent unlimited
vzctl set $CTID --save --swappages 512M

vzctl set $CTID --save --quotatime 0
vzctl set $CTID --save --diskinodes 800000:880000
vzctl set $CTID --save --diskspace 1G

Enter in your OpenVZ container for cleanup

vzctl start $CTID
vzctl enter $CTID

Theses steps needs to be done from INSIDE your OpenVZ

Fix df 

rm -f /etc/mtab
ln -s /proc/mounts /etc/mtab 

remove ssh host keys

rm -f /etc/ssh/ssh_host_*

remove boot and kernel

rm -rf /boot/*.*
for i in `rpm -q kernel`; do rpm -e --nodeps $i; done

Remove unwanted packages (tested on Centos 6.2)

rpm -qa | egrep 'grub|fs|firmware|libdrm|b43-openfwwf|dracut|plymouth|qpid'
And proceed...
rpm -qa | egrep 'grub|fs|firmware|libdrm|b43-openfwwf|dracut|plymouth|qpid' | while read l; do rpm -e --nodeps $l; done

clean some other dependencies and unwanted stuff (might be centos specific)
yum remove matahari matahari-lib qpid-cpp-server

Clean rpm db :
yum clean all

Creating the template

Exit the OpenVZ container with "exit" and stop it
vzctl stop $CTID 

Final cleanup

rm /vz/private/$CTID/etc/resolv.conf
touch /vz/private/$CTID/etc/resolv.conf
rm /vz/private/$CTID/etc/hostname

Go to the CTID directory

cd /vz/private/$CTID

Create the tar file

tar --numeric-owner -zcf /vz/template/cache/centos-6.2-standard-x86_64.tar.gz .

Test the template

create a sample file (or get it from elsewere)

cp /etc/pve/openvz/$CTID.conf /etc/pve/openvz/ve-testOZ.conf-sample
sed -i -e 's/^OSTEMPLATE.*//g'  /etc/pve/openvz/ve-testOZ.conf-sample

Test it!

Do it using the command line or the web based interface.
vzctl create 123456 --ostemplate  centos-6.2-standard-x86_64  --config testOZ