Tag Archives: centos

Automatically set the hostname during Kickstart Installation

I hate having to manually set the hostname in kickstart file, so when I found a fix, I was very happy. I wish I can take credit, but it was originally made by somebody who was trying to figure out a way to automatically set the hostname for VMWare ESX machines. Unfortunately, I lost that link, so I can’t refer to the other page for credit. So the best I can do is to explain how it is done and hopefully I find that link later and update this post, so that the right person is properly attributed.

To explain how the solution works, its good to understand how Linux boots a system, which this article does a very good job of explaining. However, if you are impatient, this is short version:

  1. Computer turns on (DUH!)
  2. BIOS kick in, which performs POST, local device enumeration and initialization and then searches for active and bootable devices.
  3. Stage 1 (MBR) kicks in, looks for boot loader (in our case, GRUB)
  4. Grub (Stage 2) then loads kernel with an optional ramdisk.
  5. kernel boots, initializes and then starts init (or some other process) that then starts up other processes

Now with that mind, let’s take a look at our grub on jenkins:

[root@jenkins chef]# cat /etc/grub.conf 
# grub.conf generated by anaconda
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/vg_centos6-lv_root
#          initrd /initrd-[generic-]version.img
title CentOS (2.6.32-220.2.1.el6.x86_64)
	root (hd0,0)
	kernel /vmlinuz-2.6.32-220.2.1.el6.x86_64 ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos6/lv_swap rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb rd_LVM_LV=vg_centos6/lv_root  KEYBOARDTYPE=pc KEYTABLE=us crashkernel=auto rhgb quiet rd_NO_DM
	initrd /initramfs-2.6.32-220.2.1.el6.x86_64.img

As you can see, it boots the kernel, as well as set parameters such as root file system, language, keyboard and others things needs for the system to boot up properly. That information is actually still available in the running kernel by viewing the following file:

[root@jenkins chef]# cat /proc/cmdline 
ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos6/lv_swap rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb rd_LVM_LV=vg_centos6/lv_root  KEYBOARDTYPE=pc KEYTABLE=us  rhgb quiet rd_NO_DM
[root@jenkins chef]

Notice that in this file, you will find the same parameters as you find in the grub.conf. In some ways, if init (at least on System-V systems) is the mother of all process, the kernel is the grandmother, quietly hidden in the background.

What if you were to pass a parameter that it doesn’t recognize? In most cases, it will probably ignore it, but it will still in the kernel list. So lets insert:


to the kernel line right between “crashkernel=auto” and “rhgb” (either in grub or at kernel line at boot loader page during stage 2):

kernel /vmlinuz-2.6.32-220.2.1.el6.x86_64 ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos6/lv_swap rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb rd_LVM_LV=vg_centos6/lv_root  KEYBOARDTYPE=pc KEYTABLE=us crashkernel=auto FOO=BAR rhgb quiet rd_NO_DM

Now lets view /proc/cmdline again:

[root@jenkins ~]# cat /proc/cmdline 
ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos6/lv_swap rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb rd_LVM_LV=vg_centos6/lv_root  KEYBOARDTYPE=pc KEYTABLE=us  FOO=BAR rhgb quiet rd_NO_DM
[root@jenkins ~]# 

As we can see, FOO=BAR is in there, with no ill effects to the system boot.

So why would we want to pass a value that the kernel doesn’t use? So that we can do this:

[rilindo@jenkins ~]$ for x in `cat /proc/cmdline`
> do
> case $x in FOO*)
> eval $x
> echo "${FOO}" 
> ;;
> esac
> done
[rilindo@jenkins ~]$ 

What this script does is to get the output of /proc/cmdline as a series of positional elements (think of it like a list or an array) and loop through it. Then we will test each element through a case statement and if it matches (in this case, FOO), then it evaluates it to a variable. We then echo that variable, which will then return a value. In other words, we look for a section that has “FOO”, and get “BAR” out of it.

That is essentially how we automatically set the hostname in our installation. Using this technique, we put this script in our %pre section of our kickstart: 

for x in `cat /proc/cmdline`; do
        case $x in SERVERNAME*)
	        eval $x
		echo "network --device eth0 --bootproto dhcp --hostname ${SERVERNAME}.monzell.com" > /tmp/network.ks

Here, we look for a value called SERVERNAME and evaluates that value into a variable. We will then echo the network setup with the variable (which we will use as part of the hostname setup) and redirect into the file under /tmp. Then we will include that file in our installation section:

At this point, we are essentially done. To use it, we just need to pass SERVERNAME=X (where X is the name of the hostname you want to set) in our kickstart setup. In our case, we build virtual machines with KVM via virt-install, so we pass that in the following line:

virt-install --name jenkins --disk path=/home/vms/jenkins,size=50,bus=virtio --vnc --noautoconsole --vcpus=1 --ram=512 --network bridge=br0,mac=52:54:00:91:95:30 --location= -x "ks= SERVERNAME=jenkins"

Here is my entire kickstart file:

url --url
lang en_US.UTF-8
keyboard us
%include /tmp/network.ks

rootpw  --iscrypted PUTPASSWORDHERE
firewall --service=ssh
authconfig --enableshadow --passalgo=sha512 --enablefingerprint
selinux --enforcing
timezone --utc America/New_York
bootloader --location=mbr --driveorder=vda --append="crashkernel=auto rhgb quiet"
clearpart --all --drives=vda --initlabel

part /boot --fstype=ext4 --size=500
part pv.EPlgaf-h1b4-YqDI-2wfs-3C7I-SPPt-Agk5O7 --grow --size=1

volgroup vg_centos6 --pesize=4096 pv.EPlgaf-h1b4-YqDI-2wfs-3C7I-SPPt-Agk5O7
logvol / --fstype=ext4 --name=lv_root --vgname=vg_centos6 --grow --size=1024 --maxsize=51200
logvol swap --name=lv_swap --vgname=vg_centos6 --grow --size=1008 --maxsize=2016

repo --name="Local CentOS 6 - x86_64"  --baseurl=
repo --name="Local CentOS 6 - x86_64 - Updates"  --baseurl=
repo --name="Local Custom Installs" --baseurl=


for x in `cat /proc/cmdline`; do
        case $x in SERVERNAME*)
	        eval $x
		echo "network --device eth0 --bootproto dhcp --hostname ${SERVERNAME}.example.com" > /tmp/network.ks

%post --log=/root/my-post-log

setsebool -P use_nfs_home_dirs on
mkdir /home/users
mkdir /etc/chef

curl ${URLPOSTCONF}/6.2/repos/CentOS-Custom.repo -o /etc/yum.repos.d/CentOS-Custom.repo
curl ${URLPOSTCONF}/6.2/autofs/auto.master -o /etc/auto.master
curl ${URLPOSTCONF}/6.2/autofs/auto.home -o /etc/auto.home
curl ${URLPOSTCONF}/keys/cacert.pem -o /etc/openldap/cacerts/cacert.pem

curl ${URLPOSTCONF}/chef/validation.pem -o /etc/chef/validation.pem
curl ${URLPOSTCONF}/chef/client.rb -o /etc/chef/client.rb
curl ${URLPOSTCONF}/chef/first-run.json -o /etc/chef/first-run.json
rpm --import ${URLPOSTCONF}/keys/legacy.key
rpm --import ${URLPOSTCONF}/keys/custom.key

authconfig --enablesssd --enableldap --enableldaptls --ldapserver=kerberos.monzell.com --ldapbasedn="dc=monzell,dc=com" --enableldapauth --update

echo "nameserver" >> /etc/resolv.conf
echo "nameserver" >> /etc/resolv.conf

gem install chef
chef-client -j /etc/chef/first-run.json
chkconfig chef-client on
chkconfig rpcbind on
chkconfig sssd on
chkconfig ntpd on



Let me know if this is useful. And again, I didn’t originally came up with this, so I plead innocent to charges of plagiarism. 🙂

Installing Chef on CentOS

I have been playing around with Chef for the past week and while I liked it, it was a pain it setup. It seems to be work well if you run Debian and Ubuntu. Everything else … not so much.

First sign of trouble is when I attempt to bootstrap the install. The install calls for installing Ruby from the RBEL repo. Which I don’t have too much with trouble – in fact, they have binary RPMs of chef already available, so I used that initially and installed with:

yum install rubygem-chef-server --disablerepo=updates --disablerepo=CentOS-Custom --disablerepo=extras

(Centos-Custom is my own repo, by the way).

That went well – until it turns out that it installed Ruby 1.8 along with it.

So I got that removed. I spent the next few hours of trying (and failing) to install Ruby 1.9 while avoiding have to install 1.8. In the end, I gave up. Instead, what I did is the following:

  1. Installed the prerequisites  for ruby (including my build of Ruby 1.9 and Rubygems).
  2. Then, I ran “gem install ruby-shadow”, as there was no RPM for it in the CentOS repo.
  3. Then I installed the EPEL repo (instead of the RBEL repo). That allow to proceed with the install of chef with “gem install chef”. That, in turn, took care of all the requirements and package installation.

The next step is to configure a web proxy, as detail here. I decided to deviate slight and just use Red Hat’s utility with:

genkey chef.monzell.com

And then open the firewall ports.

However, because I had SELinux running, apache is not able to communicate to another application (as they are in different security context. So I had to enable access with:

setsebool -P httpd_can_network_connect on

That got me further, but I still had issues. After tailing the audit log and cat the output to audit2allow, I found that I still need to open a port in SELinux:

#============= httpd_t ==============

allow httpd_t reserved_port_t:tcp_socket name_bind;

I enabled access with:

[root@chef audit]# tail audit.log  | audit2allow -M chef444

******************** IMPORTANT ***********************

To make this policy package active, execute:

semodule -i chef444.pp

Installed the module and got the web access working.

There is more, but that’s for another post. 🙂

(as a side note, is there a tumbler theme that is code friendly – that is, I can paste in code and command line snippets without looking like snot?)

EDIT: Nevermind, looks like I’ll be poking around with CSS again to get it working the way I like.



CentOS has been criticized heavily earlier this year, mainly because of the big delay their distribution normally has (compared to the original RHEL releases).
One of the problems that comes with this delay is that security fixes that RedHat writes for their latest release are unavailable for…

Linux: CentOS CR for CentOS 6.0

The simple way of setting up NAT with iptables and Red Hat / CentOS and Scientific Linux

I always feel intimidated with setting NAT. I knew, of course, how to filter packets with iptables, but I always felt that NAT to be just a tad bit confusing. Then I studied for the RHCE exam and it turns out that it is a lot easier than I expected, with a little help from Red Hat’s firewall tool.

With earlier releases of Red Hat, the firewall tool is limited to just filtering by ports with no NAT or ACLs support. With version 6, the tool was significantly revamped. While ACLs are still not supported, you can now setup NAT with the firewall GUI. To get started, log yourself into the X-Windows GUI and run the following from the terminal.


Alternatively, you may run it from the menu -> System- Administration -> firewall. Or if you are logged remotely and you have X-Window running on your workstation, you can forward the tool over SSH to run it locally on your workstation by logging to the server with:

ssh -X username@hostname

and then run the “system-config-firewall.”

(One notable caution: if you have an existing iptables configuration, running this tool will wipe out your rules. Be sure to back /etc/system/iptables before you proceed further on this.)

From there, you will see the following options available:

Select “Masquerading” and then to your right, select the interface or interfaces you want your traffic to go through.

Congratulations, NAT is now setup! The next step is to setup forwarding to your devices or servers. Select “Port Forwarding” to your left:

Then click on add button at your right:


Then near the top of the following screen under the Source heading, click on the interface button, select your interface and click on OK

Then click the protocol button, select your protocol and then click on OK

Then click on the port button and select (or enter) your port(s) and then click on  OK:

Now under the Destination heading, select “Forward to another port” and enter the IP address of the machine you will forward the packets to in the field:

Then select the Port button or enter the port(s) you will be forwarding to:

Click on OK,  then OK to return to the main screen

From there, click on apply (which will write to the /etc/sysconfig/iptables file) and then reload (which will restart iptables).

(If you have backed up your iptables file, you may be able restore them with the custom rules option. However, the iptable backup must be in the iptables-save format, which presumably means that a custom-made one will not work).

You are mostly done here, but there is a couple of more changes youneed to make. First of all, though, lets login in via the command and take a look at the iptables file:

[root@sl6vmware sysconfig]# cat iptables

# Firewall configuration written by system-config-firewall

# Manual customization of this file is not recommended.






-A PREROUTING -i eth+ -p tcp --dport 20:21 -j DNAT --to-destination







-A INPUT -p icmp -j ACCEPT

-A INPUT -i lo -j ACCEPT

-A INPUT -i eth+ -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT


-A FORWARD -p icmp -j ACCEPT


-A FORWARD -i eth+ -j ACCEPT

-A FORWARD -o eth+ -j ACCEPT

-A FORWARD -i eth+ -m state --state NEW -m tcp -p tcp -d --dport 20:21 -j ACCEPT

-A INPUT -j REJECT --reject-with icmp-host-prohibited

-A FORWARD -j REJECT --reject-with icmp-host-prohibited


As you can see there, setting up NAT comprised of a few steps:

1) you set the table type, which at the beginning, would be *nat. If you were to do it from the command line, it would be the first part of the following statement

iptables -t nat <statement>

2) Then, you would set POSTROUTING s. From the command line, it will the second part of the statement we mention earlier.

iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE

At that point, the nat is setup.

3) From this point, it is just the matter of forwarding the packets based on source port (you can add the ACLs at this point, but the GUI tool will most likely overwrite them. Again, make sure that you have a backup!) . That is done by setting up a PREROUTING rule for a port, with:

-A PREROUTING -i eth+ -p tcp –dport 20:21 -j DNAT –to-destination

From the command line, it would be:

iptables -t nat -A PREROUTING -i eth+ -p tcp –dport 20:21 -j DNAT –to- destination

And then, you would add a FORWARD rule with:

-A FORWARD -i eth+ -m state –state NEW -m tcp -p tcp -d – dport 20:21 -j ACCEPT

Which, from the command line would be:

iptables -t filter -A FORWARD -i eth+ -m state –state NEW -m tcp -p tcp -d –dport 20:21 -j ACCEPT

Note that statement must be under the filter table, not under the nat table.

Getting this right via the command-line is fairly tricky even for experienced administrations, which is why the firewall tool is a great way to manage your rules for NAT (assuming that they are simple enough)

But you are not done yet. First, you need to make sure that you actually enable IP forwarding with the kernel.  You can set it dynamically with either:

sysctl -w net.ipv4.conf.all.forwarding =1


echo “1” > /proc/sys/net/ipv4/ip_forward

To change it permanently (which is what you want), add or change the  net.ipv4.conf.all.forwarding value  in /etc/sysctl.conf to:

net.ipv4.ip_forward = 1

And then reboot (assuming that you didn’t make the change dynamically).

At this point, there is one more thing you may  need to do, , particularly if you are running a FTP service.

With FTP, when a client connects to a server, the FTP server returns the response via different port (usually a high-number port above 1024). That becomes a problem when the client attempts to respond to that same port when the server is behind either a firewall or a NAT , as that port will most likely be blocked.

So there are 4 options you choose to address this problem.

1) Use SFTP. It is is encrypted and travels through the same port (22), so that is the best option. However, not all clients would have thats support.

2) Have the FTP server return a response to a specific port and open that port.

3) Have the client use passive mode

4) Modify the nat/firewall dynamically as well as modify the PORT and PASV commands dynamically.

We will go with the last option. Fortunately, it is not complicated in this case. We just need the open the following file:


And add (or change) the following:


This is a helper module that allows us to dynamically set the ports and track the FTP connectivity. It will load once you restart type iptables, either from the gui or from the command line with:

service iptables restart

If you were to prefer the load the module manual, you would run:

modprobe nf_nat_ftp

Which will load that module as the other supporting modules. You confirm whether it is loaded by running:

lsmod | grep ftp

Which will present you with the following output

nf_nat_ftp              3473  0 

nf_conntrack_ftp       12879  1 nf_nat_ftp

nf_nat                 22788  3 nf_nat_ftp,ipt_MASQUERADE,iptable_nat

nf_conntrack           79611  8 nf_nat_ftp,nf_conntrack_ftp,ipt_MASQUERADE,iptable_nat,nf_nat,nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state

Now you are done with NAT. You can start forwarding traffic to your internal servers and have them accessible from outside your network. 

For more information on setting up NAT, go to the following links:

http://www.linuxhomenetworking.com/wiki/index.php/Quick_HOWTO_:_Ch14_:_Linux_Firewalls_Using_iptables – A longer guide to setting up IP tables, with a section for NAT.

http://debianclusters.org/index.php/NAT_with_IPTables – Setting up IP tables with Debian-type distributions.

http://www.ncftp.com/ncftpd/doc/misc/ftp_and_firewalls.html – The problems you will encounter with with NAT and FTP.

Configuring ISCSI with RHEL, Scientific Linux or CentOS 6

I have been playing around with my new QNAP NAS appliance, getting the storage configured and the volumes setup with my Scientific Linux 6 virtual machines using  Daniel’s articles as a reference point. While the articles worked well easily for me at the beginning, setting client VMs with authentication to multiple targets took a bit more effort. Hopefully, this post will help those who may encounter this similar problem.

The first thing to do is the go through the configuration wizard to create the targets as documented in the article. Continue on until you get to this screen:

Choose “Use CHAP Authentication” (leave Mutual CHAP disabled for now), assigned it a login user and (THIS IMPORTANT), a password that is up to 16 chapters long. The wizard will not make it obvious that you exceeded your password field, so pay careful attention when you type in your credentials.

At any event, after entering your credentials, continue through the wizard and repeat until you reached the desired number of volumes (or LUNs). You will have the screen similar to this:

Note the IQNs. Those names will become important later.

On the client server, we will setup a iSCSI initiator. First, we will install the following package:


Assuming you have a repo setup, you can install it like this:

 yum -y install iscsi-initiator-utils

Then cd to /etc/iscsi. After backing the backup of the existing iscsi.conf file, you will enable or add the following:

node.session.auth.authmethod = CHAP

node.session.auth.username = puttargetusernamehere

node.session.auth.password = puttargetpasswordhere

discovery.sendtargets.auth.authmethod = CHAP

discovery.sendtargets.auth.username = puttargetusernamehere

discovery.sendtargets.auth.password = puttargetpasswordhere

Afterward, save the file and then enable iscsi for startup:

chkconfig iscsi on

And then bring up the service:

service iscsi start

It’s okay if you don’t see the “OK” response back yet. You are not done yet.

Now we will need to initiate a connection the NAS with the following command:

iscsiadm -m discoverydb -t st -p -D

What this will do is to pull a list of targets (this is when the actual ISCSI daemon on the initiator starts up):

[root@localhost iscsi]# iscsiadm -m discoverydb -t st -p -D

Starting iscsid:                                           [  OK  ],1 iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0005.c2d7bd,1 iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0004.c2d7bd,1 iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0003.c2d7bd,1 iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd,1 iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0001.c2d7bd

and save them to the following directory:

root@localhost iscsi]# cd /var/lib/iscsi/

[root@localhost iscsi]# ls

ifaces  isns  nodes  send_targets  slp  static

[root@localhost iscsi]# find .






























(It should be noted while the login credentials are saved as well in that directory, the files are only readable by root).

Finally, you will enable the initiator to login and attach to a specific LUN. Enter following with IQN of the LUN you will be using:

iscsiadm -m node -T iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd –login

For some reason, you have to pull a list of target first from the volume, otherwise, you will encounter something similar to this:

iscsiadm: no records found!

Now, assuming you have the correct login in the iscsi.conf and on the NAS volume, you will get the following screen:

[root@localhost iscsi]# iscsiadm -m node -T iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd –login

Logging in to [iface: default, target: iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd, portal:,3260]

Login to [iface: default, target: iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd, portal:,3260] successful.

Otherwise, you will get the following screen:

[root@localhost iscsi]# iscsiadm -m node -T iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd –login

Logging in to [iface: default, target: iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd, portal:,3260]

iscsiadm: Could not login to [iface: default, target: iqn.2004-04.com.qnap:ts-419pplus:iscsi.kvm0002.c2d7bd, portal:,3260].

iscsiadm: initiator reported error (19 – encountered non-retryable iSCSI login failure)

You will probably need to recheck your login. Worse case, you can always wiped the initiator config with:

iscsiadm -m discoverydb -t st -p -o delete

From this point, when you established a successful ISCSI connect, you will see the following in kernel buffer:

csi4 : iSCSI Initiator over TCP/IP

scsi 4:0:0:0: Direct-Access     QNAP     iSCSI Storage    3.1  PQ: 0 ANSI: 5

sd 4:0:0:0: [sda] 104857600 512-byte logical blocks: (53.6 GB/50.0 GiB)

sd 4:0:0:0: [sda] Write Protect is off

sd 4:0:0:0: [sda] Mode Sense: 2f 00 00 00

sd 4:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn’t support DPO or FUA

 sda: unknown partition table

sd 4:0:0:0: [sda] Attached SCSI disk

sd 4:0:0:0: Attached scsi generic sg0 type 0

If you see this, you are done. RHEL OS sees it as a regular block device and configures it accordingly. You may now partition and format it for production use.