linux documentation

This linux documentation section is just beginning. The plan is to develop a thorough linux admin site with summary and indepth information so linux users can put together a solid environment from beginning to end without grasping for straws "googling" information.-

installation

Right now this section has the grub documentation, very soon I'll add the fedora installation.

introduction to grub

Briefly, a boot loader is the first software program that runs when a computer starts. It is responsible for loading and transferring control to an operating system kernel software (such as Linux or GNU Mach). The kernel, in turn, initializes the rest of the operating system (e.g. a GNU system).

GNU GRUB is a very powerful boot loader, which can load a wide variety of free operating systems, as well as proprietary operating systems with chain-loading(1). GRUB is designed to address the complexity of booting a personal computer; both the program and this manual are tightly bound to that computer platform, although porting to other platforms may be addressed in the future.

One of the important features in GRUB is flexibility; GRUB understands filesystems and kernel executable formats, so you can load an arbitrary operating system the way you like, without recording the physical position of your kernel on the disk. Thus you can load the kernel just by specifying its file name and the drive and partition where the kernel resides.

When booting with GRUB, you can use either a command-line interface (see section 12.1 The flexible command-line interface), or a menu interface (see section 12.2 The simple menu interface). Using the command-line interface, you type the drive specification and file name of the kernel manually. In the menu interface, you just select an OS using the arrow keys. The menu is based on a configuration file which you prepare beforehand (see section 5. Configuration). While in the menu, you can switch to the command-line mode, and vice-versa. You can even edit menu entries before using them.

In the following chapters, you will learn how to specify a drive, a partition, and a file name (see section 2. Naming convention) to GRUB, how to install GRUB on your drive (see section 3. Installation), and how to boot your OSes (see section 4. Booting), step by step.

Besides the GRUB boot loader itself, there is a grub shell grub (see section 15. Invoking the grub shell) which can be run when you are in your operating system. It emulates the boot loader and can be used for installing the boot loader.

grub features

The primary requirement for GRUB is that it be compliant with the Multiboot Specification, which is described in section `Motivation' in The Multiboot Specification.

The other goals, listed in approximate order of importance, are:

  • Basic functions must be straightforward for end-users.
  • Rich functionality to support kernel experts and designers.
  • Backward compatibility for booting FreeBSD, NetBSD, OpenBSD, and Linux. Proprietary kernels (such as DOS, Windows NT, and OS/2) are supported via a chain-loading function.

Except for specific compatibility modes (chain-loading and the Linux piggyback format), all kernels will be started in much the same state as in the Multiboot Specification. Only kernels loaded at 1 megabyte or above are presently supported. Any attempt to load below that boundary will simply result in immediate failure and an error message reporting the problem.

In addition to the requirements above, GRUB has the following features (note that the Multiboot Specification doesn't require all the features that GRUB supports):

Recognize multiple executable formats
Support many of the a.out variants plus ELF. Symbol tables are also loaded.
Support non-Multiboot kernels
Support many of the various free 32-bit kernels that lack Multiboot compliance (primarily FreeBSD, NetBSD, OpenBSD, and Linux). Chain-loading of other boot loaders is also supported.
Load multiples modules
Fully support the Multiboot feature of loading multiple modules.
Load a configuration file
Support a human-readable text configuration file with preset boot commands. You can also load another configuration file dynamically and embed a preset configuration file in a GRUB image file. The list of commands (see section 13. The list of available commands) are a superset of those supported on the command-line. An example configuration file is provided in 5. Configuration.
Provide a menu interface
A menu interface listing preset boot commands, with a programmable timeout, is available. There is no fixed limit on the number of boot entries, and the current implementation has space for several hundred.
Have a flexible command-line interface
A fairly flexible command-line interface, accessible from the menu, is available to edit any preset commands, or write a new boot command set from scratch. If no configuration file is present, GRUB drops to the command-line.

The list of commands (see section 13. The list of available commands) are a subset of those supported for configuration files. Editing commands closely resembles the Bash command-line (see section `Command Line Editing' in Bash Features), with TAB-completion of commands, devices, partitions, and files in a directory depending on context.

Support multiple filesystem types
Support multiple filesystem types transparently, plus a useful explicit blocklist notation. The currently supported filesystem types are BSD FFS, DOS FAT16 and FAT32, Minix fs, Linux ext2fs, ReiserFS, JFS, XFS, and VSTa fs. See section 11. Filesystem syntax and semantics, for more information.
Support automatic decompression
Can decompress files which were compressed by gzip. This function is both automatic and transparent to the user (i.e. all functions operate upon the uncompressed contents of the specified files). This greatly reduces a file size and loading time, a particularly great benefit for floppies.(2)

It is conceivable that some kernel modules should be loaded in a compressed state, so a different module-loading command can be specified to avoid uncompressing the modules.

Access data on any installed device
Support reading data from any or all floppies or hard disk(s) recognized by the BIOS, independent of the setting of the root device.
Be independent of drive geometry translations
Unlike many other boot loaders, GRUB makes the particular drive translation irrelevant. A drive installed and running with one translation may be converted to another translation without any adverse effects or changes in GRUB's configuration.
Detect all installed RAM
GRUB can generally find all the installed RAM on a PC-compatible machine. It uses an advanced BIOS query technique for finding all memory regions. As described on the Multiboot Specification (see section `Motivation' in The Multiboot Specification), not all kernels make use of this information, but GRUB provides it for those who do.
Support Logical Block Address mode
In traditional disk calls (called CHS mode), there is a geometry translation problem, that is, the BIOS cannot access over 1024 cylinders, so the accessible space is limited to at least 508 MB and to at most 8GB. GRUB can't universally solve this problem, as there is no standard interface used in all machines. However, several newer machines have the new interface, Logical Block Address (LBA) mode. GRUB automatically detects if LBA mode is available and uses it if available. In LBA mode, GRUB can access the entire disk.
Support network booting
GRUB is basically a disk-based boot loader but also has network support. You can load OS images from a network by using the TFTP protocol.
Support remote terminals
To support computers with no console, GRUB provides remote terminal support, so that you can control GRUB from a remote host. Only serial terminal support is implemented at the moment.

1.4 The role of a boot loader

<!--docid::SEC5::-->

The following is a quotation from Gordon Matzigkeit, a GRUB fanatic:

Some people like to acknowledge both the operating system and kernel when they talk about their computers, so they might say they use "GNU/Linux" or "GNU/Hurd". Other people seem to think that the kernel is the most important part of the system, so they like to call their GNU operating systems "Linux systems."

I, personally, believe that this is a grave injustice, because the boot loader is the most important software of all. I used to refer to the above systems as either "LILO"(3) or "GRUB" systems.

Unfortunately, nobody ever understood what I was talking about; now I just use the word "GNU" as a pseudonym for GRUB.

So, if you ever hear people talking about their alleged "GNU" systems, remember that they are actually paying homage to the best boot loader around... GRUB!

We, the GRUB maintainers, do not (usually) encourage Gordon's level of fanaticism, but it helps to remember that boot loaders deserve recognition. We hope that you enjoy using GNU GRUB as much as we did writing it.

naming convention

GRUB Naming convention

The device syntax used in GRUB is a wee bit different from what you may have seen before in your operating system(s), and you need to know it so that you can specify a drive/partition.

Look at the following examples and explanations:

(fd0)

First of all, GRUB requires that the device name be enclosed with `(' and `)'. The `fd' part means that it is a floppy disk. The number `0' is the drive number, which is counted from zero. This expression means that GRUB will use the whole floppy disk.

(hd0,1)

Here, `hd' means it is a hard disk drive. The first integer `0' indicates the drive number, that is, the first hard disk, while the second integer, `1', indicates the partition number (or the PC slice number in the BSD terminology). Once again, please note that the partition numbers are counted from zero, not from one. This expression means the second partition of the first hard disk drive. In this case, GRUB uses one partition of the disk, instead of the whole disk.

(hd0,4)

This specifies the first extended partition of the first hard disk drive. Note that the partition numbers for extended partitions are counted from `4', regardless of the actual number of primary partitions on your hard disk.

(hd1,a)

This means the BSD `a' partition of the second hard disk. If you need to specify which PC slice number should be used, use something like this: `(hd1,0,a)'. If the PC slice number is omitted, GRUB searches for the first PC slice which has a BSD `a' partition.

Of course, to actually access the disks or partitions with GRUB, you need to use the device specification in a command, like `root (fd0)' or `unhide (hd0,2)'. To help you find out which number specifies a partition you want, the GRUB command-line (see section 12.1 The flexible command-line interface) options have argument completion. This means that, for example, you only need to type

root (

followed by a TAB, and GRUB will display the list of drives, partitions, or file names. So it should be quite easy to determine the name of your target partition, even with minimal knowledge of the syntax.

Note that GRUB does not distinguish IDE from SCSI - it simply counts the drive numbers from zero, regardless of their type. Normally, any IDE drive number is less than any SCSI drive number, although that is not true if you change the boot sequence by swapping IDE and SCSI drives in your BIOS.

Now the question is, how to specify a file? Again, consider an example:

(hd0,0)/vmlinuz

This specifies the file named `vmlinuz', found on the first partition of the first hard disk drive. Note that the argument completion works with file names, too.

That was easy, admit it. Now read the next chapter, to find out how to actually install GRUB on your drive.

<!--docid::SEC6::-->

Installation

In order to install GRUB as your boot loader, you need to first install the GRUB system and utilities under your UNIX-like operating system (see section A. How to obtain and build GRUB). You can do this either from the source tarball, or as a package for your OS.

After you have done that, you need to install the boot loader on a drive (floppy or hard disk). There are two ways of doing that - either using the utility grub-install (see section 16. Invoking grub-install) on a UNIX-like OS, or by running GRUB itself from a floppy. These are quite similar, however the utility might probe a wrong BIOS drive, so you should be careful.

Also, if you install GRUB on a UNIX-like OS, please make sure that you have an emergency boot disk ready, so that you can rescue your computer if, by any chance, your hard drive becomes unusable (unbootable).

GRUB comes with boot images, which are normally put in the directory `/usr/share/grub/i386-pc'. If you do not use grub-install, then you need to copy the files `stage1', `stage2', and `*stage1_5' to the directory `/boot/grub'. Hereafter, the directory where GRUB images are initially placed (normally `/usr/share/grub/i386-pc') will be called the image directory, and the directory where the boot loader needs to find them (usually `/boot/grub') will be called the boot directory.

3.1 Creating a GRUB boot floppy
3.2 Installing GRUB natively
3.3 Installing GRUB using grub-install
3.4 Making a GRUB bootable CD-ROM

3.1 Creating a GRUB boot floppy

To create a GRUB boot floppy, you need to take the files `stage1' and `stage2' from the image directory, and write them to the first and the second block of the floppy disk, respectively.

Caution: This procedure will destroy any data currently stored on the floppy.

On a UNIX-like operating system, that is done with the following commands:

# cd /usr/share/grub/i386-pc
# dd if=stage1 of=/dev/fd0 bs=512 count=1
1+0 records in
1+0 records out
# dd if=stage2 of=/dev/fd0 bs=512 seek=1
153+1 records in
153+1 records out
#

The device file name may be different. Consult the manual for your OS.

3.2 Installing GRUB natively

Caution: Installing GRUB's stage1 in this manner will erase the normal boot-sector used by an OS.

GRUB can currently boot GNU Mach, Linux, FreeBSD, NetBSD, and OpenBSD directly, so using it on a boot sector (the first sector of a partition) should be okay. But generally, it would be a good idea to back up the first sector of the partition on which you are installing GRUB's stage1. This isn't as important if you are installing GRUB on the first sector of a hard disk, since it's easy to reinitialize it (e.g. by running `FDISK /MBR' from DOS).

If you decide to install GRUB in the native environment, which is definitely desirable, you'll need to create a GRUB boot disk, and reboot your computer with it. Otherwise, see 3.3 Installing GRUB using grub-install.

Once started, GRUB will show the command-line interface (see section 12.1 The flexible command-line interface). First, set the GRUB's root device(4) to the partition containing the boot directory, like this:

grub> root (hd0,0)

If you are not sure which partition actually holds this directory, use the command find (see section 13.3.11 find), like this:

grub> find /boot/grub/stage1

This will search for the file name `/boot/grub/stage1' and show the devices which contain the file.

Once you've set the root device correctly, run the command setup (see section 13.3.34 setup):

grub> setup (hd0)

This command will install the GRUB boot loader on the Master Boot Record (MBR) of the first drive. If you want to put GRUB into the boot sector of a partition instead of putting it in the MBR, specify the partition into which you want to install GRUB:

grub> setup (hd0,0)

If you install GRUB into a partition or a drive other than the first one, you must chain-load GRUB from another boot loader. Refer to the manual for the boot loader to know how to chain-load GRUB.

After using the setup command, you will boot into GRUB without the GRUB floppy. See the chapter 4. Booting to find out how to boot your operating systems from GRUB.

3.3 Installing GRUB using grub-install

Caution: This procedure is definitely less safe, because there are several ways in which your computer can become unbootable. For example, most operating systems don't tell GRUB how to map BIOS drives to OS devices correctly--GRUB merely guesses the mapping. This will succeed in most cases, but not always. Therefore, GRUB provides you with a map file called the device map, which you must fix if it is wrong. See section 15.3 The map between BIOS drives and OS devices, for more details.

If you still do want to install GRUB under a UNIX-like OS (such as GNU), invoke the program grub-install (see section 16. Invoking grub-install) as the superuser (root).

The usage is basically very simple. You only need to specify one argument to the program, namely, where to install the boot loader. The argument can be either a device file (like `/dev/hda') or a partition specified in GRUB's notation. For example, under Linux the following will install GRUB into the MBR of the first IDE disk:

# grub-install /dev/hda

Likewise, under GNU/Hurd, this has the same effect:

# grub-install /dev/hd0

If it is the first BIOS drive, this is the same as well:

# grub-install '(hd0)'

Or you can omit the parentheses:

# grub-install hd0

But all the above examples assume that GRUB should use images under the root directory. If you want GRUB to use images under a directory other than the root directory, you need to specify the option `--root-directory'. The typical usage is that you create a GRUB boot floppy with a filesystem. Here is an example:

# mke2fs /dev/fd0
# mount -t ext2 /dev/fd0 /mnt
# grub-install --root-directory=/mnt fd0
# umount /mnt

Another example is when you have a separate boot partition which is mounted at `/boot'. Since GRUB is a boot loader, it doesn't know anything about mountpoints at all. Thus, you need to run grub-install like this:

# grub-install --root-directory=/boot /dev/hda

By the way, as noted above, it is quite difficult to guess BIOS drives correctly under a UNIX-like OS. Thus, grub-install will prompt you to check if it could really guess the correct mappings, after the installation. The format is defined in 15.3 The map between BIOS drives and OS devices. Please be quite careful. If the output is wrong, it is unlikely that your computer will be able to boot with no problem.

Note that grub-install is actually just a shell script and the real task is done by the grub shell grub (see section 15. Invoking the grub shell). Therefore, you may run grub directly to install GRUB, without using grub-install. Don't do that, however, unless you are very familiar with the internals of GRUB. Installing a boot loader on a running OS may be extremely dangerous.

3.4 Making a GRUB bootable CD-ROM

GRUB supports the no emulation mode in the El Torito specification(5). This means that you can use the whole CD-ROM from GRUB and you don't have to make a floppy or hard disk image file, which can cause compatibility problems.

For booting from a CD-ROM, GRUB uses a special Stage 2 called `stage2_eltorito'. The only GRUB files you need to have in your bootable CD-ROM are this `stage2_eltorito' and optionally a config file `menu.lst'. You don't need to use `stage1' or `stage2', because El Torito is quite different from the standard boot process.

Here is an example of procedures to make a bootable CD-ROM image. First, make a top directory for the bootable image, say, `iso':

$ mkdir iso

Make a directory for GRUB:

$ mkdir -p iso/boot/grub

Copy the file `stage2_eltorito':

$ cp /usr/share/grub/i386-pc/stage2_eltorito iso/boot/grub

If desired, make the config file `menu.lst' under `iso/boot/grub' (see section 5. Configuration), and copy any files and directories for the disc to the directory `iso/'.

Finally, make a ISO9660 image file like this:

$ mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \
-boot-load-size 4 -boot-info-table -o grub.iso iso

This produces a file named `grub.iso', which then can be burned into a CD (or a DVD). mkisofs has already set up the disc to boot from the boot/grub/stage2_eltorito file, so there is no need to setup GRUB on the disc. (Note that the -boot-load-size 4 bit is required for compatibility with the BIOS on many older machines.)

You can use the device `(cd)' to access a CD-ROM in your config file. This is not required; GRUB automatically sets the root device to `(cd)' when booted from a CD-ROM. It is only necessary to refer to `(cd)' if you want to access other drives as well.

booting

GRUB can load Multiboot-compliant kernels in a consistent way, but for some free operating systems you need to use some OS-specific magic.

4.1 How to boot operating systems How to boot OSes with GRUB generally
4.2 Some caveats on OS-specific issues Notes on some operating systems

4.1 How to boot operating systems

GRUB has two distinct boot methods. One of the two is to load an operating system directly, and the other is to chain-load another boot loader which then will load an operating system actually. Generally speaking, the former is more desirable, because you don't need to install or maintain other boot loaders and GRUB is flexible enough to load an operating system from an arbitrary disk/partition. However, the latter is sometimes required, since GRUB doesn't support all the existing operating systems natively.

4.1.1 How to boot an OS directly with GRUB
4.1.2 Load another boot loader to boot unsupported operating systems

4.1.1 How to boot an OS directly with GRUB

Multiboot (see section `Motivation' in The Multiboot Specification) is the native format supported by GRUB. For the sake of convenience, there is also support for Linux, FreeBSD, NetBSD and OpenBSD. If you want to boot other operating systems, you will have to chain-load them (see section 4.1.2 Load another boot loader to boot unsupported operating systems).

Generally, GRUB can boot any Multiboot-compliant OS in the following steps:

1. Set GRUB's root device to the drive where the OS images are stored with the command root (see section 13.3.31 root).

2. Load the kernel image with the command kernel (see section 13.3.20 kernel).

3. If you need modules, load them with the command module (see section 13.3.25 module) or modulenounzip (see section 13.3.26 modulenounzip).

4. Run the command boot (see section 13.3.2 boot).

Linux, FreeBSD, NetBSD and OpenBSD can be booted in a similar manner. You load a kernel image with the command kernel and then run the command boot. If the kernel requires some parameters, just append the parameters to kernel, after the file name of the kernel. Also, please refer to 4.2 Some caveats on OS-specific issues, for information on your OS-specific issues.

4.1.2 Load another boot loader to boot unsupported operating systems

If you want to boot an unsupported operating system (e.g. Windows 95), chain-load a boot loader for the operating system. Normally, the boot loader is embedded in the boot sector of the partition on which the operating system is installed.

1. Set GRUB's root device to the partition by the command rootnoverify (see section 13.3.32 rootnoverify):

grub> rootnoverify (hd0,0)

2. Set the active flag in the partition using the command makeactive(6) (see section 13.3.22 makeactive):

grub> makeactive

3. Load the boot loader with the command chainloader (see section 13.3.4 chainloader):

grub> chainloader +1

`+1' indicates that GRUB should read one sector from the start of the partition. The complete description about this syntax can be found in 11.3 How to specify block lists.

4. Run the command boot (see section 13.3.2 boot).

However, DOS and Windows have some deficiencies, so you might have to use more complicated instructions. See section 4.2.6 DOS/Windows, for more information.

4.2 Some caveats on OS-specific issues

Here, we describe some caveats on several operating systems.

4.2.1 GNU/Hurd
4.2.2 GNU/Linux

4.2.1 GNU/Hurd

Since GNU/Hurd is Multiboot-compliant, it is easy to boot it; there is nothing special about it. But do not forget that you have to specify a root partition to the kernel.

1. Set GRUB's root device to the same drive as GNU/Hurd's. Probably the command find /boot/gnumach or similar can help you (see section 13.3.11 find).

2. Load the kernel and the module, like this:

grub> kernel /boot/gnumach root=hd0s1
grub> module /boot/serverboot

3. Run the command boot (see section 13.3.2 boot).

4.2.2 GNU/Linux

It is relatively easy to boot GNU/Linux from GRUB, because it somewhat resembles to boot a Multiboot-compliant OS.

1. Set GRUB's root device to the same drive as GNU/Linux's. Probably the command find /vmlinuz or similar can help you (see section 13.3.11 find).

2. Load the kernel:

grub> kernel /vmlinuz root=/dev/hda1

If you need to specify some kernel parameters, just append them to the command. For example, to set `vga' to `ext', do this:

grub> kernel /vmlinuz root=/dev/hda1 vga=ext

See the documentation in the Linux source tree for complete information on the available options.

3. If you use an initrd, execute the command initrd (see section 13.3.17 initrd) after kernel:

grub> initrd /initrd

4. Finally, run the command boot (see section 13.3.2 boot).

Caution: If you use an initrd and specify the `mem=' option to the kernel to let it use less than actual memory size, you will also have to specify the same memory size to GRUB. To let GRUB know the size, run the command uppermem before loading the kernel. See section 13.3.37 uppermem, for more information.

configuration

You've probably noticed that you need to type several commands to boot your OS. There's a solution to that - GRUB provides a menu interface (see section 12.2 The simple menu interface) from which you can select an item (using arrow keys) that will do everything to boot an OS.

To enable the menu, you need a configuration file, `menu.lst' under the boot directory. We'll analyze an example file.

The file first contains some general settings, the menu interface related options. You can put these commands (see section 13.1 The list of commands for the menu only) before any of the items (starting with title (see section 13.1.5 title)).

#
# Sample boot menu configuration file
#

As you may have guessed, these lines are comments. Lines starting with a hash character (`#'), and blank lines, are ignored by GRUB.

# By default, boot the first entry.
default 0

The first entry (here, counting starts with number zero, not one!) will be the default choice.

# Boot automatically after 30 secs.
timeout 30

As the comment says, GRUB will boot automatically in 30 seconds, unless interrupted with a keypress.

# Fallback to the second entry.
fallback 1

If, for any reason, the default entry doesn't work, fall back to the second one (this is rarely used, for obvious reasons).

Note that the complete descriptions of these commands, which are menu interface specific, can be found in 13.1 The list of commands for the menu only. Other descriptions can be found in 13. The list of available commands.

Now, on to the actual OS definitions. You will see that each entry begins with a special command, title (see section 13.1.5 title), and the action is described after it. Note that there is no command boot (see section 13.3.2 boot) at the end of each item. That is because GRUB automatically executes boot if it loads other commands successfully.

The argument for the command title is used to display a short title/description of the entry in the menu. Since title displays the argument as is, you can write basically anything there.

# For booting GNU/Hurd
title  GNU/Hurd
root   (hd0,0)
kernel /boot/gnumach.gz root=hd0s1
module /boot/serverboot.gz

This boots GNU/Hurd from the first hard disk.

# For booting GNU/Linux
title  GNU/Linux
kernel (hd1,0)/vmlinuz root=/dev/hdb1

This boots GNU/Linux, but from the second hard disk.

# For booting Mach (getting kernel from floppy)
title  Utah Mach4 multiboot
root   (hd0,2)
pause  Insert the diskette now^G!!
kernel (fd0)/boot/kernel root=hd0s3
module (fd0)/boot/bootstrap

This boots Mach with a kernel on a floppy, but the root filesystem at hd0s3. It also contains a pause line (see section 13.3.27 pause), which will cause GRUB to display a prompt and delay, before actually executing the rest of the commands and booting.

downloading OS images from a network

6. Downloading OS images from a network

Although GRUB is a disk-based boot loader, it does provide network support. To use the network support, you need to enable at least one network driver in the GRUB build process. For more information please see `netboot/README.netboot' in the source distribution.

6.1 How to set up your network

GRUB requires a file server and optionally a server that will assign an IP address to the machine on which GRUB is running. For the former, only TFTP is supported at the moment. The latter is either BOOTP, DHCP or a RARP server(7). It is not necessary to run both the servers on one computer. How to configure these servers is beyond the scope of this document, so please refer to the manuals specific to those protocols/servers.

If you decided to use a server to assign an IP address, set up the server and run bootp (see section 13.2.1 bootp), dhcp (see section 13.2.4 dhcp) or rarp (see section 13.2.11 rarp) for BOOTP, DHCP or RARP, respectively. Each command will show an assigned IP address, a netmask, an IP address for your TFTP server and a gateway. If any of the addresses is wrong or it causes an error, probably the configuration of your servers isn't set up properly.

Otherwise, run ifconfig, like this:

grub> ifconfig --address=192.168.110.23 --server=192.168.110.14

You can also use ifconfig in conjuction with bootp, dhcp or rarp (e.g. to reassign the server address manually). See section 13.2.6 ifconfig, for more details.

Finally, download your OS images from your network. The network can be accessed using the network drive `(nd)'. Everything else is very similar to the normal instructions (see section 4. Booting).

Here is an example:

grub> bootp
Probing... [NE*000]
NE2000 base ...
Address: 192.168.110.23    Netmask: 255.255.255.0
Server: 192.168.110.14     Gateway: 192.168.110.1

grub> root (nd)
grub> kernel /tftproot/gnumach.gz root=sd0s1
grub> module /tftproot/serverboot.gz
grub> boot

6.2 Booting from a network

It is sometimes very useful to boot from a network, especially when you use a machine which has no local disk. In this case, you need to obtain a kind of Net Boot ROM, such as a PXE ROM or a free software package like Etherboot. Such a Boot ROM first boots the machine, sets up the network card installed into the machine, and downloads a second stage boot image from the network. Then, the second image will try to boot an operating system actually from the network.

GRUB provides two second stage images, `nbgrub' and `pxegrub' (see section 10. GRUB image files). These images are the same as the normal Stage 2, except that they set up a network automatically, and try to load a configuration file from the network, if specified. The usage is very simple: If the machine has a PXE ROM, use `pxegrub'. If the machine has an NBI loader such as Etherboot, use `nbgrub'. There is no difference between them except their formats. Since the way to load a second stage image you want to use should be described in the manual on your Net Boot ROM, please refer to the manual, for more information.

However, there is one thing specific to GRUB. Namely, how to specify a configuration file in a BOOTP/DHCP server. For now, GRUB uses the tag `150', to get the name of a configuration file. The following is an example with a BOOTP configuration:

.allhost:hd=/tmp:bf=null:\
:ds=145.71.35.1 145.71.32.1:\
:sm=255.255.254.0:\
:gw=145.71.35.1:\
:sa=145.71.35.5:

foo:ht=1:ha=63655d0334a7:ip=145.71.35.127:\
:bf=/nbgrub:\
:tc=.allhost:\
:T150="(nd)/tftpboot/menu.lst.foo":

Note that you should specify the drive name (nd) in the name of the configuration file. This is because you might change the root drive before downloading the configuration from the TFTP server when the preset menu feature is used (see section 8. Embedding a configuration file into GRUB).

See the manual of your BOOTP/DHCP server for more information. The exact syntax should differ a little from the example.

embedding grub configuration file

Embedding a configuration file into GRUB

GRUB supports a preset menu which is to be always loaded before starting. The preset menu feature is useful, for example, when your computer has no console but a serial cable. In this case, it is critical to set up the serial terminal as soon as possible, since you cannot see any message until the serial terminal begins to work. So it is good to run the commands serial (see section 13.2.12 serial) and terminal (see section 13.2.14 terminal) before anything else at the start-up time.

How the preset menu works is slightly complicated:

1. GRUB checks if the preset menu feature is used, and loads the preset menu, if available. This includes running commands and reading boot entries, like an ordinary configuration file.

2. GRUB checks if the configuration file is available. Note that this check is performed regardless of the existence of the preset menu. The configuration file is loaded even if the preset menu was loaded.

3. If the preset menu includes any boot entries, they are cleared when the configuration file is loaded. It doesn't matter whether the configuration file has any entries or no entry. The boot entries in the preset menu are used only when GRUB fails in loading the configuration file.

To enable the preset menu feature, you must rebuild GRUB specifying a file to the configure script with the option `--enable-preset-menu'. The file has the same semantics as normal configuration files (see section 5. Configuration).

Another point you should take care is that the diskless support (see section 6.2 Booting from a network) diverts the preset menu. Diskless images embed a preset menu to execute the command bootp (see section 13.2.1 bootp) automatically, unless you specify your own preset menu to the configure script. This means that you must put commands to initialize a network in the preset menu yourself, because diskless images don't set it up implicitly, when you use the preset menu explicitly.

Therefore, a typical preset menu used with diskless support would be like this:

# Set up the serial terminal, first of all.
serial --unit=0 --speed=19200
terminal --timeout=0 serial

# Initialize the network.
dhcp

protection from cracking

Protecting your computer from cracking

You may be interested in how to prevent ordinary users from doing whatever they like, if you share your computer with other people. So this chapter describes how to improve the security of GRUB.

One thing which could be a security hole is that the user can do too many things with GRUB, because GRUB allows one to modify its configuration and run arbitrary commands at run-time. For example, the user can even read `/etc/passwd' in the command-line interface by the command cat (see section 13.3.3 cat). So it is necessary to disable all the interactive operations.

Thus, GRUB provides a password feature, so that only administrators can start the interactive operations (i.e. editing menu entries and entering the command-line interface). To use this feature, you need to run the command password in your configuration file (see section 13.2.10 password), like this:

password --md5 PASSWORD

If this is specified, GRUB disallows any interactive control, until you press the key p and enter a correct password. The option `--md5' tells GRUB that `PASSWORD' is in MD5 format. If it is omitted, GRUB assumes the `PASSWORD' is in clear text.

You can encrypt your password with the command md5crypt (see section 13.3.24 md5crypt). For example, run the grub shell (see section 15. Invoking the grub shell), and enter your password:

grub> md5crypt
Password: **********
Encrypted: $1$U$JK7xFegdxWH6VuppCUSIb.

Then, cut and paste the encrypted password to your configuration file.

Also, you can specify an optional argument to password. See this example:

password PASSWORD /boot/grub/menu-admin.lst

In this case, GRUB will load `/boot/grub/menu-admin.lst' as a configuration file when you enter the valid password.

Another thing which may be dangerous is that any user can choose any menu entry. Usually, this wouldn't be problematic, but you might want to permit only administrators to run some of your menu entries, such as an entry for booting an insecure OS like DOS.

GRUB provides the command lock (see section 13.3.21 lock). This command always fails until you enter the valid password, so you can use it, like this:

title Boot DOS
lock
rootnoverify (hd0,1)
makeactive
chainload +1

You should insert lock right after title, because any user can execute commands in an entry until GRUB encounters lock.

You can also use the command password instead of lock. In this case the boot process will ask for the password and stop if it was entered incorrectly. Since the password takes its own PASSWORD argument this is useful if you want different passwords for different entries.

grub image file

GRUB image files

GRUB consists of several images: two essential stages, optional stages called Stage 1.5, one image for bootable CD-ROM, and two network boot images. Here is a short overview of them. See section D. Hacking GRUB, for more details.

`stage1'
This is an essential image used for booting up GRUB. Usually, this is embedded in an MBR or the boot sector of a partition. Because a PC boot sector is 512 bytes, the size of this image is exactly 512 bytes.

All `stage1' must do is to load Stage 2 or Stage 1.5 from a local disk. Because of the size restriction, `stage1' encodes the location of Stage 2 (or Stage 1.5) in a block list format, so it never understand any filesystem structure.

`stage2'
This is the core image of GRUB. It does everything but booting up itself. Usually, this is put in a filesystem, but that is not required.

`e2fs_stage1_5'
`fat_stage1_5'
`ffs_stage1_5'
`jfs_stage1_5'
`minix_stage1_5'
`reiserfs_stage1_5'
`vstafs_stage1_5'
`xfs_stage1_5'

These are called Stage 1.5, because they serve as a bridge between `stage1' and `stage2', that is to say, Stage 1.5 is loaded by Stage 1 and Stage 1.5 loads Stage 2. The difference between `stage1' and `*_stage1_5' is that the former doesn't understand any filesystem while the latter understands one filesystem (e.g. `e2fs_stage1_5' understands ext2fs). So you can move the Stage 2 image to another location safely, even after GRUB has been installed.

While Stage 2 cannot generally be embedded in a fixed area as the size is so large, Stage 1.5 can be installed into the area right after an MBR, or the boot loader area of a ReiserFS or a FFS.

`stage2_eltorito'
This is a boot image for CD-ROMs using the no emulation mode in El Torito specification. This is identical to Stage 2, except that this boots up without Stage 1 and sets up a special drive `(cd)'.

`nbgrub'
This is a network boot image for the Network Image Proposal used by some network boot loaders, such as Etherboot. This is mostly the same as Stage 2, but it also sets up a network and loads a configuration file from the network.

`pxegrub'
This is another network boot image for the Preboot Execution Environment used by several Netboot ROMs. This is identical to `nbgrub', except for the format.

filesystem syntax and semantics

Filesystem syntax and semantics

GRUB uses a special syntax for specifying disk drives which can be accessed by BIOS. Because of BIOS limitations, GRUB cannot distinguish between IDE, ESDI, SCSI, or others. You must know yourself which BIOS device is equivalent to which OS device. Normally, that will be clear if you see the files in a device or use the command find (see section 13.3.11 find).

How to specify devices

The device syntax is like this:

(device[,part-num][,bsd-subpart-letter])

`[]' means the parameter is optional. device should be either `fd' or `hd' followed by a digit, like `fd0'. But you can also set device to a hexadecimal or a decimal number which is a BIOS drive number, so the following are equivalent:

(hd0)
(0x80)
(128)

part-num represents the partition number of device, starting from zero for primary partitions and from four for extended partitions, and bsd-subpart-letter represents the BSD disklabel subpartition, such as `a' or `e'.

A shortcut for specifying BSD subpartitions is (device,bsd-subpart-letter), in this case, GRUB searches for the first PC partition containing a BSD disklabel, then finds the subpartition bsd-subpart-letter. Here is an example:

(hd0,a)

The syntax `(hd0)' represents using the entire disk (or the MBR when installing GRUB), while the syntax `(hd0,0)' represents using the first partition of the disk (or the boot sector of the partition when installing GRUB).

If you enabled the network support, the special drive, `(nd)', is also available. Before using the network drive, you must initialize the network. See section 6. Downloading OS images from a network, for more information.

If you boot GRUB from a CD-ROM, `(cd)' is available. See section 3.4 Making a GRUB bootable CD-ROM, for details.

How to specify files

There are two ways to specify files, by absolute file name and by block list.

An absolute file name resembles a Unix absolute file name, using `/' for the directory separator (not `\' as in DOS). One example is `(hd0,0)/boot/grub/menu.lst'. This means the file `/boot/grub/menu.lst' in the first partition of the first hard disk. If you omit the device name in an absolute file name, GRUB uses GRUB's root device implicitly. So if you set the root device to, say, `(hd1,0)' by the command root (see section 13.3.31 root), then /boot/kernel is the same as (hd1,0)/boot/kernel.

How to specify block lists

A block list is used for specifying a file that doesn't appear in the filesystem, like a chainloader. The syntax is [offset]+length[,[offset]+length].... Here is an example:

0+100,200+1,300+300

This represents that GRUB should read blocks 0 through 99, block 200, and blocks 300 through 599. If you omit an offset, then GRUB assumes the offset is zero.

Like the file name syntax (see section 11.2 How to specify files), if a blocklist does not contain a device name, then GRUB uses GRUB's root device. So (hd0,1)+1 is the same as +1 when the root device is `(hd0,1)'.

grub's user interface

GRUB's user interface

GRUB has both a simple menu interface for choosing preset entries from a configuration file, and a highly flexible command-line for performing any desired combination of boot commands.

GRUB looks for its configuration file as soon as it is loaded. If one is found, then the full menu interface is activated using whatever entries were found in the file. If you choose the command-line menu option, or if the configuration file was not found, then GRUB drops to the command-line interface.

The flexible command-line interface

The command-line interface provides a prompt and after it an editable text area much like a command-line in Unix or DOS. Each command is immediately executed after it is entered(8). The commands (see section 13.3 The list of command-line and menu entry commands) are a subset of those available in the configuration file, used with exactly the same syntax.

Cursor movement and editing of the text on the line can be done via a subset of the functions available in the Bash shell:

C-f
PC right key
Move forward one character.

C-b
PC left key
Move back one character.

C-a
HOME
Move to the start of the line.

C-e
END
Move the the end of the line.

C-d
DEL
Delete the character underneath the cursor.

C-h
BS
Delete the character to the left of the cursor.

C-k
Kill the text from the current cursor position to the end of the line.

C-u
Kill backward from the cursor to the beginning of the line.

C-y
Yank the killed text back into the buffer at the cursor.

C-p
PC up key
Move up through the history list.

C-n
PC down key
Move down through the history list.

When typing commands interactively, if the cursor is within or before the first word in the command-line, pressing the TAB key (or C-i) will display a listing of the available commands, and if the cursor is after the first word, the TAB will provide a completion listing of disks, partitions, and file names depending on the context. Note that to obtain a list of drives, one must open a parenthesis, as root (.

Note that you cannot use the completion functionality in the TFTP filesystem. This is because TFTP doesn't support file name listing for the security.

The simple menu interface

The menu interface is quite easy to use. Its commands are both reasonably intuitive and described on screen.

Basically, the menu interface provides a list of boot entries to the user to choose from. Use the arrow keys to select the entry of choice, then press RET to run it. An optional timeout is available to boot the default entry (the first one if not set), which is aborted by pressing any key.

Commands are available to enter a bare command-line by pressing c (which operates exactly like the non-config-file version of GRUB, but allows one to return to the menu if desired by pressing ESC) or to edit any of the boot entries by pressing e.

If you protect the menu interface with a password (see section 9. Protecting your computer from cracking), all you can do is choose an entry by pressing RET, or press p to enter the password.

Editing a menu entry

The menu entry editor looks much like the main menu interface, but the lines in the menu are individual commands in the selected entry instead of entry names.

If an ESC is pressed in the editor, it aborts all the changes made to the configuration entry and returns to the main menu interface.

When a particular line is selected, the editor places the user in a special version of the GRUB command-line to edit that line. When the user hits RET, GRUB replaces the line in question in the boot entry with the changes (unless it was aborted via ESC, in which case the changes are thrown away).

If you want to add a new line to the menu entry, press o if adding a line after the current line or press O if before the current line.

To delete a line, hit the key d. Although GRUB unfortunately does not support undo, you can do almost the same thing by just returning to the main menu.

The hidden menu interface

When your terminal is dumb or you request GRUB to hide the menu interface explicitly with the command hiddenmenu (see section 13.1.3 hiddenmenu), GRUB doesn't show the menu interface (see section 12.2 The simple menu interface) and automatically boots the default entry, unless interrupted by pressing ESC.

When you interrupt the timeout and your terminal is dumb, GRUB falls back to the command-line interface (see section 12.1 The flexible command-line interface).

command-line & menu entry commands

These commands are usable in the command-line and in menu entries. If you forget a command, you can run the command help (see section 15 help).

1 blocklist

Command: blocklist file
Print the block list notation of the file file. See section 11.3 How to specify block lists.

2 boot

Command: boot
Boot the OS or chain-loader which has been loaded. Only necessary if running the fully interactive command-line (it is implicit at the end of a menu entry).

3 cat

Command: cat file
Display the contents of the file file. This command may be useful to remind you of your OS's root partition:

grub> cat /etc/fstab

4 chainloader

Command: chainloader [`--force'] file
Load file as a chain-loader. Like any other file loaded by the filesystem code, it can use the blocklist notation to grab the first sector of the current partition with `+1'. If you specify the option `--force', then load file forcibly, whether it has a correct signature or not. This is required when you want to load a defective boot loader, such as SCO UnixWare 7.1 (see section 4.2.7 SCO UnixWare).

5 cmp

Command: cmp file1 file2
Compare the file file1 with the file file2. If they differ in size, print the sizes like this:

Differ in size: 0x1234 [foo], 0x4321 [bar]

If the sizes are equal but the bytes at an offset differ, then print the bytes like this:

Differ at the offset 777: 0xbe [foo], 0xef [bar]

If they are completely identical, nothing will be printed.

6 configfile

Command: configfile file
Load file as a configuration file.

7 debug

Command: debug
Toggle debug mode (by default it is off). When debug mode is on, some extra messages are printed to show disk activity. This global debug flag is mainly useful for GRUB developers when testing new code.

8 displayapm

Command: displayapm
Display APM BIOS information.

9 displaymem

Command: displaymem
Display what GRUB thinks the system address space map of the machine is, including all regions of physical RAM installed. GRUB's upper/lower memory display uses the standard BIOS interface for the available memory in the first megabyte, or lower memory, and a synthesized number from various BIOS interfaces of the memory starting at 1MB and going up to the first chipset hole for upper memory (the standard PC upper memory interface is limited to reporting a maximum of 64MB).

10 embed

Command: embed stage1_5 device
Embed the Stage 1.5 stage1_5 in the sectors after the MBR if device is a drive, or in the boot loader area if device is a FFS partition or a ReiserFS partition.(9) Print the number of sectors which stage1_5 occupies, if successful.

Usually, you don't need to run this command directly. See section 34 setup.

11 find

Command: find filename
Search for the file name filename in all mountable partitions and print the list of the devices which contain the file. The file name filename should be an absolute file name like /boot/grub/stage1.

12 fstest

Command: fstest
Toggle filesystem test mode. Filesystem test mode, when turned on, prints out data corresponding to all the device reads and what values are being sent to the low-level routines. The format is `<partition-offset-sector, byte-offset, byte-length>' for high-level reads inside a partition, and `[disk-offset-sector]' for low-level sector requests from the disk. Filesystem test mode is turned off by any use of the install (see section 18 install) or testload (see section 35 testload) commands.

13 geometry

Command: geometry drive [cylinder head sector [total_sector]]
Print the information for the drive drive. In the grub shell, you can set the geometry of the drive arbitrarily. The number of cylinders, the number of heads, the number of sectors and the number of total sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR, respectively. If you omit TOTAL_SECTOR, then it will be calculated based on the C/H/S values automatically.

14 halt

Command: halt `--no-apm'
The command halts the computer. If the `--no-apm' option is specified, no APM BIOS call is performed. Otherwise, the computer is shut down using APM.

15 help

Command: help `--all' [pattern ...]
Display helpful information about builtin commands. If you do not specify pattern, this command shows short descriptions of most of available commands. If you specify the option `--all' to this command, short descriptions of rarely used commands (such as 35 testload) are displayed as well.

If you specify any patterns, it displays longer information about each of the commands which match those patterns.

16 impsprobe

Command: impsprobe
Probe the Intel Multiprocessor Specification 1.1 or 1.4 configuration table and boot the various CPUs which are found into a tight loop. This command can be used only in the Stage 2, but not in the grub shell.

17 initrd

Command: initrd file ...
Load an initial ramdisk for a Linux format boot image and set the appropriate parameters in the Linux setup area in memory. See also 4.2.2 GNU/Linux.

18 install

Command: install [`--force-lba'] [`--stage2=os_stage2_file'] stage1_file [`d'] dest_dev stage2_file [addr] [`p'] [config_file] [real_config_file]
This command is fairly complex, and you should not use this command unless you are familiar with GRUB. Use setup (see section 34 setup) instead.

In short, it will perform a full install presuming the Stage 2 or Stage 1.5(10) is in its final install location.

In slightly more detail, it will load stage1_file, validate that it is a GRUB Stage 1 of the right version number, install in it a blocklist for loading stage2_file as a Stage 2. If the option `d' is present, the Stage 1 will always look for the actual disk stage2_file was installed on, rather than using the booting drive. The Stage 2 will be loaded at address addr, which must be `0x8000' for a true Stage 2, and `0x2000' for a Stage 1.5. If addr is not present, GRUB will determine the address automatically. It then writes the completed Stage 1 to the first block of the device dest_dev. If the options `p' or config_file are present, then it reads the first block of stage2, modifies it with the values of the partition stage2_file was found on (for `p') or places the string config_file into the area telling the stage2 where to look for a configuration file at boot time. Likewise, if real_config_file is present and stage2_file is a Stage 1.5, then the Stage 2 config_file is patched with the configuration file name real_config_file. This command preserves the DOS BPB (and for hard disks, the partition table) of the sector the Stage 1 is to be installed into.

Caution: Several buggy BIOSes don't pass a booting drive properly when booting from a hard disk drive. Therefore, you will unfortunately have to specify the option `d', whether your Stage2 resides at the booting drive or not, if you have such a BIOS. We know these are defective in this way:

Fujitsu LifeBook 400 BIOS version 31J0103A

HP Vectra XU 6/200 BIOS version GG.06.11

Caution2: A number of BIOSes don't return a correct LBA support bitmap even if they do have the support. So GRUB provides a solution to ignore the wrong bitmap, that is, the option `--force-lba'. Don't use this option if you know that your BIOS doesn't have LBA support.

Caution3: You must specify the option `--stage2' in the grub shell, if you cannot unmount the filesystem where your stage2 file resides. The argument should be the file name in your operating system.

19 ioprobe

Command: ioprobe drive
Probe I/O ports used for the drive drive. This command will list the I/O ports on the screen. For technical information, See section D. Hacking GRUB.

20 kernel

Command: kernel [`--type=type'] [`--no-mem-option'] file ...
Attempt to load the primary boot image (Multiboot a.out or ELF, Linux zImage or bzImage, FreeBSD a.out, NetBSD a.out, etc.) from file. The rest of the line is passed verbatim as the kernel command-line. Any modules must be reloaded after using this command.

This command also accepts the option `--type' so that you can specify the kernel type of file explicitly. The argument type must be one of these: `netbsd', `freebsd', `openbsd', `linux', `biglinux', and `multiboot'. However, you need to specify it only if you want to load a NetBSD ELF kernel, because GRUB can automatically determine a kernel type in the other cases, quite safely.

The option `--no-mem-option' is effective only for Linux. If the option is specified, GRUB doesn't pass the option `mem=' to the kernel. This option is implied for Linux kernels 2.4.18 and newer.

21 lock

Command: lock
Prevent normal users from executing arbitrary menu entries. You must use the command password if you really want this command to be useful (see section 13.2.10 password).

This command is used in a menu, as shown in this example:

title This entry is too dangerous to be executed by normal users
lock
root (hd0,a)
kernel /no-security-os

See also 9. Protecting your computer from cracking.

22 makeactive

Command: makeactive
Set the active partition on the root disk to GRUB's root device. This command is limited to primary PC partitions on a hard disk.

23 map

Command: map to_drive from_drive
Map the drive from_drive to the drive to_drive. This is necessary when you chain-load some operating systems, such as DOS, if such an OS resides at a non-first drive. Here is an example:

grub> map (hd0) (hd1)
grub> map (hd1) (hd0)

The example exchanges the order between the first hard disk and the second hard disk. See also 4.2.6 DOS/Windows.

24 md5crypt

Command: md5crypt
Prompt to enter a password, and encrypt it in MD5 format. The encrypted password can be used with the command password (see section 13.2.10 password). See also 9. Protecting your computer from cracking.

25 module

Command: module file ...
Load a boot module file for a Multiboot format boot image (no interpretation of the file contents are made, so the user of this command must know what the kernel in question expects). The rest of the line is passed as the module command-line, like the kernel command. You must load a Multiboot kernel image before loading any module. See also 26 modulenounzip.

26 modulenounzip

Command: modulenounzip file ...
The same as module (see section 25 module), except that automatic decompression is disabled.

27 pause

Command: pause message ...
Print the message, then wait until a key is pressed. Note that placing ^G (ASCII code 7) in the message will cause the speaker to emit the standard beep sound, which is useful when prompting the user to change floppies.

28 quit

Command: quit
Exit from the grub shell grub (see section 15. Invoking the grub shell). This command can be used only in the grub shell.

29 reboot

Command: reboot
Reboot the computer.

30 read

Command: read addr
Read a 32-bit value from memory at address addr and display it in hex format.

31 root

Command: root device [hdbias]
Set the current root device to the device device, then attempt to mount it to get the partition size (for passing the partition descriptor in ES:ESI, used by some chain-loaded boot loaders), the BSD drive-type (for booting BSD kernels using their native boot format), and correctly determine the PC partition where a BSD sub-partition is located. The optional hdbias parameter is a number to tell a BSD kernel how many BIOS drive numbers are on controllers before the current one. For example, if there is an IDE disk and a SCSI disk, and your FreeBSD root partition is on the SCSI disk, then use a `1' for hdbias.

See also 32 rootnoverify.

32 rootnoverify

Command: rootnoverify device [hdbias]
Similar to root (see section 31 root), but don't attempt to mount the partition. This is useful for when an OS is outside of the area of the disk that GRUB can read, but setting the correct root device is still desired. Note that the items mentioned in root above which derived from attempting the mount will not work correctly.

33 savedefault

Command: savedefault
Save the current menu entry as a default entry. Here is an example:

default saved
timeout 10

title GNU/Linux
root (hd0,0)
kernel /boot/vmlinuz root=/dev/sda1 vga=ext
initrd /boot/initrd
savedefault

title FreeBSD
root (hd0,a)
kernel /boot/loader
savedefault

With this configuration, GRUB will choose the entry booted previously as the default entry. See also 13.1.1 default.

34 setup

Command: setup [`--force-lba'] [`--stage2=os_stage2_file'] [`--prefix=dir'] install_device [image_device]
Set up the installation of GRUB automatically. This command uses the more flexible command install (see section 18 install) in the backend and installs GRUB into the device install_device. If image_device is specified, then find the GRUB images (see section 10. GRUB image files) in the device image_device, otherwise use the current root device, which can be set by the command root. If install_device is a hard disk, then embed a Stage 1.5 in the disk if possible.

The option `--prefix' specifies the directory under which GRUB images are put. If it is not specified, GRUB automatically searches them in `/boot/grub' and `/grub'.

The options `--force-lba' and `--stage2' are just passed to install if specified. See section 18 install, for more information.

35 testload

Command: testload file
Read the entire contents of file in several different ways and compare them, to test the filesystem code. The output is somewhat cryptic, but if no errors are reported and the final `i=X, filepos=Y' reading has X and Y equal, then it is definitely consistent, and very likely works correctly subject to a consistent offset error. If this test succeeds, then a good next step is to try loading a kernel.

36 testvbe

Command: testvbe mode
Test the VESA BIOS EXTENSION mode mode. This command will switch your video card to the graphics mode, and show an endless animation. Hit any key to return. See also 38 vbeprobe.

37 uppermem

Command: uppermem kbytes
Force GRUB to assume that only kbytes kilobytes of upper memory are installed. Any system address range maps are discarded.

Caution: This should be used with great caution, and should only be necessary on some old machines. GRUB's BIOS probe can pick up all RAM on all new machines the author has ever heard of. It can also be used for debugging purposes to lie to an OS.

38 vbeprobe

Command: vbeprobe [mode]
Probe VESA BIOS EXTENSION information. If the mode mode is specified, show only the information about mode. Otherwise, this command lists up available VBE modes on the screen. See also 36 testvbe.

kernel

kernel pages go here.....

kernel rebuild guide

Why Rebuild?

Why rebuild the kernel? The main reason was once to optimize the kernel to your environment (hardware and usage patterns). With modern hardware there is rarely a need to recompile unless there is a particular feature of a new kernel that you must have. The performance gains are probably not noticeable unless specific benchmarks are being run.

This said, the newest Linux kernel (2.6.5 as of this writing) has noticeable improvements for the typical desktop user as a result of the improved scheduling system in the new kernel. Even for older kernels, rebuilding is often necessary for low memory situations, esoteric hardware, and in cases where every ounce of performance must be extracted.

This guide covers the steps necessary to build both the 2.4.x and 2.6.x series of kernels. Because the process is quite different from one version to the next, the two kernel versions are described in separate chapters.


What is the kernel?

The Linux kernel is often likened to the conductor in an orchestra. Among other things, it makes sure that all other processes in the system work together coherently. Though it is only a small part of the operating system, the kernel has the most important job of keeping everything else synchronized.


Preparation

Hardware Requirements

Hardware requirements can differ greatly between kernel versions, and indeed, within versions depending upon the configuration. Though the Linux 2.4.x kernel can boot with as little as 8M of RAM, a more realistic number is about 64M. As of this writing, the published minimum hardware required for the typical distribution is about 128M RAM, 2G of hard drive space, and 200MhZ Pentium or equivalent CPU. To actually build the kernel, however, requires a little extra hardware. The kernel sources themselves will occupy anywhere from 40M to 80M of filesystem space. To build them requires a minimum of 400M of drive space for all the interim files. The actual kernel and included modules will require anywhere from 4M for an almost useless, bare minimum kernel to about 40M fully loaded. [1] Luckily, the kernel does not need to be built on the same machine on which it will be deployed. This means that you can compile and package your kernel on a more robust machine and then install on the minimal system.


Software Requirements

The minimum software versions for a kernel build are found in the ./Documentation/Changes file of the installed sources. They are as follows: 2.4.x series

		o  Gnu C                  2.91.66     # gcc --version
o Gnu make 3.77 # make --version
o binutils 2.9.1.0.25 # ld -v
o util-linux 2.10o # fdformat --version
o modutils 2.4.2 # insmod -V
o e2fsprogs 1.19 # tune2fs
o reiserfsprogs 3.x.0b # reiserfsck 2>&1|grep reiserfsprogs
o pcmcia-cs 3.1.21 # cardmgr -V
o PPP 2.4.0 # pppd --version
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version

2.6.x series

		o  Gnu C                  2.95.3       # gcc --version
o Gnu make 3.78 # make --version
o binutils 2.12 # ld -v
o util-linux 2.10o # fdformat --version
o module-init-tools 0.9.10 # depmod -V
o e2fsprogs 1.29 # tune2fs
o jfsutils 1.1.3 # fsck.jfs -V
o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs
o xfsprogs 2.1.0 # xfs_db -V
o pcmcia-cs 3.1.21 # cardmgr -V
o quota-tools 3.09 # quota -V
o PPP 2.4.0 # pppd --version
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
o nfs-utils 1.0.5 # showmount --version
o procps 3.1.13 # ps --version
o oprofile 0.5.3 # oprofiled --version

A common sticking point on distributions transitioning between 2.4.x and 2.6.x kernels is the module-init-tools package which must be updated to work with the 2.6.x kernel. Also, be aware that the underlying version of glibc, the GNU libc package, is implied. If you are upgrading from particularly old distributions then you will likely need to upgrade glibc itself. [2]


Determine Current Hardware

Once you have determined that your hardware and software meet the minimum requirements for the kernel build, we will need to collect more detailed information about the system. This is needed during the configuration process when we decide which hardware will be supported under our new kernel. Among the information we will gather include: Processor, Drive type and Controller (SCSI, IDE), Ethernet devices, Graphics and Sound Cards, USB HUB.

We start by running the /sbin/lspci utility to print information about our hardware:

			$ /sbin/lspci

		00:00.0 Host bridge: Silicon Integrated Systems [SiS] 735 Host (rev 01)
00:01.0 PCI bridge: Silicon Integrated Systems [SiS] 5591/5592 AGP
00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
00:02.2 USB Controller: Silicon Integrated Systems [SiS] 7001 (rev 07)
00:02.3 USB Controller: Silicon Integrated Systems [SiS] 7001 (rev 07)
00:02.5 IDE interface: Silicon Integrated Systems [SiS] 5513 [IDE] (rev d0)
00:02.7 Multimedia audio controller: SiS7012 PCI Audio Accelerator (rev a0)
00:03.0 Ethernet controller: [SiS] SiS900 10/100 Ethernet (rev 90)
01:00.0 VGA compatible controller: ATI Technologies Inc Rage 128 RF/SG AGP

Next, we must determine our processor type if not known. Some Linux systems contain a /proc filesystem that allows a user to view raw information about the system. If /proc exists you can issue the following command to get CPU information:

			$ cat /proc/cpuinfo

		processor       : 0
vendor_id : AuthenticAMD
cpu family : 6
model : 6
model name : AMD Athlon(tm) XP 1800+
stepping : 2
cpu MHz : 1526.870
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge
bogomips : 3047.42


Acquiring the Sources

There are many ways to acquire the Linux kernel sources. If you are using a packaged distribution then most likely the distributor will bundle a kernel source package. These are installable via the package installation method, whether RPM, apt, YAST, portage, etc.. If you decide to go this route, please consult your distribution's documentation for specifics.

The other option is to use the "pristine" sources, either the "official" sources from Linus Torvalds himself, or one of the regularly maintained trees from people such as Alan Cox, Robert Love, Andrew Morton, et al.. These sources are often on the bleeding-edge of kernel development, full of new features and untested code.

Untested code? This is a feature of the distributed development model of Linux and Open Source (??) in general. The traditional model of a software release is somewhat antithetical to this model, as new code must be released to allow all developers to test and improve the code. However, because Linux is used in production environments throughout world it is necessary to separate the unstable development tree from the tested, stable tree. This is done through the version number of the kernel. There are three main numbers associated with the kernel -- the Major, Minor, and PatchLevel fields. The Major number rarely changes, and then only when/if the entire architecture is revamped. The Minor number changes more frequently, perhaps once every couple years. Kernels with an odd Minor number are considered unstable, testing branches. Kernels with an even Minor number are generally rock solid. The PatchLevel is updated frequently, sometimes more than once a week in extreme cases.

To recap, you can build either from your distribution's modified kernel sources or from the stable or unstable branch of the offical sources. If you are making minor modifications to the configuration, it is perhaps safest to install your distributor's version. These kernels usually include stability and feature patches that may be missing from the stock kernels. For example, some distributors will include low-latency or security patches and do the more difficult work of integrating these into their system. The downside is that the distributors tend to lag behind the bleeding-edge kernels. If you would like to test features that are available in the newest tree then you will likely need to build from the "pristine" source from Linus or the tree maintainer of your choice.. FIXME: NO LONGER really true -- 2.6 based distributions are out there / will be (e.g., SuSE 9.1) by the end of April 2004.


Download the Source

Though the latest sources are always available from http://kernel.org, to be kind to the Internet, always use one of the mirrors listed at http://kernel.org/mirrors. In general, geographically close mirrors will tend to be fastest. You can either browse the sites with an Internet browser or with a dedicated FTP client.

You will see several links to /pub/linux on the mirror site. Select the kernel directory, then the kernel version that you would like to install. As of this writing, 2.4.22 is the latest stable version and 2.6.0 is in pre-release state. Once you select a kernel version you will see several files.

		ChangeLog-2.6.0-test9          25-Oct-2003 14:51    41k  
LATEST-IS-2.6.0-test9 25-Oct-2003 14:51 0k
linux-2.6.0-test9.tar.bz2.sign 25-Oct-2003 15:14 1k
linux-2.6.0-test9.tar.gz 25-Oct-2003 15:14 39.7M
linux-2.6.0-test9.tar.gz.sign 25-Oct-2003 15:14 1k
linux-2.6.0-test9.tar.sign 25-Oct-2003 15:14 1k
patch-2.6.0-test9.bz2.sign 25-Oct-2003 15:14 1k
patch-2.6.0-test9.gz 25-Oct-2003 15:14 123k
patch-2.6.0-test9.gz.sign 25-Oct-2003 15:14 1k
patch-2.6.0-test9.sign 25-Oct-2003 15:14 1k

The Changelog files detail the differences between versions. The linux- files are the compressed sources for the entire Linux kernel. Most sites will contain both gzip and bzip packages. The bzip packages tend to be about 20% smaller than the GZIP versions, so they are usually the best option since all modern Linux distributions contain BZIP utilities.

The patch files are a list of differences between versions of the kernel. If you have previously downloaded an earlier source package, you will only need to download the much smaller patch file to bring those up to date. We will discuss patch application in the next section.

There are also some .sign files that contain GPG checksum information which are useful for verifying that the sources you downloaded have not been corrupted or maliciously modified. For more information on verifying the GPG signature, see http://www.kernel.org/signature.html .

The http://kernel.org website is not the only place to retrieve patches. Many other vendors and individuals have developed patches to improve aspects of the kernel's performance, support new hardware, or introduce features that are too esoteric or experimental to make it to the stock kernel. For example, kernel hacker Robert Love had developed the pre-emptible kernel modifications that made dramatic improvements to the responsiveness of a Linux system. These patches were not part of the standard 2.4.x kernel but were of such usefulness that they were officially adopted into the 2.6.0 series. For the most part these third-party patches are stable but do use your judgment when downloading and applying them.


Extract and Patch

Once you have retrieved the kernel sources and patches, you will need to extract them and apply the patches. The pristine 2.4.x and 2.6.x sources can be built as a regular, unprivileged user and this is recommended. [3]

We will begin by creating a directory to hold all the source tarballs and patches, then proceed to extract the sources. For these examples we will assume that you have previously downloaded an earlier release of the kernel and will now need to patch to bring it up to the current version.

			$ mkdir src
$ cd src

If your Linux sources are in BZIP compressed format (that is, end with a .bz2 extenstion, then use the following command:

			$ tar xfvj /path/to/linux-2.6.0-test7.tar.bz2

Otherwise, use the options for GZIP compressed data:

			$ tar xfvz /path/to/linux-2.6.0-test7.tar.gz

You should see a list of filenames scroll by as they are being extracted. Verify that the new kernel source directory is created:

			$ ls -l

		total 4
drwxr-xr-x 18 kwan users 4096 Oct 8 15:24 linux-2.6.0-test7
-rw-r--r-- 1 kwan users 276260 Nov 15 02:05 patch-2.6.0-test8.gz
-rw-r--r-- 1 kwan users 126184 Nov 15 02:07 patch-2.6.0-test9.gz

Next we must apply the patches in order. Patch files are created by the diff program, and can selectively modify one or more files by adding, deleting, or modifying lines in the source code. Because they contain only the differences between files it is usually a lot faster (and better for the Internet in general) if you patch to the current release. (TBF unclear). Appendix TBF shows a typical patch file. Like the kernel sources, the patch files are also compressed.

			$ gunzip patch-2.6.0-test8.gz
$ gunzip patch-2.6.0-test9.gz
$ ls -l

		-rw-r--r--    1 kwan  users  1072806 Nov 15 02:05 patch-2.6.0-test8
-rw-r--r-- 1 kwan users 486902 Nov 15 02:07 patch-2.6.0-test9

Once the patches are uncompressed we can apply them to the kernel sources. Remember that it is important to apply them in order.

			$ cd linux-2.6.0-test7
$ patch -p1 <../patch-2.6.0.test8
$ patch -p1 <../patch-2.6.0.test9

If it is successful you will see messages similar to the following scroll by:

		patching file Documentation/filesystems/jfs.txt
patching file Documentation/filesystems/xfs.txt
patching file Documentation/ia64/fsys.txt
patching file Documentation/ide.txt
patching file Documentation/x86_64/boot-options.txt
patching file Makefile

If unsuccessful you will get a warning and be prompted for a file to patch. If this occurs, press Ctrl-C to break out of the patch utility and verify that you are using the correct patch and applying them in the correct order.

Once all the patches are applied you might consider backing up the directory.

			$ cd ..
$ mv linux-2.6.0-test7 linux-2.6.0-test9
$ tar cfvj linux-2.6.0-test9.tar.bz2 linux-2.6.0-test9


Configuration

The Configuration Process

The configuration process is the most strenous portion of the kernel rebuild process. In this step you are deciding which features will be included in the final kernel and it can require lots of hardware knowledge. In truth, it is not too onerous. The current kernels have graphical configuration programs and though not perfect, provide help screens for most of the configuration options.

Many changes were made to the configuration subsystem in the 2.6.x kernel series. It is easier to add modules and much more robust than before. It has also changed dramatically in appearance especially when using the X-based configuration tool, xconfig. For this reason the configuration steps for the different branches have been split into two sections in this chapter.

As mentioned, both configuration tools provide context sensitive help screens for the different options. Because this help is readily available to the user (and more importantly, because there are several hundred options) this guide will only cover a fraction of the choices.


Compile Modules or Static

One of the first choices you will make is whether or not to build device support directly into the kernel or as a module. In the early days of Linux, when module support was in its infancy, it was possible that static (i.e., compiled in) drivers were faster. With any modern CPU, the time to load and unload the modules and the memory required for the module loader subsystem is negligible even to benchmarking utilities. Some devices, notably the disk controller, can be built directly into the kernel in order to simplify the boot process. [4]

You may also choose to disable some options entirely. Though you will not have any performance increases, there are advantages to disabling features that are not required. For one, the compile times will be drastically reduced depending on which subsystem is disabled. For another, the final kernel and installed modules will require less space. On modern hard drives of 40G, 60G, and even 250G, an extra 20M or so is negligible but is significant on embedded or older systems. The disadvantage is that you will not have support for those features until you recompile the kernel. One other thing to keep in mind, as noted in KERNELTRAP.ORG (http://www.kerneltrap.org/node/view/799):

Having unnecessary drivers will make the kernel bigger, and can under some 
circumstances lead to problems: probing for a nonexistent controller card may 
confuse your other controllers.

--kerneltrap.org


Assign Unique Name

We have so far extracted and patched the Linux sources. During our preparation we also determined what hardware is installed in the system so that we will know which modules will need compilation. Before we proceed to actually configuring the kernel there are a couple minor but important details to complete.

Inside the Linux source directory is the default Makefile. This file is used by the make utility to compile the Linux sources. The first few lines of the Makefile contains some versioning information:

		VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 22
EXTRAVERSION = -1

Note that there is an additional EXTRAVERSION field. To prevent overwriting any existing kernel modules on the system we will change this EXTRAVERSION to something unique. When the final installation steps are run, kernel module files will then get written to /lib/modules/$VERSION.$PATCHLEVEL.$SUBLEVEL-$EXTRAVERSION.


Backup .config

Finally, before we begin, please note that the configuration choices are kept in the ../linux/.config file. If you have not already run any configurations, this file will not exist. If you have, and would like to save your configuration, copy the .config to another file:

			$ cd linux
$ cp .config config.save

If you are using the sources from a vendor, then the default configuration files are usually included in the configs or in the ./arch/i386/defconfig (for i386 machines) file. You can use these configurations as a starting point for your customizations. The .config will be overwritten in the next step, so do make a backup before proceeding!

We begin the configuration by wiping out all previous configurations and resetting the source directory to a pristine state. The main reason for doing this is that some files do not automatically get rebuilt, which can lead to failed builds, or at worst, a buggy kernel.

			$ make mrproper

In the 2.4.x series, a few dozen lines of rm -f commands will appear as all generated files get removed. The 2.6.x process is less noisy and returns only a few CLEAN messages. Please note that it is generally safe to omit the make mrproper step during subsequent rebuilds.

As of this writing (December 15, 2003), the 2.4.x kernel is in wide deployment. The 2.6.0 has just been released to the world. FIXME -- the previous sentence needs to be updated Though the configuration and build procedures are quite similar, there are enough differences to warrant separate sections for each kernel. If you are building a 2.6.x series kernel, skip to the Section called Configuring the 2.6.x kernels. Otherwise, proceed to the next section, the Section called Configuring the 2.4.x kernels.


Configuring the 2.4.x kernels

Our next step is to run the configuration utility. In the 2.4.x kernels there are four main frontends: config, oldconfig, menuconfig, xconfig. We choose one configuration method and run it, for example:

			$ make config

config is the least user-friendly option as it merely presents a series of questions that must be answered sequentially. Alas, if an error is made you must begin the process from the top. Pressing Enter will accept the default entry, which is in upper case.

oldconfig will read the defaults from an existing .config and rewrite necessary links and files. Use this option if you've made minor changes to source files or need to script the rebuild process. Note that oldconfig will only work within the same major version of the kernel. You cannot, for example, use a 2.4.x .config with the 2.6.x kernel.

menuconfig is an ncurses-based frontend. Your system must have the ncurses-devel libraries installed in order to use this utility. As the help text at the top of the screen indicates, use the arrow keys to navigate the menu. Press Enter to select sub-menus. Press the highlighted letter on each option to jump directly to that option. To build an option directly into the kernel, press Y. To disable an option entirely, press N. To build an option as a loadable module, press M. You can also access content-specific help screens by pressing ? on each page or selecting HELP from the lower menu. Figure 1 shows an example screen. [5]

Figure 1. make menuconfig

xconfig, as the name suggests, is an X Window based frontend. It requires the Tcl/Tk and X libraries to work, and of course, an X server. Figure 2 shows an example screen.

Figure 2. make xconfig

For the purposes of this next section we will assume that make xconfig is used. The options are identical otherwise. As mentioned, there are literally hundreds of configuration options and this precludes us from listing every one of them. If you are unsure of an option use the online help or consult the kernel documentation found in the ../linux/Documentation directory. We begin by typing:

			$ make xconfig

The main configuration menu will appear. Selecting an item will bring up another window with further options. These in turn can spawn other sub-menus.

Code Maturity Level Options

This option allows configuration of alpha-quality software. It is best to disable this option if the kernel is intended for a stable production system. If you require an experimental feature in the kernel, such as a driver for new hardware, then enable this option but be aware that it "may not meet the normal level of reliability" as tested code.

Loadable Module Support

You will almost certainly want to enable module support. If you will need third-party kernel modules you will also need to enable Set Version Information on All Module Symbols.

Processor Type and Features

This is perhaps the most important option to choose. In the Preparation section we determined our processor type by examining /proc/cpuinfo and we use that information here to select the appropriate processor. Included in this submenu are features such as Low Latency Scheduling which can improve desktop responsiveness, Symmetric Multi-processing Support for machines with multiple CPUs, and High Memory Support for machines with more than 1G of RAM. Laptop users can also benefit from the CPU Frequency Scaling feature.

General Setup

Choices for PCI, ISA, PCMCIA and other architectural support such as Advanced Power Management are found here.

Memory Technology Devices

MTD devices include Compact Flash devices. Some digital cameras will require this support.

Block Devices

The Block Device section contains options for floppy and hard drives, including parallel port devices, tape drives and RAID controllers. Important options include loopback device support, which allows mounting on disk images, and initrd support, which is needed to preload drivers necessary to boot the system.

Multi-Device support (RAID and LVM)

Important for servers, these options include RAID support for combining multiple disks. Note that this option is not needed for certain hardware RAID that function below the operating system level. LVM is a useful subsystem that allows, among other things, dynamic resizing of filesystems.

ATA/IDE/MFM/RLL support.

This section includes options for IDE/ATAPI chipsets, including performance tweaks such as DMA. Most systems will need this support.

Cryptography Support (CryptoAPI)

Useful options include Loopback Crypto Support, which allows encrypted filesystem images to be mounted. Even with full access to the PC, loopback encryption can help safeguard data.

Networking Options

Many choices are available for networking. TCP/IP, IP tunneling, packet filtering, IPv4 and IPv6, routing support and network QoS are among the most useful. If your kernel is intended for a dedicated firewall or router device, then the options here can significantly improve performance. Read the online and kernel documentation.

SCSI Support

SCSI support is needed for not only true SCSI devices, but also for IDE CDR/W drives in SCSI emulation mode. If your root filesystem is mounted on a SCSI disk, then you must build support directly into the kernel and not as a module.

Character Devices

Dozens of options are available here, including support for many serial and parallel devices, hardware sensors (for system monitors), mice, joysticks and DRM. Many of the options can be safely disabled without problem.

File Systems

It is a good idea to build support for your root filesystem directly into the kernel. Though the initrd utilities can get around the chicken-and-egg boot problem, it is generally safer and easier to just build the fs modules directly. Many options can also be safely disabled if you have no use for the feature.

Once all the configuration changes have been made, you can go ahead and save settings. By defaulti, the configuration is placed in the .config file in the topmost directory. Because this file is deleted by make mrproper and is also hidden, it is a good idea to use the Save to Alternate File before exiting. It will prompt for another save location. Enter something outside of the source tree and with a useful name such as kernel-2.4.22-lowlatency.config. Once this is done, exit the configuration menu. You will be prompted to save the configuration again. Select Yes and continue.

The configuration for the 2.4.x kernel is now complete. You may now skip to the chapter called Build.


Configuring the 2.6.x kernels

Our next step is to run the configuration utility. On the 2.6.x kernels there are four main frontend programs: config, menuconfig, and xconfig.

config is the least user-friendly option as it merely presents a series of questions that must be answered sequentially. Alas, if an error is made you must begin the process from the top. Pressing Enter will accept the default entry which is in upper case.

oldconfig will read the defaults from an existing .config and rewrite necessary links and files. Use this option if you've made minor changes to source files or need to script the rebuild process.

menuconfig is an ncurses based frontend. Your system must have the ncurses-devel libraries installed in order to use this utility. As the help text at the top of the screen indicates, use the arrow keys to navigate the menu. Press Enter to select sub-menus. Press the highlighted letter on each option to jump directly to that option. To build an option directly into the kernel, press Y. To disable an option entirely, press N. To build an option as a loadable module, press M. You can also access content-specific help screens by pressing ? on each page or selecting HELP from the lower menu. Figure 1 in the Section called Configuring the 2.4.x kernels shows an example screen from the 2.4.x kernel series.

xconfig is a graphical frontend using qconf by Roman Zippel. It requires the qt and X libraries to build and use. The interface is intuitive and customizable. Online help is automatically shown for each kernel configuration option. It also can show dependency information for each module which can help diagnose build errors. Figure 3 shows an example of the xconfig screen. From the online help:

For each option, a blank box indicates the feature is disabled, a check
indicates it is enabled, and a dot indicates that it is to be compiled
as a module. Clicking on the box will cycle through the three states.
If you do not see an option (e.g., a device driver) that you believe
should be present, try turning on Show All Options under the Options menu.
Although there is no cross reference yet to help you figure out what other
options must be enabled to support the option you are interested in, you can
still view the help of a grayed-out option.

--qconf help

Figure 3. make xconfig

Once you have decided which configuration option to use, start the process with make followed by either config, menuconfig, or xconfig. For example:

		 	$ make menuconfig

The system will take a few moments to build the configuration utility. Next you will be presented with the configuration menus. Though similar to the 2.4.x series, the 2.6.x menu is more logically organized with better grouping of sub-modules. Following are some of the top level configuration options in the 2.6 kernel.

 

Code Maturity Level Options

This option allows configuration of alpha-quality software or obsoleted drivers. It is best to disable this option if the kernel is intended for a stable production system. If you require an experimental feature in the kernel, such as a driver for new hardware, then enable this option but be aware that it "may not meet the normal level of reliability" as more rigorously tested code.

General Setup

This section contains options for sysctl support, a feature allowing run-time configuration of the kernel. A new feature, kernel .config support, allows the complete kernel configuration to be viewed during run-time. This addresses many requests to be able to see what features were compiled into the kernel.

Loadable Module Support

You will almost certainly want to enable module support. If you will need third-party kernel modules you will also need to enable Set Version Information on All Module Symbols.

Processor Type and Features

This is perhaps the most important configuration choice. In the Preparation section we determined our processor type by examining /proc/cpuinfo and we use that information here to select the appropriate processor. Included in this submenu are features such as Preemptible Kernel which can improve desktop responsiveness, Symmetric Multi-processing Support for machines with multiple CPUs, and High Memory Support for machines with more than 1G of RAM.

Power Management Options

Found here are options for ACPI and CPU Frequency Scaling which can dramatically improve laptop power usage. Read the Documentation/power file for more information.

Bus Options ( PCI, PCMCIA, EISA, MCA, ISA)

Here are found options for all system bus devices. On modern machines the ISA and MCA support can often be disabled.

Executable File Formats

Interesting features here include the kernel support for miscellaneous binaries, which can allow seamless operation of non-Linux binaries with a little userland help.

Device Drivers

All the device-driver configuration options that were previously scattered throughout the 2.4.x menus are now neatly organized under this option. Features such as SCSI support, graphic card optimizations, sound, USB and other hardware are configured here.

File Systems

Found here are options for filesystems which are supported by the kernel, such as EXT2 and ReiserFS. It is best to build support for the root filesystems directly into the kernel rather than as a module.

Security Options

Interesting options here include support for NSA Security Enhanced Linux and other, somewhat experimental, features to increase security.


Build

Dependencies

The next step is to create the necessary include files and generate dependency information. This step is only required for the 2.4.x kernel tree.

			$make dep

Lots of messages will scroll by. Depending on the speed of your machine and on what options you chose, this may take several minutes to complete. Once the dependency information is created we can clean up some miscellaneous object files. This step is required for all versions of the kernel.

			$make clean


Build the Kernel

We are now (finally) ready to start the actual kernel build. At the prompt type:

			$make bzImage

As the Kbuild documentation states:

Some computers won't work with 'make bzImage', either due to hardware
problems or very old versions of lilo or loadlin. If your kernel image
is small, you may use 'make zImage', 'make zdisk', or 'make zlilo'
on these systems.

--Kbuild 2.4 Documentation

[6] On an Athlon 1800XP, building the bzImage took approximately seven minutes for a moderately configured kernel. On a Pentium 100 used as a baseline, a similar configuration took almost 45 minutes. If you are not in a hurry you may want to start the build on a console while you continue to work. The main difference between the 2.4 and 2.6 trees is the amount of information presented on the screen. Much less information is displayed with 2.6.x, making errors and warnings easier to spot. If everything went correctly then the new kernel should exist in ./arch/$ARCH/boot. For example, on IA32 systems we can verify this with:

			$ls -l arch/i386/boot


Build the Modules

There is one more step needed for the build process, however. You have created the kernel, but now you need to create all the loadable modules if you have them configured. Be aware that typical distribution kernels tend to have almost every feature installed, plus a few others for good measure. These can typically take an hour or so to build on our Athlon XP1800. The stock kernels are somewhat leaner by default and take, on average, 25 minutes to compile. To build the modules we run:

			$ make modules

Again, lots of messages will scroll by on the screen. Here also the 2.6.x series is less talkative, outputting only summary information. Once the modules are built they can be installed. If you were building as a non-privileged user you will now need to switch to root to complete this next step:

			$ su
password:
$ make modules_install

The freshly baked modules will be copied into /lib/modules/KERNEL_VERSION.


Create Initial RAMDisk

If you have built your main boot drivers as modules (e.g., SCSI host adapter, filesystem, RAID drivers) then you will need to create an initial RAMdisk image. The initrd is a way of sidestepping the chicken and egg problem of booting -- drivers are needed to load the root filesystem but the filesystem cannot be loaded because the drivers are on the filesystem. As the manpage for mkinitrd states:

mkinitrd creates filesystem images which are suitable for use as Linux initial
ramdisk(initrd) images. Such images are often used for preloading  the
block device modules (such as IDE, SCSI or RAID) which are needed to access the
root filesystem. mkinitrd automatically loads filesystem  modules (such as
ext3 and jbd), IDE modules,all scsi_hostadapter entries in /etc/modules.conf,
and raid modules if the systems root partition is on raid, which makes it
simple to build and use kernels using modular device drivers.

--MKINITRD(8)

To create the initrd, do the following:

				$ mkinitrd /boot/initrd-2.6.0.img 2.6.0

Some versions of mkinitrd may require other options to specify the location of the new kernel. On SuSe 9.0, for example, the following syntax is required:

				$ mkinitrd -k vmlinux-VERSION -i initrd-VERSION

[7]


Troubleshooting Build Failures

If your build fails with a signal 11 error it is most likely because of hardware problems; often the culprit is failing memory. Unfortunately, the BIOS memory check is close to useless in detecting intermittent memory failures. Even dedicated memory checkers do not stress memory as much as gcc running a kernel build. One way to tell if hardware is at fault is to restart the 'make bzImage' process. If you can get a little further before failing again then it is a hardware error. There are several possible ways to try to correct these.

Try changing your memory settings in the BIOS to more conservative levels. For example, change to SLOW or NORMAL instead of FAST. Verify that all the fans are working correctly. [8] Swap out the memory. One trick is to specify less memory than is actually installed by passing values to the kernel on boot. This prevents the kernel from accessing all the memory in the machine, and could help diagnose bad SIMMs or SDRAMs.

If instead the 'make' fails at the same point each time, then it is a configuration error. These usually result from not enabling a feature that is required by another. For example, IP Firewalling requires TCP/IP. If the prerequisite is not enabled, the build will fail. You may also get errors if you select the wrong processor or are using either a very old or development compiler.

Also keep in mind that the kernel is highly sensitive to the versions of the build tools such as the compiler and linker. The versions listed are requirements, not suggested.


Installation

Copy the Kernel and System.map

Once your kernel is created, you can prepare it for use. From the ./linux directory, copy the kernel and System.map file to /boot. In the following examples change KERNEL_VERSION to the version of your kernel. [9]

			$ cp arch/i386/boot/bzImage /boot/bzImage-KERNEL_VERSION
$ cp System.map /boot/System.map-KERNEL_VERSION
$ ln -s /boot/System.map-KERNEL_VERSION /boot/System.map

The next step is to configure your bootloader. The bootloader is the first program that runs when a computer is booted. For this document it is assumed that you are running an IA32 system with a standard PC BIOS. If you are running the LiLO bootloader skip to the the Section called LiLO Configuration otherwise proceed to the Section called GrUB Configuration.

FIXME: Need information on non-IA32 bootloaders!!


GrUB Configuration

GrUB is beginning to supplant LiLO as the bootloader of choice in more recent Linux distributions. It is generally more flexible and a lot more forgiving of system errors. For example, LiLO generally requires that an alternate boot disk is used if the kernel configuration renders the system unbootable Grub allows "on-the-fly" modification of kernel location, boot parameters, kernel to boot, etc..

Once you have copied the bzImage and System.map to /boot, edit the grub configuration file located in /boot/grub/menu.lst. On some distributions /etc/grub.conf is a symbolic link to this file.

		# Note that you do not have to rerun grub after making changes to this file
#boot=/dev/hda
default=0
timeout=10
title Red Hat Linux (2.4.20-24.9)
root (hd0,1)
kernel /boot/vmlinuz-2.4.20-24.9 ro root=LABEL=/
initrd /boot/initrd-2.4.20-24.9.img
title Red Hat Linux (2.4.20-20.9)
root (hd0,1)
kernel /boot/vmlinuz-2.4.20-20.9 ro root=LABEL=/
initrd /boot/initrd-2.4.20-20.9.img

Edit the file to include your new kernel information. Keep in mind that GrUB counts starting from 0, so (hd0,1) references the first controller, second partition. If you have created an initial RAMdisk be sure to include it here too. A typical configuration may look something like this:

		title Test Kernel (2.6.0)
root (hd0,1)
kernel /boot/bzImage-2.6.0 ro root=LABEL=/
initrd /boot/initrd-2.6.0.img


LiLO Configuration

LiLO is an older bootloader. Its configuration file is located in /etc/lilo.conf on most systems. Unlike GrUB, any changes to lilo.conf will not be set until the lilo program is rerun.

		boot=/dev/hda
map=/boot/map
install=/boot/boot.b
default=test-2.6.0
keytable=/boot/us.klt
lba32
prompt
timeout=50
message=/boot/message
menu-scheme=wb:bw:wb:bw
image=/boot/vmlinuz
label=linux
root=/dev/hda3
append=" ide1=autotune ide0=autotune"
read-only

image=/boot/bzImage-2.6.0
label=test-2.6.0
root=/dev/hda2
read-only

The important sections are the image=/boot/bzImage and the default=test-2.6.0 options. Notice that you can have several image sections in the lilo.conf, allowing multiple configurations. Install the new kernel by running the lilo program.

		$  /sbin/lilo

If you are installing and testing the kernel remotely, you can instead specify to LiLO that the new kernel is loaded only for the next boot by using the following syntax:

		$  /sbin/lilo -R test-2.6.0

Messages will appear showing the newly added kernel with an asterisk marking the default image. If you get errors, consult the lilo documentation for the correct syntax.


Bibliography

Books

[LinuxKernel] Daniel P. Dovet and Marco Cesati, 2003, Edited by FIXME FIXME, 0672325128 , SAMS, Linux Kernel Development.


Resources

Online Resources

 


Feedback

Comments and corrections

The current maintainer of this HOWTO is Kwan Lowe. Please send corrections, additions, comments and criticisms to .

The HOWTO's maintainer is not a professional writer. If you find some parts of this HOWTO difficult to comprehend then let the maintainer know.


Colophon

Written in DocBook 4.1 SGML. Vim was used to create the SGML source file. The HTML, PostScript and PDF output was generated from the DocBook source by the Linux Documentation Project.

 

Notes

 

[1]

I have successfully installed a serviceable machine on an original Pentium 100, 64M RAM, and 1.2G of drive space. A full build of the 2.6.0test9 kernel took approximately 4 hours to complete.

[2]

On an RPM-based system you can query a minimal version with a command such as:

			$ rpm -q --requires gcc|grep glibc
[3]

Distributions will often install the kernel sources into /usr/src/linux. To build in this directory will require root access. Note that there are usually two source packages -- one called something like kernel-source-VERSION-i386.rpm and another called kernel-VERSION.src.rpm. You can generally rebuild the src.rpm as an unpriveleged user.

[4]

This is a relative thing. The initrd utility is robust and easy to use. Bootloaders have also improved to the point that little effort is saved by using static kernels. My two cents.

[5]

I have noticed some minor screen corruption when using menuconfig in slightly non-standard terminals. Though it functions normally some of the menu entries may be difficult to read until the screen is refreshed.

[6]

The difference between 'zImage' files and 'bzImage' files is that 'bzImage' uses a different layout and a different loading algorithm, and thus has a larger capacity. Both files use gzip compression. The 'bz' in 'bzImage' stands for 'big zImage', not for 'bzip'!

[7]

At this writing there are some issues with the modules.conf when moving from 2.4 to 2.6 kernels. Some module names have changed which seems to cause glitches with initrd.

[8]

For a long while, I thought that the xmatrix screensaver was crashing my machine because of the numerous core dumps I would discover in my home directory. It turned out that xmatrix was cpu intensive. Unknown to me, the CPU fan on this machine had failed. Everything was fine until xmatrix started, causing the processor to overheat, eventually leading to a crash.

[9]

Jerome Walter offers the following information for PowerPPC plaforms: On a PowerPC (PreP architecture). To make the system bootable, one needs to copy the bzImage file into the special partition (PreP Boot Partition type 41), using dd. Assuming that the so called partition is named /dev/sda1, the command should look like :

			$ dd if=bzImage-you-have-just-done.img of=/dev/sda1

People should be warned that if their partition is too small, the bzImage will not fit, and the boot procedure will fail.

Kwan Lowe
Digital Hermit
kwan@digitalhermit.com
Dedication: To penguin lovers everywhere...
Copyright and License

This document, Kernel Build HOWTO, is copyrighted (c) 2004 by Kwan L. Lowe. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is available at http://www.gnu.org/copyleft/fdl.html .

Linux is a registered trademark of Linus Torvalds.

 

loadable kernel module

Loadable Kernel Modules (LKM) allow admins to code to the Linux kernel while it is running. These modules can do lots of things, but they typically are one of three things:

  1. device drivers;
  2. filesystem drivers;
  3. system calls.

The kernel isolates certain functions, including these, especially well so they don't have to be intricately wired into the rest of the kernel.

The Case For Loadable Kernel Modules

You often have a choice between putting a module into the kernel by loading it as an LKM or binding it into the base kernel. LKMs have a lot of advantages over binding into the base kernel and I recommend them wherever
possible.

One advantage is that you don't have to rebuild your kernel as often. This saves you time and spares you the possibility of introducing an error in rebuilding and reinstalling the base kernel. Once you have a working base kernel, it is good to leave it untouched as long as possible.

Another advantage is that LKMs help you diagnose system problems. A bug in a device driver which is bound into the kernel can stop your system from booting at all. And it can be really hard to tell which part of the base kernel caused the trouble. If the same device driver is an LKM, though, the base kernel is up and running before the device driver even gets loaded. If
your system dies after the base kernel is up and running, it's an easy matter to track the problem down to the trouble-making device driver and just not load that device driver until you fix the problem.

LKMs can save you memory, because you have to have them loaded only when you're actually using them. All parts of the base kernel stay loaded all the time. And in real storage, not just virtual storage.

LKMs are much faster to maintain and debug. What would require a full reboot to do with a filesystem driver built into the kernel, you can do with a few quick commands with LKMs. You can try out different parameters or even change the code repeatedly in rapid succession, without waiting for a boot.

LKMs are not slower, by the way, than base kernel modules. Calling either one is simply a branch to the memory location where it resides. [1]

Sometimes you have to build something into the base kernel instead of making it an LKM. Anything that is necessary to get the system up far enough to load LKMs must obviously be built into the base kernel. For example, the driver
for the disk drive that contains the root filesystem must be built into the base kernel.

What LKMs Can't Do

There is a tendency to think of LKMs like user space programs. They do share a lot of their properties, but LKMs are definitely not user space programs. They are part of the kernel. As such, they have free run of the system and can easily crash it.

What LKMs Are Used For

There are six main things LKMs are used for:

* Device drivers. A device driver is designed for a specific piece of hardware. The kernel uses it to communicate with that piece of hardware without having to know any details of how the hardware works. For example, there is a device driver for ATA disk drives. There is one for NE2000 compatible Ethernet cards. To use any device, the kernel must contain a device driver for it.

* Filesystem drivers. A filesystem driver interprets the contents of a filesystem (which is typically the contents of a disk drive) as files and directories and such. There are lots of different ways of storing files and directories and such on disk drives, on network servers, and in other ways. For each way, you need a filesystem driver. For example, there's a filesystem driver for the ext2 filesystem type used almost universally on Linux disk drives. There is one for the MS-DOS filesystem too, and one for NFS.

* System calls. User space programs use system calls to get services from the kernel. For example, there are system calls to read a file, to create a new process, and to shut down the system. Most system calls are integral to the system and very standard, so are always built into the base kernel (no LKM option). But you can invent a system call of your own and install it as an LKM. Or you can decide you don't like the way Linux does something and override an existing system call with an LKM of your own.

* Network drivers. A network driver interprets a network protocol. It feeds and consumes data streams at various layers of the kernel's networking function. For example, if you want an IPX link in your network, you would use the IPX driver.

* TTY line disciplines. These are essentially augmentations of device drivers for terminal devices.

* Executable interpreters. An executable interpreter loads and runs an executable. Linux is designed to be able to run executables in various formats, and each must have its own executable interpreter.

making loadable kernel modules

An LKM lives in a single ELF object file (normally named like "serial.o"). You typically keep all your LKM object files in a particular directory (near your base kernel image makes sense). When you use the insmod program to insert an LKM into the kernel, you give the name of that object file.

For the LKMs that are part of Linux, you build them as part of the same kernel build process that generates the base kernel image. See the README file in the Linux source tree. In short, after you make the base kernel image with a command such as make zImage, you will make all the LKMs with the command

make modules

This results in a bunch of LKM object files (*.o) throughout the Linux source tree. (In older versions of Linux, there would be symbolic links in the modules directory of the Linux source tree pointing to all those LKM object files). These LKMs are ready to load, but you probably want to install them in some appropriate directory. The conventional place is described in Section 5.6. The command make modules_install will copy them all over to the conventional locations.

Part of configuring the Linux kernel (at build time) is choosing which parts of the kernel to bind into the base kernel and which parts to generate as separate LKMs. In the basic question-and-answer configuration (make config), you are asked, for each optional part of the kernel, whether you want it bound into the kernel (a "Y" response), created as an LKM (an "M" response),
or just skipped completely (an "N" response). Other configuration methods are similar.

As explained in Section 2.3, you should have only the bare minimum bound into the base kernel. And only skip completely the parts that you're sure you'll never want. There is very little to lose by building an LKM that you won't use. Some compile time, some disk space, some chance of a problem in the code killing the kernel build. That's it.

As part of the configuration dialog you also must choose whether to use symbol versioning or not. This choice affects building both the base kernel and the LKMs and it is crucial you get it right. See Section 6.

LKMs that are not part of Linux (i.e. not distributed with the Linux kernel) have their own build procedures which I will not cover. The goal of any such procedure, though, is always to end up with an ELF object file.

You don't necessarily have to rebuild all your LKMs and your base kernel image at the same time (e.g. you could build just the base kernel and use LKMs you built earlier with it) but it is always a good idea.

networks

network pages go here...

dns

Introduction.

What this is and isn't.

DNS is the Domain Name System. DNS converts machine names to the IP addresses that all machines on the net have. It translates (or "maps" as the jargon would have it) from name to address and from address to name, and some other things. This HOWTO documents how to define such mappings using Unix system, with a few things specific to Linux.

A mapping is simply an association between two things, in this case a machine name, like ftp.linux.org, and the machine's IP number (or address) 199.249.150.4. DNS also contains mappings the other way, from the IP number to the machine name; this is called a "reverse mapping".

DNS is, to the uninitiated (you ;-), one of the more opaque areas of network administration. Fortunately DNS isn't really that hard. This HOWTO will try to make a few things clearer. It describes how to set up a simple DNS name server, starting with a caching only server and going on to setting up a primary DNS server for a domain. For more complex setups you can check the qanda section of this document. If it's not described there you will need to read the Real Documentation. I'll get back to what this Real Documentation consists of in the last chapter.

Before you start on this you should configure your machine so that you can telnet in and out of it, and successfully make all kinds of connections to the net, and you should especially be able to do telnet 127.0.0.1 and get your own machine (test it now!). You also need good /etc/nsswitch.conf, /etc/resolv.conf and /etc/hosts files as a starting point, since I will not explain their function here. If you don't already have all this set up and working the Networking-HOWTO and/or the Networking-Overview-HOWTO explains how to set it up. Read them.

When I say `your machine' I mean the machine you are trying to set up DNS on, not any other machine you might have that's involved in your networking effort.

I assume you're not behind any kind of firewall that blocks name queries. If you are you will need a special configuration --- see the section on qanda.

Name serving on Unix is done by a program called named. This is a part of the ``BIND'' package which is coordinated by The Internet Software Consortium. Named is included in most Linux distributions and is usually installed as /usr/sbin/named, usually from a package called BIND, in upper or lower case depending on the whim of the packager.

If you have a named you can probably use it; if you don't have one you can get a binary off a Linux ftp site, or get the latest and greatest source from ftp://ftp.isc.org/isc/bind9/. This HOWTO is about BIND version 9. The old versions of the HOWTO, about BIND 4 and 8, is still available at http://langfeldt.net/DNS-HOWTO/ in case you use BIND 4 or 8 (incidentally, you will find this HOWTO there too). If the named man page talks about (at the very end, in the FILES section) named.conf you have BIND 8; if it talks about named.boot you have BIND 4. If you have 4 and are security conscious you really ought to upgrade to the latest version of BIND 8. Now.

DNS is a net-wide database. Take care about what you put into it. If you put junk into it, you, and others, will get junk out of it. Keep your DNS tidy and consistent and you will get good service from it. Learn to use it, admin it, debug it and you will be another good admin keeping the net from falling to its knees by mismanagement.

Tip: Make backup copies of all the files I instruct you to change if you already have them, so that if after going through this nothing works you can get it back to your old, working state.

file management

this book contains information on file management

directory overview

 

< / >

The root directory. The starting point of your directory structure. This is where the Linux system begins. Every other file and directory on your system is under the root directory. Usually the root directory contains only subdirectories, so it's a bad idea to store single files directly under root.

Don't confuse the root directory with the root user account, root password (which obviously is the root user's password) or root user's home directory.

< /boot >

As the name suggests, this is the place where Linux keeps information that it needs when booting up. For example, this is where the Linux kernel is kept. If you list the contents of /boot, you'll see a file called vmlinuz - that's the kernel.

< /etc >

The configuration files for the Linux system. Most of these files are text files and can be edited by hand. Some interesting stuff in this directory:

/etc/inittab
A text file that describes what processes are started at system bootup and during normal operation. For example, here you can determine if you want the X Window System to start automatically at bootup, and configure what happens when a user presses Ctrl+Alt+Del.

/etc/fstab
This file contains descriptive information about the various file systems and their mount points, like floppies, cdroms, and so on.

/etc/passwd
A file that contains various pieces of information for each user account. This is where the users are defined.

< /bin, /usr/bin >

These two directories contain a lot of programs (binaries, hence the directory's name) for the system. The /bin directory contains the most important programs that the system needs to operate, such as the shells, ls, grep, and other essential things. /usr/bin in turn contains applications for the system's users. However, in some cases it really doesn't make much difference if you put the program in /bin or /usr/bin.

< /sbin, /usr/sbin >

Most system administration programs are stored in these directories. In many cases you must run these programs as the root user.

< /usr >

This directory contains user applications and a variety of other things for them, like their source codes, and pictures, docs, or config files they use. /usr is the largest directory on a Linux system, and some people like to have it on a separate partition. Some interesting stuff in /usr:

/usr/doc
Documentation for the user apps, in many file formats.

/usr/share
Config files and graphics for many user apps.

/usr/src
Source code files for the system's software, including the Linux kernel.

/usr/include
Header files for the C compiler. The header files define structures and constants that are needed for building most standard programs. A subdirectory under /usr/include contains headers for the C++ compiler.

/usr/X11R6
The X Window System and things for it. The subdirectories under /usr/X11R6 may contain some X binaries themselves, as well as documentation, header files, config files, icons, sounds, and other things related to the graphical programs.

< /usr/local >

This is where you install apps and other files for use on the local machine. If your machine is a part of a network, the /usr directory may physically be on another machine and can be shared by many networked Linux workstations. On this kind of a network, the /usr/local directory contains only stuff that is not supposed to be used on many machines and is intended for use at the local machine only.

Most likely your machine isn't a part of a network like this, but it doesn't mean that /usr/local is useless. If you find interesting apps that aren't officially a part of your distro, you should install them in /usr/local. For example, if the app would normally go to /usr/bin but it isn't a part of your distro, you should install it in /usr/local/bin instead. When you keep your own programs away from the programs that are included in your distro, you'll avoid confusion and keep things nice and clean.

< /lib >

The shared libraries for programs that are dynamically linked. The shared libraries are similar to DLL's on Winblows.

< /home >

This is where users keep their personal files. Every user has their own directory under /home, and usually it's the only place where normal users are allowed to write files. You can configure a Linux system so that normal users can't even list the contents of other users' home directories. This means that if your family members have their own user accounts on your Linux system, they won't see all the w4r3z you keep in your home directory. ;-)

< /root >

The superuser's (root's) home directory. Don't confuse this with the root directory (/) of a Linux system.

< /var >

This directory contains variable data that changes constantly when the system is running. Some interesting subdirectories:

/var/log
A directory that contains system log files. They're updated when the system runs, and checking them out can give you valuable info about the health of your system. If something in your system suddenly goes wrong, the log files may contain some info about the situation.

/var/mail
Incoming and outgoing mail is stored in this directory.

/var/spool
This directory holds files that are queued for some process, like printing.

< /tmp >

Programs can write their temporary files here.

< /dev >

The devices that are available to a Linux system. Remember that in Linux, devices are treated like files and you can read and write devices like they were files. For example, /dev/fd0 is your first floppy drive, /dev/cdrom is your CD drive, /dev/hda is the first IDE hard drive, and so on. All the devices that a Linux kernel can understand are located under /dev, and that's why it contains hundreds of entries.

< /mnt >

This directory is used for mount points. The different physical storage devices (like the hard disk drives, floppies, CD-ROM's) must be attached to some directory in the file system tree before they can be accessed. This attaching is called mounting, and the directory where the device is attached is called the mount point.

The /mnt directory contains mount points for different devices, like /mnt/floppy for the floppy drive, /mnt/cdrom for the CD-ROM, and so on. However, you're not forced to use the /mnt directory for this purpose, you can use whatever directory you wish. Actually in some distros, like Debian and SuSE, the default is to use /floppy and /cdrom as mount points instead of directories under /mnt.

< /proc >

This is a special directory. Well, actually /proc is just a virtual directory, because it doesn't exist at all! It contains some info about the kernel itself. There's a bunch of numbered entries that correspond to all processes running on the system, and there are also named entries that permit access to the current configuration of the system. Many of these entries can be viewed.

< /lost+found >

Here Linux keeps the files that it restores after a system crash or when a partition hasn't been unmounted before a system shutdown. This way you can recover files that would otherwise have been lost.

access control lists on fedora

What Are ACLs And Their Purpose

Access control lists (ACLs) are a kernel-level feature of Fedora's default ext3 file system. ACLs provide an important level of flexibility for managing file permissions, that is, who or what has the rights to read, write, or execute a file.

Traditional Linux/UNIX file permissions (read, write, execute) are defined for three classes of users: the file owner, the file group, and others. This means that when a group is granted access to a particular shared resource (document, directory, printer, etc.), the same level of access is granted to all members of a group.

In practice, it is often required that some of the group members have limited or no access to the shared resource, or that the access is granted to other users who are not members of the particular group. In a non-ACL file permissions scheme this requires creation of numerous new groups, which quickly becomes difficult to manage, especially on large systems.

Fedora provides ACL support for ext3, NFS-exported ext3, and ext3 file systems accessed via Samba (which provides CIFS/Microsoft Windows file sharing.)

The most common file manipulation utilities, such as mv, cp, and ls also support ACLs. To preserve ACLs when archiving files, the star utility should be used instead of tar, which does not support ACLs.

There are two types of ACLs:

  • Access ACL - ACL that controls the level of access to the object (file or directory)
  • Default ACL - ACL associated with a directory. If set, all objects within a directory inherit the default ACL as their initial access ACL

Each ACL is composed of a set of ACL entries. Each ACL entry specifies access permissions to the object as a combination of read, write, and execute permissions for an individual user or a group.

Using Access Control Lists

There are a few prerequisites to using ACLs:

  • File system must support ACLs
  • File system must be mounted with acl option
  • RPM package acl must be installed

Enabling ACLs on a file system

On a default Fedora installation, file systems are mounted without ACL support. To enable ACLs for a local file system, edit the /etc/fstab file and add the acl option for the desired partition. The entry might look similar to:

LABEL=/data   /data   ext3   rw,acl   1 2

This entry ensures that ACL support is preserved after reboot but reboot is not required to enable ACLs. To accomplish this on an already mounted /data partition run:

su -c '/bin/mount -o remount /data'

Additional parameters are not required when mounting ACL enabled remote Samba shares. If the client accessing an NFS share can read ACLs and the NFS share is exported from an ACL enabled file system, ACLs are utilized by the client.

Setting ACLs and retrieving ACL information

ACLs are controlled by two utilities:

  • getfacl is used to retrieve ACL information
  • setfacl is used to set or modify ACL entry

To view ACL information on an object (directory docs) in the /data directory, run:

getfacl /data/docs

The output shows ACL information associated with the docs directory:

getfacl: Removing leading '/' from absolute path names
user::rwx
group::r-x
other::r-x

Since ACLs are not yet set, this information corresponds to common permissions on the /data/docs directory:

ls -dl /data/docs
drwxr-xr-x 5 jerry black 4096 Nov 1 19:57 /data/docs

To set an ACL for an object, run setfacl:

setfacl -m <rules> <object>

The command option -m is used to create or modify an ACL entry. For an object without previously set ACLs, a new ACL entry is created. If an object already has an ACL entry, option -m modifies the existing ACL entry by appending the new ACL entry to the object's ACL.

If using the --set option, all user, group, and others permissions must be defined.
The command option --set is used to create a new ACL or replace all existing ACLs on the object, so it needs a complete definition for the setting.

The <object> is a file or a directory on which an ACL is created

The <rules> are specified per user, per group, using an effective rights mask or for users who are not members of the user group for an object, using one of the following:

u:<uid>:<permissions>: sets the ACL for user; <uid> can be user name or numerical UID; <permissions> are any combination of rwx

g:<gid>:<permissions>: sets the ACL for group; <gid> can be group name or numerical GID; <permissions> are any combination of rwx

m:<permissions>: sets the effective rights mask on the object; <permissions> are any combination of rwx

o:<permissions>: sets the ACL for users who are not members of the object group; <permissions> are any combination of rwx

The effective rights mask is a sum of all permissions of the object group owner and all ACLs set on the object. It represents the actual rights granted to all ACL users and groups on the object and limits their access to the level it specifies. If a user has read and write permission through an ACL but the mask is set to read, the more restrictive permission (read) is in effect. The effective mask does not apply to file owner or file group.

Numerical UID or GID can be specified for a non-existing user or group, respectively. If the actual user or group name is specified, they must exist on the system, otherwise the setfacl command exits with an error.

To specify multiple ACLs on the same line, separate them by commas. Blank spaces are ignored:

setfacl -m u:<uid>:rw,g:<gid>:rx, u:<uid>:r /dir/file

To remove an ACL entry for user, use the -x command option and do not specify any permissions:

setfacl -x u:<uid> /dir/file

To set the default ACL, prefix the rule with a d:

setfacl -m d:g:<gid>:rx /dir

ACL examples

To grant the user carlos read, write, and execute rights on all files in the /data/docs directory, run:

setfacl -R -m u:carlos:rw /data/docs

(i) Use the -R command option to recursively set ACL on all files in /data/docs directory.

To check permissions for the /data/docs directory, run:

ls -dl /data/docs
drwxrwxr-x+ 5 jerry black 4096 Nov 1 19:57 /data/docs

To check modified ACL information for the /data/docs directory, run:

getfacl /data/docs
getfacl: Removing leading '/' from absolute path names
user::rwx
user:carlos:rwx
group::r-x
mask::rwx
other::r-x

Both of the above commands now produce a different output than previously.

The plus sign next to permission bits after the ls command shows that the ACL is now set on the object. Likewise, the getfacl output has two additional entries:

  • user:carlos:rwx indicates the additional user with the access rights on the object
  • mask::rwx denotes the effective rights on the object

The setfacl command also accepts input from text files. This is useful if identical long rules must be set for large number of objects. To accomplish this, create a plain text file (rules.txt in the next example) with a rule per line and use the -M command option to set ACL on all html files in a directory /dir:

setfacl -M rules.txt /dir/*.html

The format of the rules.txt file is the same as an output of the getfacl command with the --omit-header option:

getfacl --omit-header /data/etc/conf/script1.cfg

user::rw-
user:jerry:rw-
group::r--
group:black:r-x
mask::rwx
other::r--

This is very useful if the same ACL must be applied to some other files. You can create the rules.txt file by simply redirecting the output of the getfacl command:

getfacl --omit-header /data/etc/conf/script1.cfg > rules.txt

cat rules.txt
user::rw-
user:jerry:rw-
roup::r--
group:black:r-x
mask::rwx
other::r--

Copying And Archiving ACLs

Common file utilities mv and cp on Fedora support ACLs. Archiving tools such as tar and dump do not have support for ACLs and the star utility should be used to preserve ACLs while archiving files.

Copying And Moving ACLs

To copy the file or directory while preserving ACLs, use the -p or -a command option:

cp -p /dir1/file1 /dirx/file2
The /dirx directory must reside on a partition mounted with the acl option to copy the ACL of file1 to file2.
cp -a /dir1/dir2 /dirx/dir3
The /dirx directory must reside on a partition mounted with the acl option to copy the ACLs of dir2 to dir3.

The mv command always transfers ACLs, without any extra command options, if the destination file system is ACL enabled. If not, it transfers the files and issues a warning about the inability to preserve ACLs.

Archiving ACLs

To archive the files or directories while preserving ACLs, use the star command with the -acl option:

star -c -acl file=archive.star /data

This creates the backup.star archive of /data directory with preserved ACLs.

To restore the star archive and ACLs, run star with the -acl command option:

star -x -acl file=backup.star

This extracts the backup.star archive into current directory with preserved ACLs. The target filesystem being extracted to must support ACLs for this to work.

Additional Information

Related web sites

ACLs web site:

Related manuals

For more information on ACLs and associated utilities, read the following manual pages:

  • man acl
  • man getfacl
  • man setfacl
  • man star

fstab manpage

fstab stand's for File System TABle. It is where the system administrator can tell the OS about any filesystems the machine may have access to. It also allows default parameters to be provided for each filesystem.

A typical fstab looks something like the following:

#
# /etc/fstab
#
# <device> <mountpoint> <filesystemtype><options> <dump> <fsckorder>

/dev/hdb5 / ext2 defaults 1 1
/dev/hdb2 /home ext2 defaults 1 2
/dev/hdc /mnt/cdrom iso9660 noauto,ro,user 0 0
/dev/hda1 /mnt/dos/c msdos defaults 0 0
/dev/hdb1 /mnt/dos/d msdos defaults 0 0
/dev/fd0 /mnt/floppy ext2 noauto,user 0 0
/dev/hdb4 none ignore defaults 0 0

none /proc proc defaults
/dev/hdb3 none swap sw

Note that this system has two IDE partitions, one which is used as /, and the other used as /home. It also has two DOS partitions which are mounted under /mnt. Note the user option provided for the cdrom, and the floppy drive. This is one of the many default parameters you can specify. In this case it means that any user can mount a cdrom, or floppy disk. Other options will be dealt with later.

fstab consists of a number of lines (one for each filesystem) seperated into six fields. Each field is seperated from the next by whitespace (spaces/tabs).

So from the example given previously:

/dev/hdc	/mnt/cdrom   	iso9660  	noauto,ro,user 	0 	0

The first field (/dev/hdc) is the physical device/remote filesystem which is to be described.

The second field (/mnt/cdrom) specifies the mount point where the filesystem will be mounted.

The third field (iso9660) is the type of filesystem on the device from the first field.

The fourth field (noauto,ro,user) is a (default) list of options which mount should use when mounting the filesystem.

The fifth field (0) is used by dump (a backup utility) to decide if a filesystem should be backed up. If zero then dump will ignore that filesystem. The sixth field (0) is used by fsck (the filesystem check utility) to determine the order in which filesystems should be checked.
If zero then fsck won't check the filesystem.
(as the example line above is a cdrom there is very little point in doing a fsck on it, so the value is zero).

lvm manpage

LVM(8) LVM(8)

NAME

lvm - LVM2 tools

SYNOPSIS

lvm [command | file]

DESCRIPTION

lvm provides the command-line tools for LVM2. A separate manual page
describes each command in detail.

If lvm is invoked with no arguments it presents a readline prompt
(assuming it was compiled with readline support). LVM commands may be
entered interactively at this prompt with readline facilities including
history and command name and option completion. Refer to readline(3)
for details.

If lvm is invoked with argv[0] set to the name of a specific LVM com‐
mand (for example by using a hard or soft link) it acts as that com‐
mand.

Where commands take VG or LV names as arguments, the full path name is
optional. An LV called "lvol0" in a VG called "vg0" can be specified
as "vg0/lvol0". Where a list of VGs is required but is left empty, a
list of all VGs will be substituted. Where a list of LVs is required
but a VG is given, a list of all the LVs in that VG will be substi‐
tuted. So "lvdisplay vg0" will display all the LVs in "vg0". Tags can
also be used - see addtag below.

One advantage of using the built-in shell is that configuration infor‐
mation gets cached internally between commands.

A file containing a simple script with one command per line can also be
given on the command line. The script can also be executed directly if
the first line is #! followed by the absolute path of lvm.

BUILT-IN COMMANDS

The following commands are built into lvm without links normally being
created in the filesystem for them.

dumpconfig — Display the configuration information after
loading lvm.conf (5) and any other configuration files.

formats — Display recognised metadata formats.

help — Display the help text.

pvdata — Not implemented in LVM2.

segtypes — Display recognised logical volume segment types.

version — Display version information.

COMMANDS

The following commands implement the core LVM functionality.

pvchange — Change attributes of a physical volume.

pvck — Check physical volume metadata.

pvcreate — Initialize a disk or partition for use by LVM.

pvdisplay — Display attributes of a physical volume.

pvmove — Move physical extents.

pvremove — Remove a physical volume.

pvresize — Resize a disk or partition in use by LVM2.

pvs — Report information about physical volumes.

pvscan — Scan all disks for physical volumes.

vgcfgbackup — Backup volume group descriptor area.

vgcfgrestore — Restore volume group descriptor area.

vgchange — Change attributes of a volume group.

vgck — Check volume group metadata.

vgconvert — Convert volume group metadata format.

vgcreate — Create a volume group.

vgdisplay — Display attributes of volume groups.

vgexport — Make volume groups unknown to the system.

vgextend — Add physical volumes to a volume group.

vgimport — Make exported volume groups known to the system.

vgmerge — Merge two volume groups.

vgmknodes — Recreate volume group directory and logical volume special
files

vgreduce — Reduce a volume group by removing one or more physical vol‐
umes.

vgremove — Remove a volume group.

vgrename — Rename a volume group.

vgs — Report information about volume groups.

vgscan — Scan all disks for volume groups and rebuild caches.

vgsplit — Split a volume group into two, moving any logical volumes
from one volume group to another by moving entire physical volumes.

lvchange — Change attributes of a logical volume.

lvconvert — Convert a logical volume from linear to mirror or snapshot.

lvcreate — Create a logical volume in an existing volume group.

lvdisplay — Display attributes of a logical volume.

lvextend — Extend the size of a logical volume.

lvmchange — Change attributes of the logical volume manager.

lvmdiskscan — Scan for all devices visible to LVM2.

lvmdump — Create lvm2 information dumps for diagnostic purposes.

lvreduce — Reduce the size of a logical volume.

lvremove — Remove a logical volume.

lvrename — Rename a logical volume.

lvresize — Resize a logical volume.

lvs — Report information about logical volumes.

lvscan — Scan (all disks) for logical volumes.

The following commands are not implemented in LVM2 but might be in the
future: lvmsadc, lvmsar, pvdata.

OPTIONS

The following options are available for many of the commands. They are
implemented generically and documented here rather than repeated on
individual manual pages.

-h | --help — Display the help text.

--version — Display version information.

-v | --verbose — Set verbose level.
Repeat from 1 to 3 times to increase the detail of messages sent
to stdout and stderr. Overrides config file setting.

-d | --debug — Set debug level.
Repeat from 1 to 6 times to increase the detail of messages sent
to the log file and/or syslog (if configured). Overrides config
file setting.

--quiet — Suppress output and log messages.
Overrides -d and -v.

-t | --test — Run in test mode.
Commands will not update metadata. This is implemented by dis‐
abling all metadata writing but nevertheless returning success
to the calling function. This may lead to unusual error mes‐
sages in multi-stage operations if a tool relies on reading back
metadata it believes has changed but hasn’t.

--driverloaded { y | n }
Whether or not the device-mapper kernel driver is loaded. If
you set this to n, no attempt will be made to contact the
driver.

-A | --autobackup { y | n }
Whether or not to metadata should be backed up automatically
after a change. You are strongly advised not to disable this!
See vgcfgbackup (8).

-P | --partial
When set, the tools will do their best to provide access to vol‐
ume groups that are only partially available. Where part of a
logical volume is missing, /dev/ioerror will be substituted, and
you could use dmsetup (8) to set this up to return I/O errors
when accessed, or create it as a large block device of nulls.
Metadata may not be changed with this option. To insert a
replacement physical volume of the same or large size use pvcre‐
ate -u to set the uuid to match the original followed by vgcf‐
grestore (8).

-M | --metadatatype type
Specifies which type of on-disk metadata to use, such as lvm1 or
lvm2, which can be abbreviated to 1 or 2 respectively. The
default (lvm2) can be changed by setting format in the global
section of the config file.

--ignorelockingfailure
This lets you proceed with read-only metadata operations such as
lvchange -ay and vgchange -ay even if the locking module fails.
One use for this is in a system init script if the lock direc‐
tory is mounted read-only when the script runs.

--addtag tag
Add the tag tag to a PV, VG or LV. A tag is a word that can be
used to group LVM2 objects of the same type together. Tags can
be given on the command line in place of PV, VG or LV arguments.
Tags should be prefixed with @ to avoid ambiguity. Each tag is
expanded by replacing it with all objects possessing that tag
which are of the type expected by its position on the command
line. PVs can only possess tags while they are part of a Volume
Group: PV tags are discarded if the PV is removed from the VG.
As an example, you could tag some LVs as database and others as
userdata and then activate the database ones with lvchange -ay
@database. Objects can possess multiple tags simultaneously.
Only the new LVM2 metadata format supports tagging: objects
using the LVM1 metadata format cannot be tagged because the on-
disk format does not support it. Snapshots cannot be tagged.
Characters allowed in tags are: A-Z a-z 0-9 _ + . -

--deltag tag
Delete the tag tag from a PV, VG or LV, if it’s present.

--alloc AllocationPolicy
The allocation policy to use: contiguous, cling, normal, any‐
where or inherit. When a command needs to allocate physical
extents from the volume group, the allocation policy controls
how they are chosen. Each volume group and logical volume has
an allocation policy. The default for a volume group is normal
which applies common-sense rules such as not placing parallel
stripes on the same physical volume. The default for a logical
volume is inherit which applies the same policy as for the vol‐
ume group. These policies can be changed using lvchange (8) and
vgchange (8) or over-ridden on the command line of any command
that performs allocation. The contiguous policy requires that
new extents be placed adjacent to existing extents. The cling
policy places new extents on the same physical volume as exist‐
ing extents in the same stripe of the Logical Volume. If there
are sufficient free extents to satisfy an allocation request but
normal doesn’t use them, anywhere will - even if that reduces
performance by placing two stripes on the same physical volume.

N.B. The policies described above are not implemented fully yet.
In particular, contiguous free space cannot be broken up to sat‐
isfy allocation attempts.

ENVIRONMENT VARIABLES

LVM_SYSTEM_DIR
Directory containing lvm.conf and other LVM system files.
Defaults to "/etc/lvm".

HOME Directory containing .lvm_history if the internal readline shell
is invoked.

LVM_VG_NAME
The volume group name that is assumed for any reference to a
logical volume that doesn’t specify a path. Not set by default.

VALID NAMES

The following characters are valid for VG and LV names: a-z A-Z 0-9 + _
. -

VG and LV names cannot begin with a hyphen. There are also various
reserved names that are used internally by lvm that can not be used as
LV or VG names. A VG cannot be called anything that exists in /dev/ at
the time of creation, nor can it be called ’.’ or ’..’. A LV cannot be
called ’.’ ’..’ ’snapshot’ or ’pvmove’. The LV name may also not con‐
tain the strings ’_mlog’ or ’_mimage’

DIAGNOSTICS

All tools return a status code of zero on success or non-zero on fail‐
ure.

FILES

/etc/lvm/lvm.conf
$HOME/.lvm_history

SEE ALSO

clvmd(8), lvchange(8), lvcreate(8), lvdisplay(8), lvextend(8), lvm‐
change(8), lvmdiskscan(8), lvreduce(8), lvremove(8), lvrename(8), lvre‐
size(8), lvs(8), lvscan(8), pvchange(8), pvck(8), pvcreate(8), pvdis‐
play(8), pvmove(8), pvremove(8), pvs(8), pvscan(8), vgcfgbackup(8),
vgchange(8), vgck(8), vgconvert(8), vgcreate(8), vgdisplay(8), vgex‐
tend(8), vgimport(8), vgmerge(8), vgmknodes(8), vgreduce(8), vgre‐
move(8), vgrename(8), vgs(8), vgscan(8), vgsplit(8), readline(3),
lvm.conf(5)

lvm commands

Initializing disks or disk partitions

To use LVM, partitions and whole disks must first be converted into physical volumes (PVs) using the command. For example, to convert pvcreate/dev/hda and /dev/hdb into PVs use the following commands:

pvcreate /dev/hda
pvcreate /dev/hdb

If a Linux partition is to be converted make sure that it is given partition type 0x8E using fdisk, then use pvcreate:

pvcreate /dev/hda1

Creating a volume group

Once you have one or more physical volumes created, you can create a volume group from these PVs using the vgcreate command. The following command:

vgcreate  volume_group_one /dev/hda /dev/hdb

creates a new VG called volume_group_one with two disks, /dev/hda and /dev/hdb, and 4 MB PEs. If both /dev/hda and /dev/hdb are 128 GB in size, then the VG volume_group_one will have a total of 2**16 physical extents that can be allocated to logical volumes.

Additional PVs can be added to this volume group using the vgextend command. The following commands convert /dev/hdc into a PV and then adds that PV to volume_group_one:

pvcreate /dev/hdc
vgextend volume_group_one /dev/hdc

This same PV can be removed from volume_group_one by the vgreduce command:

vgreduce volume_group_one /dev/hdc

Note that any logical volumes using physical extents from PV /dev/hdc will be removed as well. This raises the issue of how we create an LV within a volume group in the first place.

Creating a logical volume

We use the lvcreate command to create a new logical volume using the free physical extents in the VG pool. Continuing our example using VG volume_group_one (with two PVs /dev/hda and /dev/hdb and a total capacity of 256 GB), we could allocate nearly all the PEs in the volume group to a single linear LV called logical_volume_one with the following LVM command:

lvcreate -n logical_volume_one   --size 255G volume_group_one 

Instead of specifying the LV size in GB we could also specify it in terms of logical extents. First we use vgdisplay to determine the number of PEs in the volume_group_one:

vgdisplay volume_group_one | grep "Total PE"

which returns

Total PE   65536

Then the following lvcreate command will create a logical volume with 65536 logical extents and fill the volume group completely:

lvcreate -n logical_volume_one  -l 65536 volume_group_one

To create a 1500MB linear LV named logical_volume_one and its block device special file /dev/volume_group_one/logical_volume_one use the following command:

lvcreate -L1500 -n logical_volume_one volume_group_one

The lvcreate command uses linear mappings by default.

Striped mappings can also be created with lvcreate. For example, to create a 255 GB large logical volume with two stripes and stripe size of 4 KB the following command can be used:

lvcreate -i2 -I4 --size 255G -n logical_volume_one_striped volume_group_one

It is possible to allocate a logical volume from a specific physical volume in the VG by specifying the PV or PVs at the end of the lvcreate command. If you want the logical volume to be allocated from a specific physical volume in the volume group, specify the PV or PVs at the end of the lvcreate command line. For example, this command:

lvcreate -i2 -I4 -L128G -n logical_volume_one_striped volume_group_one /dev/hda /dev/hdb 

creates a striped LV named logical_volume_one that is striped across two PVs (/dev/hda and /dev/hdb) with stripe size 4 KB and 128 GB in size.

An LV can be removed from a VG through the lvremove command, but first the LV must be unmounted:

umount /dev/volume_group_one/logical_volume_one
lvremove /dev/volume_group_one/logical_volume_one

Note that LVM volume groups and underlying logical volumes are included in the device special file directory tree in the /dev directory with the following layout:

/dev// 
so that if we had two volume groups myvg1 and myvg2 and each with three logical volumes named lv01, lv02, lv03, six device special files would be created:
/dev/myvg1/lv01
/dev/myvg1/lv02
/dev/myvg1/lv03
/dev/myvg2/lv01
/dev/myvg2/lv02
/dev/myvg2/lv03

Extending a logical volume

An LV can be extended by using the lvextend command. You can specify either an absolute size for the extended LV or how much additional storage you want to add to the LVM. For example:

lvextend -L120G /dev/myvg/homevol

will extend LV /dev/myvg/homevol to 12 GB, while

lvextend -L+10G /dev/myvg/homevol

will extend LV /dev/myvg/homevol by an additional 10 GB. Once a logical volume has been extended, the underlying file system can be expanded to exploit the additional storage now available on the LV. With Red Hat Enterprise Linux 4, it is possible to expand both the ext3fs and GFS file systems online, without bringing the system down. (The ext3 file system can be shrunk or expanded offline using the ext2resize command.) To resize ext3fs, the following command

ext2online /dev/myvg/homevol

will extend the ext3 file system to completely fill the LV, /dev/myvg/homevol, on which it resides.

The file system specified by device (partition, loop device, or logical volume) or mount point must currently be mounted, and it will be enlarged to fill the device, by default. If an optional size parameter is specified, then this size will be used instead.

Differences between LVM1 and LVM2

The new release of LVM, LVM 2, is available only on Red Hat Enterprise Linux 4 and later kernels. It is upwardly compatible with LVM 1 and retains the same command line interface structure. However it uses a new, more scalable and resilient metadata structure that allows for transactional metadata updates (that allow quick recovery after server failures), very large numbers of devices, and clustering. For Enterprise Linux servers deployed in mission-critical environments that require high availability, LVM2 is the right choice for Linux volume management. Table 1. A comparison of LVM 1 and LVM 2 summarizes the differences between LVM1 and LVM2 in features, kernel support, and other areas.

Features LVM1 LVM2
RHEL AS 2.1 support No No
RHEL 3 support Yes No
RHEL 4 support No Yes
Transactional metadata for fast recovery No Yes
Shared volume mounts with GFS No Yes
Cluster Suite failover supported Yes Yes
Striped volume expansion No Yes
Max number PVs, LVs 256 PVs, 256 LVs 2**32 PVs, 2**32 LVs
Max device size 2 Terabytes 8 Exabytes (64-bit CPUs)
Volume mirroring support No Yes, in Fall 2005
Table 1. A comparison of LVM 1 and LVM 2

lvm -help

dumpconfig- Dump active configuration
formats- List available metadata formats
help--Display help for commands
lvchange- Change the attributes of logical volume(s)
lvconvert- Change logical volume layout
lvcreate- Create a logical volume
lvdisplay- Display information about a logical volume
lvextend- Add space to a logical volume
lvmchange- With the device mapper, this is obsolete and does nothing.
lvmdiskscan-List devices that may be used as physical volumes
lvmsadc- Collect activity data
lvmsar- Create activity report
lvreduce- Reduce the size of a logical volume
lvremove- Remove logical volume(s) from the system
lvrename- Rename a logical volume
lvresize- Resize a logical volume
lvs-- Display information about logical volumes
lvscan- List all logical volumes in all volume groups
pvchange- Change attributes of physical volume(s)
pvresize- Resize physical volume(s)
pvck--Check the consistency of physical volume(s)
pvcreate- Initialize physical volume(s) for use by LVM
pvdata- Display the on-disk metadata for physical volume(s)
pvdisplay- Display various attributes of physical volume(s)
pvmove- Move extents from one physical volume to another
pvremove- Remove LVM label(s) from physical volume(s)
pvs-- Display information about physical volumes
pvscan- List all physical volumes
segtypes- List available segment types
vgcfgbackup-Backup volume group configuration(s)
vgcfgrestore Restore volume group configuration
vgchange- Change volume group attributes
vgck--Check the consistency of volume group(s)
vgconvert- Change volume group metadata format
vgcreate- Create a volume group
vgdisplay- Display volume group information
vgexport- Unregister volume group(s) from the system
vgextend- Add physical volumes to a volume group
vgimport- Register exported volume group with system
vgmerge- Merge volume groups
vgmknodes- Create the special files for volume group devices in /dev
vgreduce- Remove physical volume(s) from a volume group
vgremove- Remove volume group(s)
vgrename- Rename a volume group
vgs-- Display information about volume groups
vgscan- Search for all volume groups
vgsplit- Move physical volumes into a new or existing volume group
version- Display software and driver version information


cryptsetup-luks on fedora

Take a Fedora Core 5 system and encrypt (using dm-crypt and LUKS) the partition that gets mounted on /home.

Note that /home needs to be on its own partition, not on the / partition. Also, in words similar to those from night-shade, I have tested this with LVM2 devices containing nothing important. It worked for me but you are advised to have current working backups if the data matters to you. Because we are dealing with the /home partition, these instructions will also explain how to ensure that the /home partition is mounted during a boot.

Step 0: Log on as root

Because you will need to unmount /home, you must log on as root rather than su to root from an unpriveledged user account.

-=Step 1: Backup /home Presumably you would like to return to the same Home environment that you started with before you encrypted your /home partition. Therefore, you need to backup the contents of /home. (Be aware that these instructions will not necessary restore your Home environment EXACTLY as it was before you encrypted /home. Please read all of these instructions before proceeding, so that you are sure that this solution will work for you.) In this HOWTO, we will assume there is only one unpriveledged user (jmaher) on the system, so only /home/jmaher needs to be backed up. One way to back up this folder is to use the following commands:

# mkdir /root/jmaher
# /bin/cp -a /home/jmaher/.* /root/jmaher

The -a option is for archiving files and directories. It uses recursion and preserves the permissions of the files and directories.

cryptsetup-luks on fedora: step 2, 3

cryptsetup-luks on fedora: step  2,  3
 
Remove the user whose Home directory we just backed up
We will be recreating the unpriviledged user (jmaher) after we have encrypted and re-mounted our /home directory, so we should clean things up first and remove that account:
# userdel jmaher
 
Step 3: Get the correct cryptsetup version
 
You need the version of cryptsetup with luks enabled. You can determine if the correct version of cryptsetup is install using the command:
 
# cryptsetup --help
 
You should see "cryptsetup-luks" displayed near the top of the output.
If you do not have cryptsetup, you can install it using yum (assuming yum has been properly configured):
 
# yum -y install cryptsetup-luks
 
The -y option will assume that the answer is yes to any question that would be presented during the execution of yum.

cryptsetup-luks on fedora: step 4

cryptsetup-luks on fedora: step 4

Step 4a: (Optional) Check the hard disk for errors and fill it with random data.

(Much of the following was shamelessly lifted from William Owen Smith's HOWTO: EncryptedDeviceUsingLUKS.)

It's probably a good idea to check for errors on the partition where /home will be mounted. Not only is this good practice, but modern hard disks contain a few 'spare' sectors, and if they detect errors in reading, they can silently replace the bad sector with a backup sector (this is invisible to the OS). So writing and reading the entire disk before you start should allow this to happen.

We will now use the information in /etc/fstab to determine the partition that is currently mounted on /home. (This partition may be represented as a logical volume, as it is in the example below.) You should see a line in /etc/fstab that is similar to the following:

/dev/vg0/home /home ext3 defaults 1 2

The above line indicates that partition /dev/vg0/home, which is actually a logical volume, is currently mounted on /home. We will use this partition as our physical device. We need to unmount this device in order the proceed with the next steps:

# umount /home

It's good to fill an encrypted disk with initial random data. This makes breaking the passphrase so much harder. The below method is sufficient for a casual attack but is not 'random enough' to defeat sophisticated cryptographers. If you need protection against sophisticated cryptanaylsis, use the '/dev/urandom' method shown in Step 4b.

The following command will perform a disk check and fill the disk with random data at the same time. Read the man page for more details on this command:

# /sbin/badblocks -c 10240 -s -w -t random -v /dev/vg0/home
(wait several hours...)
Checking for bad blocks in read-write mode
From block 0 to 295360984
done
Reading and comparing: done
Pass completed, 0 bad blocks found.
#

The -c option will test 10,240 blocks at a time. The -s option will show the progress of the scan by writing out the block numbers as they are checked. The -w option scans for bad blocks by writing some patterns (0xaa, 0x55, 0xff, 0x00) on every block of the device, reading every block and comparing the contents. The -t options specifies that each scanned block should be filled with a random bit pattern. The -v option indicates verbose mode. The physical device (logical volume) is /dev/vg0/home.

This will take some time. On William Owen Smith's USB-attached 300Gb disk it took around 8 hours. Phase 1 will write random data to the disk, phase 2 will read it back and verify it.

Step 4b: (Optional) Fill the disk with random data

If you didn't do Step 4a (or you left out the -t random option), do Step 4b. This will take a long time, because generating good quality random data is very CPU intensive. However, this method is 'more random' (and more secure) than the primitive random number generator included in 'badblocks', above.

One minor advantage to the method in Step xa above is that it has a progress indicator, while "dd" only shows its progress when a USR1 signal is sent to it ("kill -USR1 `pidof dd`").

# dd if=/dev/urandom of=/dev/vg0/home
(wait several hours...)

cryptsetup-luks on fedora: step 5, 6

cryptsetup-luks on fedora: step 5, 6

Step 5: Initialize a LUKS partition and set the initial key

This step establishes the mapping between physical partitions and logical partitions.

In this HOWTO, our physical partition will actually be a logical volume. By default, when installing Fedora Core 5, a volume group and logical volumes within the volume group are created. The volume group is called VolGroup00?, and the logical volumes are called LogVol00?, LogVol01?, etc, for each of the partitions. However, in this HOWTO, our volume group will be called vg0, and our logical volume that will eventually get mounted to /home will be called home. So, the full path of the physical partition that will be mounted on /home (when we are done) is /dev/vg0/home. (Your device path will likely be different, but you need to identify the device that is currently mounted to /home.)

With that said, let's use the following command to initialize a LUKS partition and set the initial key using a passphrase (note, this will wipe out all data on the /home partition):

# cryptsetup --verbose --verify-passphrase luksFormat /dev/vg0/home

WARNING!
========
This will overwrite data on /dev/vg0/home irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: (enter your passphrase, and write it down somewhere!)
Verify passphrase: (repeat passphrase)

Step 6: Create a mapping between physical and logical partitions

# cryptsetup luksOpen /dev/vg0/home home
Enter LUKS passphrase:
#

If all is well, you now have a special file called /dev/mapper/home. This is what you will mount on /home. Verify that the file was created:

# ls -l /dev/mapper/

total 0
crw------- 1 root root 10, 63 May 24 06:52 control
brw-rw---- 1 root disk 253, 4 May 24 10:54 home
brw-rw---- 1 root disk 253, 1 May 24 06:52 vg0-home
brw-rw---- 1 root disk 253, 0 May 24 10:53 vg0-root
brw-rw---- 1 root disk 253, 2 May 24 06:52 vg0-swap

Notice the other logical volumes (vg0-home, vg0-root, and vg0-swap) that were created when Fedora Core 5 was installed. (Note, the names of these volumes were changed by me during the installation. The were originally VolGroup00-LogVol00?, VolGroup00-LogVol01?, etc.) The fact that you are using logical volumes (like /dev/vg0/home) as physical devices can be confusing. It may help to remember that when we refer to physical devices we use devices located in the volume group directory (example: /dev/vg0), and when we refer to logical devices we use devices located in /dev/mapper (i.e., they have been mapped are are ready to use). (Okay, yes, it's confusing that the physical devices in /dev/vg0 are also listed as logical devices in /dev/mapper. Try to ignore them.)

cryptsetup-luks on fedora: step 7, 8

cryptsetup-luks on fedora: step 7, 8

Step 7: Create a filesystem on the new logical partition

For this HOWTO, we make an ext3 file system on /dev/mapper/home using the following commands:

# /sbin/mkfs.ext3 -j -m 1 /dev/mapper/home

(wait several minutes...)
mke2fs 1.35 (28-Feb-2004)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
36634624 inodes, 73258400 blocks
732584 blocks (1.00%) reserved for the super user
First data block=0
2236 block groups
32768 blocks per group, 32768 fragments per group
16384 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616

Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 39 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.
#

(Note, the above output was borrowed from William Owen Smith's HOWTO: "EncryptedDeviceUsingLUKS".)

Step 8: Mount the filesystem

Mount your new logical device /dev/mapper/home to /home.

# mount /dev/mapper/home /home

View the file system's disk usage to verify that it worked:

# df -h /dev/mapper/home
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/home 4.0G 80M 3.8G 3% /home

cryptsetup-luks on fedora: step 9, 10

cryptsetup-luks on fedora: step 9, 10

Step 9: Restore the user's Home directory

Re-create the unpriviledged user:

# useradd -m jmaher
# passwd jmaher
Changing password for user jmaher.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
#

The -m option create's the user's home directory using the files and directories in /etc/skel as a template.

Now we need to copy MOST of the user's backed-up files back to the user's Home directory. I say MOST because I have found that copying all of the files back to the user's Home directory will break the use of the Home directory for that user. I have not investigated this, so someone else may want to comment as to the reason for this. Basically, I found it safe to copy all non-hidden files and directories back to the /home/jmaher using the following command:

# /bin/cp -r --preserve /root/jmaher/* /home/jmaher

The -r options allows recursion of subdirectories to occur, and the --preserve option preserves permissions and ownership of the files and directories.

I would recommend selectively copying hidden files and directories for those applications you find most important. For example, I really wanted my Thunderbird, Firefox, and ssh settings to be restored, so I used the following commands:

# /bin/cp -r --preserve /root/jmaher/.thunderbird /home/jmaher
# /bin/cp -r --preserve /root/jmaher/.mozilla /home/jmaher
# /bin/cp -r --preserve /root/jmaher/.ssh /home/jmaher

If you had previously modified .bashrc, .bash_profile, or .bash_logout, then you may want to copy those files as well.

Don't reboot yet, but you should now be able to test your actions and log on as the unpriviledged user (jmaher) using the following command:

# su - jmaher

After confirming that you can log on as the unpriviledged user without errors indicating that the user's environment in /home is missing, log off as the unpriviledged user to return to root.

# logout

Step 10: Modify /etc/fstab

Some aspects of the boot sequence need to be changed, because the physical volume (/dev/vg0/home) that gets mounted to /home is encrypted and is no longer a recognizable file system as far as /bin/mount is concerned. Of course, if cryptsetup is used to open the device (using the command cryptsetup luksOpen /dev/vg0/home), then /bin/mount could see that the device has an ext3 file system, and the device can be mounted.

So here are the steps to do that.

Change the line in /etc/fstab that mounted the Home directory so that:
(a) the first field refers to /dev/mapper/home rather than /dev/vg0/home
(b) the fifth field no longer indicates that this device should be accessed by the dump command
(c) the six field no longer indicates that fsck should check this device at boot time.

In short, change the line that looks similar to this:

/dev/vg0/home /home ext3 defaults 1 2

and change it to this:

/dev/mapper/home /home ext3 defaults 0 0

cryptsetup-luks on fedora: step 11, 12 & 13

cryptsetup-luks on fedora: step 11, 12 & 13

Step 11: Create and modify luksopen script

Copy the wonderful script called luksopen (created by embro and modified by johnny) from http://www.saout.de/tikiwiki/tiki-index.php?page=luksopen, and paste it into a new file called /sbin/luksopen.

Modify the script as follows:

a. Change devArray variable from:
devArray=(/dev/hda7 /dev/hda10 /dev/hda11 /dev/hda13)
to:
devArray=(/dev/vg0/home)
(Remember, this is the physical device used for /home. Yours is probably different.)

b. Delete the entire mapArray variable line

c. Change mntArray variable from:
mntArray=(/tmp /mnt/bergen /mnt/trondheim /mnt/oslo)
to:
mntArray=(/home)

d. Replace the line that reads:
map=${mapArray[$i]}
with:
# assign last directory name of device name to $map variable
map_elements=`echo ${devArray[$i]} | sed -e 's/^\///' -e 's/\// /g'`
for e in $map_elements ; do map=$e ; done

e. Add ' answer' (no quotes) to the following line:
read -p "Next device in list is \"$dev\". Do you want to open and mount it? (y/N): "
so that it looks like this:
read -p "Next device in list is \"$dev\". Do you want to open and mount it? (y/N): " answer

f. Delete (or comment out) the three lines at the bottom of the script that immediately preceed the final 'done' command. So, if you choose to comment out those lines, they would look like this:
#if $j -le 0 || ! mount "/dev/mapper/$map" "$mnt" ; then
# echo "Failed to mount \"/dev/mapper/$map\" on \"$mnt\"" >&2
#fi

Step 12: Edit /etc/rc.d/rc.sysinit

During a boot, we now need to open (unlock) our encrypted partition (/dev/vg0/home) and map it to our logical volume (/dev/mapper/home) before the logical volume can be mounted on /home. Because we would like to have /home mounted during the boot (so we can log on as an unpriviledged user), we need to be prompted for the LUKS passphrase (established in Step 5) before any attempts are made to mount /dev/mapper/home to /home (as configured in /etc/fstab).

Now, one could assume that simply adding /sbin/luksopen to /etc/rc.d/rc.local would result in the necessary prompting for the LUKS passphrase; however, when booting to runlevel 5 I have experienced problems getting prompted. Therefore, modifying /etc/rc.d/rc.sysinit as follows will solve the prompting problem.

Modify /etc/rc.d/rc.sysinit to incude the following code . . .

# Run /sbin/luksopen to use cryptsetup to map /dev/vg0/home to /dev/mapper/home.
if -x /sbin/luksopen ; then
/sbin/luksopen
fi

. . . immediately before the code where /usr/bin/rhgb is called. In Fedora Core 5 you can place the above code immediately before the comment line that reads:

# Start the graphical boot, if necessary; /usr may not be mounted yet, so we
# may have to do this again after mounting

Step 13: REBOOT

What You Can Expect

The boot process will be essentially the same as before, but this time you will be prompted with the following text shortly after the boot begins:

Next device in list is /dev/vg0/home. Do you want to open and mount it? (y/N):

You need to type y <ENTER>, and you will then be prompted to enter your passphrase. If you enter your passphrase correctly, the device (/dev/vg0/home) that you encrypted and mapped in Steps 5 and 6 above will be mapped to /dev/mapper/home and mounted to /home. The boot process will complete, and you can log on as your unpriviledged user (jmaher).

(Written by John Maher, 24 May 2006)

cryptsetup-luks on fedora: 1 page

Take a Fedora Core 5 system and encrypt (using dm-crypt and LUKS) the partition that gets mounted on /home. Note that /home needs to be on its own partition, not on the / partition. Also, in words similar to those from night-shade, I have tested this with LVM2 devices containing nothing important. It worked for me but you are advised to have current working backups if the data matters to you. Because we are dealing with the /home partition, these instructions will also explain how to ensure that the /home partition is mounted during a boot.

Step 0: Log on as root

Because you will need to unmount /home, you must log on as root rather than su to root from an unpriveledged user account.

-=Step 1: Backup /home Presumably you would like to return to the same Home environment that you started with before you encrypted your /home partition. Therefore, you need to backup the contents of /home. (Be aware that these instructions will not necessary restore your Home environment EXACTLY as it was before you encrypted /home. Please read all of these instructions before proceeding, so that you are sure that this solution will work for you.) In this HOWTO, we will assume there is only one unpriveledged user (jmaher) on the system, so only /home/jmaher needs to be backed up. One way to back up this folder is to use the following commands:

# mkdir /root/jmaher
# /bin/cp -a /home/jmaher/.* /root/jmaher

The -a option is for archiving files and directories. It uses recursion and preserves the permissions of the files and directories.

Step 2: Remove the user whose Home directory we just backed up

We will be recreating the unpriviledged user (jmaher) after we have encrypted and re-mounted our /home directory, so we should clean things up first and remove that account:

# userdel jmaher

Step 3: Get the correct cryptsetup version

You need the version of cryptsetup with luks enabled. You can determine if the correct version of cryptsetup is install using the command:

# cryptsetup --help

You should see "cryptsetup-luks" displayed near the top of the output.

If you do not have cryptsetup, you can install it using yum (assuming yum has been properly configured):

# yum -y install cryptsetup-luks

The -y option will assume that the answer is yes to any question that would be presented during the execution of yum.

Step 4a: (Optional) Check the hard disk for errors and fill it with random data.

(Much of the following was shamelessly lifted from William Owen Smith's HOWTO: EncryptedDeviceUsingLUKS.)

It's probably a good idea to check for errors on the partition where /home will be mounted. Not only is this good practice, but modern hard disks contain a few 'spare' sectors, and if they detect errors in reading, they can silently replace the bad sector with a backup sector (this is invisible to the OS). So writing and reading the entire disk before you start should allow this to happen.

We will now use the information in /etc/fstab to determine the partition that is currently mounted on /home. (This partition may be represented as a logical volume, as it is in the example below.) You should see a line in /etc/fstab that is similar to the following:

/dev/vg0/home /home ext3 defaults 1 2

The above line indicates that partition /dev/vg0/home, which is actually a logical volume, is currently mounted on /home. We will use this partition as our physical device. We need to unmount this device in order the proceed with the next steps:

# umount /home

It's good to fill an encrypted disk with initial random data. This makes breaking the passphrase so much harder. The below method is sufficient for a casual attack but is not 'random enough' to defeat sophisticated cryptographers. If you need protection against sophisticated cryptanaylsis, use the '/dev/urandom' method shown in Step 4b.

The following command will perform a disk check and fill the disk with random data at the same time. Read the man page for more details on this command:

# /sbin/badblocks -c 10240 -s -w -t random -v /dev/vg0/home
(wait several hours...)
Checking for bad blocks in read-write mode
From block 0 to 295360984
done
Reading and comparing: done
Pass completed, 0 bad blocks found.
#

The -c option will test 10,240 blocks at a time. The -s option will show the progress of the scan by writing out the block numbers as they are checked. The -w option scans for bad blocks by writing some patterns (0xaa, 0x55, 0xff, 0x00) on every block of the device, reading every block and comparing the contents. The -t options specifies that each scanned block should be filled with a random bit pattern. The -v option indicates verbose mode. The physical device (logical volume) is /dev/vg0/home.

This will take some time. On William Owen Smith's USB-attached 300Gb disk it took around 8 hours. Phase 1 will write random data to the disk, phase 2 will read it back and verify it.

Step 4b: (Optional) Fill the disk with random data

If you didn't do Step 4a (or you left out the -t random option), do Step 4b. This will take a long time, because generating good quality random data is very CPU intensive. However, this method is 'more random' (and more secure) than the primitive random number generator included in 'badblocks', above.

One minor advantage to the method in Step xa above is that it has a progress indicator, while "dd" only shows its progress when a USR1 signal is sent to it ("kill -USR1 `pidof dd`").

# dd if=/dev/urandom of=/dev/vg0/home
(wait several hours...)

Step 5: Initialize a LUKS partition and set the initial key

This step establishes the mapping between physical partitions and logical partitions.

In this HOWTO, our physical partition will actually be a logical volume. By default, when installing Fedora Core 5, a volume group and logical volumes within the volume group are created. The volume group is called VolGroup00?, and the logical volumes are called LogVol00?, LogVol01?, etc, for each of the partitions. However, in this HOWTO, our volume group will be called vg0, and our logical volume that will eventually get mounted to /home will be called home. So, the full path of the physical partition that will be mounted on /home (when we are done) is /dev/vg0/home. (Your device path will likely be different, but you need to identify the device that is currently mounted to /home.)

With that said, let's use the following command to initialize a LUKS partition and set the initial key using a passphrase (note, this will wipe out all data on the /home partition):

# cryptsetup --verbose --verify-passphrase luksFormat /dev/vg0/home

WARNING!
========
This will overwrite data on /dev/vg0/home irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: (enter your passphrase, and write it down somewhere!)
Verify passphrase: (repeat passphrase)

Step 6: Create a mapping between physical and logical partitions

# cryptsetup luksOpen /dev/vg0/home home
Enter LUKS passphrase:
#

If all is well, you now have a special file called /dev/mapper/home. This is what you will mount on /home. Verify that the file was created:

# ls -l /dev/mapper/

total 0
crw------- 1 root root 10, 63 May 24 06:52 control
brw-rw---- 1 root disk 253, 4 May 24 10:54 home
brw-rw---- 1 root disk 253, 1 May 24 06:52 vg0-home
brw-rw---- 1 root disk 253, 0 May 24 10:53 vg0-root
brw-rw---- 1 root disk 253, 2 May 24 06:52 vg0-swap

Notice the other logical volumes (vg0-home, vg0-root, and vg0-swap) that were created when Fedora Core 5 was installed. (Note, the names of these volumes were changed by me during the installation. The were originally VolGroup00-LogVol00?, VolGroup00-LogVol01?, etc.) The fact that you are using logical volumes (like /dev/vg0/home) as physical devices can be confusing. It may help to remember that when we refer to physical devices we use devices located in the volume group directory (example: /dev/vg0), and when we refer to logical devices we use devices located in /dev/mapper (i.e., they have been mapped are are ready to use). (Okay, yes, it's confusing that the physical devices in /dev/vg0 are also listed as logical devices in /dev/mapper. Try to ignore them.)

Step 7: Create a filesystem on the new logical partition

For this HOWTO, we make an ext3 file system on /dev/mapper/home using the following commands:

# /sbin/mkfs.ext3 -j -m 1 /dev/mapper/home

(wait several minutes...)
mke2fs 1.35 (28-Feb-2004)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
36634624 inodes, 73258400 blocks
732584 blocks (1.00%) reserved for the super user
First data block=0
2236 block groups
32768 blocks per group, 32768 fragments per group
16384 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616

Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 39 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.
#

(Note, the above output was borrowed from William Owen Smith's HOWTO: "EncryptedDeviceUsingLUKS".)

Step 8: Mount the filesystem

Mount your new logical device /dev/mapper/home to /home.

# mount /dev/mapper/home /home

View the file system's disk usage to verify that it worked:

# df -h /dev/mapper/home
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/home 4.0G 80M 3.8G 3% /home

Step 9: Restore the user's Home directory

Re-create the unpriviledged user:

# useradd -m jmaher
# passwd jmaher
Changing password for user jmaher.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
#

The -m option create's the user's home directory using the files and directories in /etc/skel as a template.

Now we need to copy MOST of the user's backed-up files back to the user's Home directory. I say MOST because I have found that copying all of the files back to the user's Home directory will break the use of the Home directory for that user. I have not investigated this, so someone else may want to comment as to the reason for this. Basically, I found it safe to copy all non-hidden files and directories back to the /home/jmaher using the following command:

# /bin/cp -r --preserve /root/jmaher/* /home/jmaher

The -r options allows recursion of subdirectories to occur, and the --preserve option preserves permissions and ownership of the files and directories.

I would recommend selectively copying hidden files and directories for those applications you find most important. For example, I really wanted my Thunderbird, Firefox, and ssh settings to be restored, so I used the following commands:

# /bin/cp -r --preserve /root/jmaher/.thunderbird /home/jmaher
# /bin/cp -r --preserve /root/jmaher/.mozilla /home/jmaher
# /bin/cp -r --preserve /root/jmaher/.ssh /home/jmaher

If you had previously modified .bashrc, .bash_profile, or .bash_logout, then you may want to copy those files as well.

Don't reboot yet, but you should now be able to test your actions and log on as the unpriviledged user (jmaher) using the following command:

# su - jmaher

After confirming that you can log on as the unpriviledged user without errors indicating that the user's environment in /home is missing, log off as the unpriviledged user to return to root.

# logout

Step 10: Modify /etc/fstab

Some aspects of the boot sequence need to be changed, because the physical volume (/dev/vg0/home) that gets mounted to /home is encrypted and is no longer a recognizable file system as far as /bin/mount is concerned. Of course, if cryptsetup is used to open the device (using the command cryptsetup luksOpen /dev/vg0/home), then /bin/mount could see that the device has an ext3 file system, and the device can be mounted.

So here are the steps to do that.

Change the line in /etc/fstab that mounted the Home directory so that:
(a) the first field refers to /dev/mapper/home rather than /dev/vg0/home
(b) the fifth field no longer indicates that this device should be accessed by the dump command
(c) the six field no longer indicates that fsck should check this device at boot time.

In short, change the line that looks similar to this:

/dev/vg0/home /home ext3 defaults 1 2

and change it to this:

/dev/mapper/home /home ext3 defaults 0 0

Step 11: Create and modify luksopen script

Copy the wonderful script called luksopen (created by embro and modified by johnny) from http://www.saout.de/tikiwiki/tiki-index.php?page=luksopen, and paste it into a new file called /sbin/luksopen.

Modify the script as follows:

a. Change devArray variable from:
devArray=(/dev/hda7 /dev/hda10 /dev/hda11 /dev/hda13)
to:
devArray=(/dev/vg0/home)
(Remember, this is the physical device used for /home. Yours is probably different.)

b. Delete the entire mapArray variable line

c. Change mntArray variable from:
mntArray=(/tmp /mnt/bergen /mnt/trondheim /mnt/oslo)
to:
mntArray=(/home)

d. Replace the line that reads:
map=${mapArray[$i]}
with:
# assign last directory name of device name to $map variable
map_elements=`echo ${devArray[$i]} | sed -e 's/^\///' -e 's/\// /g'`
for e in $map_elements ; do map=$e ; done

e. Add ' answer' (no quotes) to the following line:
read -p "Next device in list is \"$dev\". Do you want to open and mount it? (y/N): "
so that it looks like this:
read -p "Next device in list is \"$dev\". Do you want to open and mount it? (y/N): " answer

f. Delete (or comment out) the three lines at the bottom of the script that immediately preceed the final 'done' command. So, if you choose to comment out those lines, they would look like this:
#if $j -le 0 || ! mount "/dev/mapper/$map" "$mnt" ; then
# echo "Failed to mount \"/dev/mapper/$map\" on \"$mnt\"" >&2
#fi

Step 12: Edit /etc/rc.d/rc.sysinit

During a boot, we now need to open (unlock) our encrypted partition (/dev/vg0/home) and map it to our logical volume (/dev/mapper/home) before the logical volume can be mounted on /home. Because we would like to have /home mounted during the boot (so we can log on as an unpriviledged user), we need to be prompted for the LUKS passphrase (established in Step 5) before any attempts are made to mount /dev/mapper/home to /home (as configured in /etc/fstab).

Now, one could assume that simply adding /sbin/luksopen to /etc/rc.d/rc.local would result in the necessary prompting for the LUKS passphrase; however, when booting to runlevel 5 I have experienced problems getting prompted. Therefore, modifying /etc/rc.d/rc.sysinit as follows will solve the prompting problem.

Modify /etc/rc.d/rc.sysinit to incude the following code . . .

# Run /sbin/luksopen to use cryptsetup to map /dev/vg0/home to /dev/mapper/home.
if -x /sbin/luksopen ; then
/sbin/luksopen
fi

. . . immediately before the code where /usr/bin/rhgb is called. In Fedora Core 5 you can place the above code immediately before the comment line that reads:

# Start the graphical boot, if necessary; /usr may not be mounted yet, so we
# may have to do this again after mounting

Step 13: REBOOT

What You Can Expect

The boot process will be essentially the same as before, but this time you will be prompted with the following text shortly after the boot begins:

Next device in list is /dev/vg0/home. Do you want to open and mount it? (y/N):

You need to type y <ENTER>, and you will then be prompted to enter your passphrase. If you enter your passphrase correctly, the device (/dev/vg0/home) that you encrypted and mapped in Steps 5 and 6 above will be mapped to /dev/mapper/home and mounted to /home. The boot process will complete, and you can log on as your unpriviledged user (jmaher).

(Written by John Maher, 24 May 2006)

mail servers

Anatomy of Postfix

by Ralf Hildebrandt and Patrick Koetter in Software

Developed with security and speed in mind, Postfix has become a popular alternative to Sendmail. The Book of Postfix published by No Starch Press is a complete guide to Postfix whether used by the home user, as a mailrelay or virus scanning gateway, or as a company mailserver. Practical examples show how to deal with daily challenges like protecting mail users from SPAM and viruses, managing multi

Please note that this book is based on is based on Postfix 2.1, later versions of Postfix have new daemons not discussed in the book.

This chapter describes how Postfix works, what each piece of the system does, and how these components relate to each other. After going through this material, you should have an understanding of Postfix as a whole, so that you can focus on individual goals.

Postfix consists of a small number of programs that interact with user processes (sendmail, postqueue, postsuper, and so on) and a larger number of programs that run in the background. Only the programs that run in the background are controlled by the master daemon. The master daemon's job is to determine what work there is to do and dispatch the appropriate program to do the work. This modular design allows for a higher level of security because each program runs with the lowest privilege set needed to fulfill its task.

You can think of the whole Postfix system as a router. This may sound strange at first, but remember that a router's job is to look at an IP packet, determine the destination IP address (and possibly the source), and then choose the right interface to route the packet toward its destination. Postfix does the same thing with mail (see Figure 5-1), looking at the destination of a message (the envelope recipient) and the source (the envelope sender) to determine the application that will move the message closer to its final destination.

Postfix works like a router

Now let's look more closely at the system. A real router usually accepts IP packets from multiple interfaces, routing them back out through the interfaces. The same is true for Postfix; it accepts messages from multiple sources and then passes the mail on to multiple destinations. A message's origin may be the local sendmail binary or an SMTP or QMQP connection. The destination can be a local mailbox, outgoing SMTP or LMTP, a pipe into a program, and more. Figure 5-2 shows this view of Postfix.

A Postfix "router" accepts and establishes all kinds of connections

The origin and destination of a message seem clear enough, but how does Postfix pick a delivery method given a destination? A router uses routing tables that match IP addresses to networks to determine a path. Postfix does the same thing with email addresses.

In Postfix, lookup tables are called maps. Postfix uses maps not only to find out where to send mail, but also to impose restrictions on clients, senders, and recipients, and to check certain patterns in email content. Figure 5-3 shows where the maps--to name but a few, aliases, virtual, and transport are shown--fit in.

Maps are the lookup tables of the Postfix "router"

Postfix Daemons

Figure 5-4 shows an overview of the Postfix daemons and how they fit together.

Figure 5-4: The relationships between the Postfix daemons

Note:

Postfix is constantly under development. The following list of daemons is based on Postfix 2.1.

master

The master daemon is the supervisor of Postfix, and it oversees all other Postfix daemons. The master waits for incoming jobs to be delegated to subordinate daemons. If there is a lot of work to do, the master can invoke multiple instances of a daemon. You can configure the number of simultaneous daemon instances, how often Postfix can reuse them, and a period of inactivity that should elapse before stopping an instance.

If you have ever worked with the inetd server on a Unix machine, you will find many similarities between it and the master daemon.

bounce and defer

A mail transfer agent must notify the sender about undeliverable mail. In Postfix, the bounce and defer daemons handle this task, which is triggered by the queue manager (qmgr). Specifically, the two event types that cause sender notices are unrecoverable errors and a destination that is unreachable for an extended period of time. The latter case results in a delay warning.

error

The error daemon is a mail delivery agent like local or smtp. It is a delivery agent that always causes mail to be bounced. Usually you don't use it unless you configure a domain as undeliverable by directing mail to the error delivery agent. If a mail is sent to the error daemon it will inform the bounce daemon to record that a recipient was undeliverable.

trivial-rewrite

The trivial-rewrite daemon acts upon request by the cleanup daemon in order to rewrite nonstandard addresses into the standard user@fqdn form.

This daemon also resolves destinations upon request from the queue manager (qmgr). By default, trivial-rewrite distinguishes only between local and remote destinations.

showq

The showq daemon lists the Postfix mail queue, and it is the program behind the mailq (sendmail -bp) command. This daemon is necessary because the Postfix queue is not world-readable; a non-setuid user program cannot list the queue (and Postfix binaries are not setuid).

flush

The flush daemon attempts to clear the mail queue of pending and deferred messages. By using a per-destination list of queued mail, it improves the performance of the SMTP Extended Turn (ETRN) request and its command-line equivalent, sendmail -qR destination. You can maintain the list of destinations with the fast_flush_domains parameter in the main.cf file.

qmgr

The qmgr daemon manages the Postfix queues; it is the heart of the Postfix mail system. It distributes delivery tasks to the local, smtp, lmtp, and pipe daemons. After delegating a job, it submits queue file path-name information, the message sender address, the target host (if the destination is remote), and one or more message-recipient addresses to the daemon it delegated the delivery task to.

The qmgr design is a good example of how Postfix handles jobs to avoid resource starving and to maintain stability. Two things stand out:

  • qmgr maintains a small active queue, with just a few messages pending for delivery. This queue effectively acts as a limited window for the potentially larger incoming and deferred queues, and it prevents qmgr from running out of memory under a heavy load.

  • If Postfix cannot immediately deliver a message, qmgr moves the message to the deferred queue. Keeping temporarily undeliverable messages in a separate queue ensures that a large mail backlog does not slow down normal queue access.

qmgr uses the bounce and error daemons to bounce mail for recipients listed in the relocated table that contains contact information for users or domains that no longer exist on the system.

proxymap

Postfix client processes can get read-only access to maps through the proxymap daemon. By sharing a single open map among many Postfix daemons, proxymap circumvents chroot restrictions and reduces the number of open lookup tables.

spawn

The spawn process creates non-Postfix processes on request. It listens on a TCP port, Unix domain socket, or FIFO connected to the standard input, output, and error streams. The only use for spawn discussed in this book is for the Postfix external content filtering system in Chapter 13.

local

As the name suggests, the local daemon is responsible for local mailbox delivery. The Postfix local daemon can write to mailboxes in the mbox and Maildir formats. In addition, local can access data in Sendmail-style alias databases and user .forward files.

Note: These capabilities make local the counterpart to the Sendmail mail posting agent, and they both maintain the same user interface.

As an alternative, local can delegate mailbox delivery to a local delivery agent (LDA) that provides more advanced features, such as filtering. Two very popular LDAs are procmail (www.procmail.org) and maildrop (www.flounder.net/~mrsam/maildrop).

Postfix can run multiple instances of local.

virtual

The virtual daemon, sometimes called the virtual delivery agent, is a stripped-down version of local that delivers exclusively to mailboxes. It is the most secure Postfix delivery agent; it does not perform alias and .forward file expansions.

This delivery agent can deliver mail for multiple domains, making it especially suitable for hosting several small domains on a single machine (a so-called POP toaster) without the need for real system or shell accounts.

smtp

The smtp client is the Postfix client program that transports outbound messages to remote destinations. It looks up destination mail exchangers, sorts the list by preference, and tries each address until it finds a server that responds. A busy Postfix system typically has several smtp daemons running at once.

lmtp

The lmtp client communicates with local and remote mailbox servers with the Local Mail Delivery Protocol (LMTP) defined in RFC 2033 (ftp.rfc-editor.org/in-notes/rfc2033.txt). It is often used with the Cyrus IMAP server (asg.web.cmu.edu/cyrus/imapd).

The advantages of a setup using Postfix's lmtp client are that Postfix handles all of the queue management and one Postfix machine can feed multiple mailbox servers (which need to have an LMTP daemon) over LMTP. The opposite is also true: several Postfix machines can feed one mailbox server through lmtp. These mailbox server(s) could, for example, be running Cyrus IMAP.

pipe

The pipe mailer client is the outbound interface to other mail transport mechanisms. It invokes programs with parameters and pipes the message body into their standard input.

pickup

The pickup daemon picks up messages put into the maildrop queue by the local sendmail user client program. After performing a few sanity checks, pickup passes messages to the cleanup daemon.

smtpd

The smtpd daemon handles communication with networked mail clients that deliver messages to Postfix through SMTP. smtpd performs a number of checks that protect the rest of the Postfix system, and it can be configured to implement unsolicited commercial email (UCE) controls (local or network-based blacklists, DNS lookups, other client requests, and so on).

After accepting a message, smtpd hands the message down to cleanup

cleanup

The cleanup daemon is the final processing stage for new messages. It adds any required missing headers, arranges for address rewriting, and (optionally) extracts recipient addresses from message headers. The cleanup daemon inserts the result into the incoming queue and then notifies the queue manager that new mail has arrived.

sendmail

sendmail is a Postfix command that replaces and emulates Eric Allman's MTA Sendmail. Its purpose is to provide a Sendmail-compatible interface to applications that will only invoke /usr/sbin/sendmail. It interacts with the postdrop binary to put mail into the maildrop queue for pickup.

Note: sendmail is the slowest way to inject mail into the Postfix queue system. If you need to send a large amount of mail at once, use SMTP instead.

qmqpd

The Postfix QMQP server implements the Quick Mail Queuing Protocol (QMQP; see http://cr.yp.to/proto/qmqp.html) to make Postfix compatible with qmail and the ezmlm list manager.

anvil

The Postfix anvil is a preliminary defense against SMTP clients and denial-of-service attacks that swamp the SMTP server with too many simultaneous or successive connection attempts. It comes with a whitelist capability for disabling restrictions for authorized clients. anvil is not included with Postfix 2.1, but it is available in the Postfix 2.2 experimental release. anvil will stay experimental until there is enough experience with Postfix rate limiting.

Postfix Queues

Postfix polls all queues in the directory specified by the queue_directory parameter in your main.cf file. The queue directory is usually /var/spool/postfix. Each queue has its own subdirectory with a name identifying the queue. All messages that Postfix handles stay in these directories until Postfix delivers them. You can determine the status of a message by its queue: incoming, maildrop, deferred, active, hold, or corrupt.

incoming

All new messages entering the Postfix queue system get sent to the incoming queue by the cleanup service. New queue files are created with the postfix user as the owner and an access mode of 0600. As soon as a queue file is ready for further processing, the cleanup service changes the queue file mode to 0700 and notifies the queue manager that new mail has arrived. The queue manager ignores incomplete queue files whose mode is 0600.

The queue manager scans the incoming queue when moving new messages into the active queue and makes sure that the active queue resource limits have not been exceeded. By default, the active queue has a maximum of 20,000 messages.

Caution: Once the active queue message limit is reached, the queue manager stops scanning the incoming and deferred queues.

maildrop

Messages submitted with the sendmail command that have not been sent to the primary Postfix queues by the pickup service await processing in the maildrop queue. You can add messages to the maildrop queue even when Postfix is not running; Postfix will look at them once it is started.

The single-threaded pickup service scans and drains the maildrop queue periodically, as well as upon notification from the postdrop program. The postdrop program is a setgid helper that allows the unprivileged sendmail program to inject mail into the maildrop queue and notify the pickup service of message arrival. (All messages that enter the main Postfix queues do so via the cleanup service.)

deferred

If a message still has recipients for which delivery failed for some transient reason, and the message has been delivered to all the recipients possible, Postfix places the message into the deferred queue.

The queue manager scans the deferred queue periodically to put deferred messages back into the active queue. The scan interval is specified with the queue_run_delay configuration parameter. If the deferred and incoming queue scans happen to take place at the same time, the queue manager alternates between the two queues on a per-message basis.

active

The active queue is somewhat analogous to an operating system's process run queue. Messages in the active queue are ready to be sent, but are not necessarily in the process of being sent.

The queue manager is a delivery agent scheduler that works to ensure fast and fair delivery of mail to all destinations within designated resource limits.

Note: Although most Postfix administrators think of the active queue as a directory on disk, the real active queue is a set of data structures in the memory of the queue manager process.

hold

The administrator can define smtpd access(5) policies and cleanup header and body checks (see Chapter 10) that cause messages to be automatically diverted from normal processing and placed indefinitely in the hold queue. Messages placed in the hold queue stay there until the administrator intervenes. No periodic delivery attempts are made for messages in the hold queue. You can run the postsuper command to manually put messages on hold or to release messages from the hold queue into the deferred queue.

Messages can potentially stay in the hold queue for a time that exceeds the queue file lifetime set by the maximal_queue_lifetime parameter (after which undelivered messages are bounced to the sender). If older messages need to be released from the hold queue, you can use postsuper -r to move them into the maildrop queue, so that the message gets a new timestamp and is given more than one opportunity to be delivered.

Note: The hold queue doesn't play much of a role in Postfix performance; monitoring of the hold queue is typically motivated by tracking spam and malware rather than by performance issues.

corrupt

The corrupt directory contains damaged queue files. Rather than discarding these, Postfix stores them here so that the (human) postmaster can inspect them using postcat.

Postfix logs a warning about any corrupt files upon startup.

Maps

Maps are files and databases that Postfix uses to look up information. Maps have many different purposes, but they all have one thing in common--a left-hand side (LHS, or key) and a right-hand side (RHS, or value).

Here are a few examples of keys and values:

Key Value
postmaster: john
postmaster@example.com john
192.168.254.12 REJECT
spammer@example.com REJECT
/^Subject: your account {25}[a-z]{8}/ REJECT Mimail Virus Detected

To use a map, you specify a key and get the associated value as a result.

Note: The keys and values here come from various files and would not make sense in one file. The preceding list is just an illustration to show that all map entries take the same basic form.

Map Types

Postfix can use many different kinds of maps. The formats available depend on the way Postfix was compiled on your particular system. To find out what formats your Postfix supports, run postconf -m on the command line. You should get a list of map types:

# postconf -m
btree
cdb
cidr
environ
hash
ldap
mysql
nis
pcre
proxy
regexp
sdbm
static
tcp
unix

Indexed Maps (hash, btree, dbm, and So On)

Indexed maps are binary databases built from regular text files with commands such as newaliases, postalias, and postmap. The binary maps have an indexed format so that Postfix can quickly retrieve the value associated with a key. As a further performance improvement, the Postfix daemons open these maps when starting up, and they do not re-read them unless they notice a change in the map files in the filesystem. To reload a map, a daemon exits and a new one is started by the master daemon.

Note:

If you have indexed maps that change frequently, the daemons using these maps will restart just as often. Under a heavy load, this can lead to performance problems.

The most common indexed maps are built from the aliases, virtual, transport, relocated, and sasl_passwd text files. You can identify a map file because its name is the original file with a suffix that also tells you the index format. For example, an aliases map file built with the postalias command is named aliases.db.

Note:

When you create a file in order to build an indexed map from it you don't have to put keys in a specific order. The conversion tools and programs that use indexed maps do not require a specific order for input. In fact, the process of conversion removes the ordering.

Postfix queries entries in a predefined order specified in the manual pages for the tables (access(5), transport(5), virtual(5), aliases(5) and canonical(5)). In other words, each map lookup actually consists of a series of single queries (derived from the original query) on single keys in the indexed map.

Linear Maps (PCRE, regexp, CIDR, and Flat Files)

Linear maps are regular text files. Postfix reads these files from top to bottom, making them different from indexed maps. This difference is quite important, because the first match in the file determines the action that Postfix will take. Postfix ignores any later entries, whether they match the query or not.

Consider the following regexp map, where a john.doe@example.com lookup returns OK, because the first line matches.

/john\.doe@example\.com/ OK
/example\.com/ REJECT

However, if you swap the lines in the regexp map, the other entry matches first, so the same john.doe@example.com lookup returns REJECT:

/example\.com/ REJECT
/john\.doe@example\.com/ OK

You do not need to convert linear maps to a binary form (in fact, you can't do it). The Postfix daemons read them at startup and do not notice any changes to the map until they are restarted. Typical Postfix linear maps include header_checks, body_checks, and mime_header_checks (see Chapter 9).

Caution:

As your linear maps grow, it takes longer for the Postfix daemons to process them. This is especially true with respect to body or header checks, because the cleanup daemon needs to check every line of the body (up to body_checks_size_limit) and headers against every line of the map.

This can cause a significant slowdown, especially if you have extensive *_checks parameters that use regexp or PCRE (Perl-compatible regular expression) type maps in order to prevent spam from entering the system. When this happens, it's usually time to hand complex spam filtering to an external application.

To make the Postfix daemons notice changes in linear maps, run postfix reload. If the timing is not critical, you can set the max_use parameter to define a time-to-live for daemons. As soon as a daemon has processed the number of tasks specified in that parameter, it quits and is restarted by master. Upon restart, it re-reads all required maps.

Databases (MySQL, PostgreSQL, LDAP)

Postfix treats a database just like an indexed map. The result of a database query is Match (along with the value returned by the query) or No match. The principal difference between a database map and an indexed map is that you do not need to restart a daemon when there is a change to the database. Postfix does not assume that the postmaster is the only person who can alter the database.

The drawback to this approach is that the database may not be able to handle the number of queries gracefully, because Postfix needs to perform at least three queries for each lookup in a map (see the "See How Postfix Queries Maps" section that follows). Under heavy load, the database backend could stop working, and your mail service would be vulnerable to a self-induced meltdown or a denial-of-service attack. This possibility should not prevent you from using database backends, but you should be aware of the risk.

Database lookups can become a problem for systems with a heavy load, but this isn't the only issue to consider--latency can be another problem. Database queries have a higher latency than indexed maps because Postfix must connect to the database backend, send the query, and then wait for the result. With an indexed map, Postfix has only to consult data that is already loaded in memory.

If your database becomes a bottleneck, and you do not have an excessively large map, you can insert a map between the database and Postfix. That is, you can create an indexed map from a complete database query, and then run Postfix with that map. You need to remember to update the map as often as necessary, but the proxymap daemon can be used to significantly reduce the number of concurrent connections.

Determining the Number of Simultaneous Connections to a Database

Postfix daemons (smtpd, smtp, and so on) run with a process limit (set by default_process_limit) of 100 simultaneous processes. Running at peak load, there would be 100 concurrent smtpd daemons, each querying the database backend for one access(5) lookup (e.g., because we use a map for checking if the client is in our personal blacklist and should then be denied from sending mail to us).

Remember that one lookup results in at least three queries, so the number of simultaneous queries to the database would be at least default_process_limit * 3 (which, in the default configuration, would be 300 queries), while the number of simultaneous connections is default_process_limit. This is only the number of queries and connections for smtpd daemons; other daemons, such as local and qmgr, may be working on other jobs, adding to the number of open connections and simultaneous queries.

How Postfix Queries Maps

Maps can be used for various tasks. Postfix has table-driven mechanisms that use maps (see access(5), aliases(5), canonical(5), and transport(5)). These maps can use different lookup mechanisms (LDAP, NIS, SQL, btree, hash, regexp, cdb, cidr, pcre, and so on). Note that the lookup order described below only applies to access(5) type maps.

  1. <localpart@domainpart> Matches the specified mail address verbatim.

  2. <domainpart> Matches domainpart as the domain part of an email address. The pattern domainpart also matches subdomains, but only when the string smtpd_access_maps is listed in the Postfix parent_domain_matches_subdomains configuration setting. Otherwise, specify .domainpart (note the initial dot) to match subdomains.

  3. <localpart@> Matches all mail addresses with the specified user part (localpart), no matter what domain they belong to.

  4. Fail If the lookups don't match, Postfix will return no match found, and the query ends with an error.

Note:

It isn't possible to look up a null sender address in some lookup table types. By default, Postfix uses <> as the lookup key for the null sender address. The value is specified with the smtpd_null_access_lookup_key parameter in the main.cf file.

This order of lookups implies that Postfix performs several lookups for each query, which isn't really a problem unless you're using high-latency maps like SQL or LDAP maps (and, of course, you should expect that a lot of lookups will need multiple queries). This is just one thing to remember before you put all your maps into LDAP and then complain on the postfix-users mailing list that "Postfix is slow. . . ."

External Sources

Postfix supports information sources that are not built on top of Postfix and that aren't even under your direct control, such as blacklists (DNSBL and RHSBL lists), DNS-based lists, and other external sources. Blacklists are almost exclusively used in smtpd_*_restrictions parameters in order to reject mail coming from clients or senders listed in DNSBL- or RHSBL-style lists (see Chapter 7).

As with any external query, these lookups can fail due to connectivity problems, denial-of-service attacks against the blacklist servers, and other problems. In case of a timeout or other failure, Postfix may still accept mail (bypassing a possible restriction), but it will log an appropriate warning to the mail log.

Command-Line Utilities

Postfix ships with a number of command-line utilities to assist you with administration tasks. Although they perform different functions (such as querying maps, examining queue files, dequeuing and requeuing messages, and changing the configuration), they all have one thing in common--their names start with "post."

Note:

These commands can do much more than what is described here. We are focusing on the options that you will experience in day-to-day operation. If you don't find what you are looking for here, the first place to look is the online manual.

postfix

The postfix command stops, starts, and reloads the configuration with the stop, start, and reload options.

postalias

The postalias command creates an indexed alias map from an alias file. It works just like the postmap command (described shortly), but it pays special attention to the notation in an alias file (where a colon separates the key and value). postalias must be used on alias files.

postcat

The postcat command displays the content of a message in a mail queue.

To read a message in a mail queue, you need its queue ID. Run mailq for a list of queue IDs. For example, the queue ID of the following message is F2B9715C0B3:

# mailq
F2B9715C0B3 2464 Mon Oct 13 15:29:39 markus.herrmann@example.com
(connect to mail.example.com[217.6.113.151]: Connection timed out)
torsten.hecke@example.net
-- 2 Kbytes in 1 Requests.

After obtaining a queue ID, use it as an option to postcat to see the contents of the queue file:

# postcat -q F2B9715C0B3

postmap

The postmap command's primary purpose is to build indexed maps from flat files. For example, to build /etc/postfix/virtual.db from /etc/postfix/virtual, run the following command.

# postmap hash:/etc/postfix/virtual

The postmap command can do more. Among its most useful features is the ability to test any kind of map that your Postfix installation supports. This is extremely helpful when debugging a configuration where lookups to the maps appear to fail, and you are unsure whether the key and value are actually visible to Postfix.

Debugging an Entry in a Lookup Table

To determine whether Postfix can find an entry in a map, use postmap -q. For example, the following command returns the value assigned to the key <sender@example.com> in the map /etc/postfix/sender_access (type hash):

# postmap -q sender@example.com hash:/etc/postfix/sender_access
OK

It's important to note that postmap does not look for the terms <sender@>, <example.com>, and <com>, even though these terms are in the access(5) manual page. You need to perform those lookups manually:

# postmap -q sender@ hash:/etc/postfix/sender_access
# postmap -q example.com hash:/etc/postfix/sender_access
# postmap -q com hash:/etc/postfix/sender_access

postdrop

The postdrop command reads mail from the standard input and drops the result into the maildrop directory. This program works in conjunction with the sendmail utility.

postkick

The postkick command sends a request to a Postfix daemon through a local transport channel, making Postfix interprocess communication accessible to shell scripts and other programs.

Note:

The postkick command sends messages to Postfix daemon processes. This requires that Postfix is running.

Requeuing a Message

The following advanced postkick example shows how to requeue a message for immediate redelivery:

# cat queueidlist | postsuper -r -
postkick public pickup W

This sequence of commands moves all selected messages listed in queueidlist to the maildrop queue with the postsuper -r - command, where the pickup daemon would process them like any other piece of mail. By doing this, you reset the content filter to the setting appropriate for local submission and add an extra Received: header.

The postkick command requests an immediate maildrop queue scan. Otherwise, the messages would stay in the maildrop queue for a maximum of 60 seconds. The pickup daemon submits the message to the cleanup daemon, where it gets a new queueid and is deposited into the incoming queue. The whole point is to move the message to the active queue as quickly as possible.

postlock

The postlock command gives you exclusive access to mbox files that Postfix writes, and then it runs a command while holding the lock. The lock you get from postlock is compatible with the Postfix local delivery agent. Postfix does not touch the file while your command executes. Here is an example:

# postlock /var/mail/user from

Caution:

Try to avoid any commands that might require a ctrl-C to terminate. Interrupting postlock does not guarantee that the lock will go away; you may need to remove a lock file to deliver to the mailbox again. To see if there is a lingering lock file, run postlock without a command. If this hangs and eventually times out, you probably have a leftover lock.

postlog

The postlog command allows external programs, such as shell scripts, to write messages to the mail log. This is a Postfix-compatible logging interface; by default, it logs the text from the command line as a single record. Here's a very simple example:

# postlog This is a test
postlog: This is a test
# grep "This is a test" /var/log/mail.log
Feb 20 11:50:16 mail postlog: This is a test

postqueue

The postqueue command is a user interface to Postfix queues, giving you functionality that is traditionally available with the sendmail command.

  1. The -f parameter makes postqueue request the queue manager to deliver all queued mail (flush), regardless of destination. This is equivalent to postfix flush or sendmail -q:

    # postqueue -f
  2. The -p parameter makes postqueue print the contents of the queue. It is equivalent to mailq:

    # postqueue -p
  3. The -s domain parameter makes postqueue attempt to deliver all queued mail bound for domain. This is equivalent to sendmail -q domain:

    # postqueue -s example.com

Note:

The postqueue command sends messages to Postfix daemon processes. This requires that Postfix is running.

postsuper

The postsuper command maintains jobs inside Postfix queues. Unlike postqueue, this command is restricted to the superuser, and it can run while Postfix is down. Some postsuper features are needed to check the queue before daemon processes are started. Table 5-1 shows what the postsuper command can do.

Table 5-1: Capabilities of the postsuper Command

Option Action
-d Delete a message with the named queue ID from the named mail queue(s)
-h Place a message on hold so that no attempt is made to deliver it
-H Release mail currently on hold
-p Purge temporary files left over from crashes
-r Requeue messages with a named queue ID from a named mail queue
-s Check and repair the queue structure

One of the most frequent uses of postsuper is deleting a message from the mail queue with postsuper -d queueid. Doing this manually is tedious, especially when deleting many files. The following Perl script (delete_from_mailq) makes it easier:

#!/usr/bin/perl
$REGEXP = shift || die "no email-address given (regexp-style, e.g. bl.*\@yahoo.com)!";
@data = qx</usr/sbin/postqueue -p>;
for (@data) {
if (/^(\w+)(\*|\!)?\s/) {
$queue_id = $1;
}
if($queue_id) {
if (/$REGEXP/i) {
$Q{$queue_id} = 1;
$queue_id = "";
}
}
}
#open(POSTSUPER,"|cat") || die "couldn't open postsuper" ;
open(POSTSUPER,"|postsuper -d -") || die "couldn't open postsuper" ;
foreach (keys %Q) {
print POSTSUPER "$_\n";
};
close(POSTSUPER);

Here's how you'd use it:

# mailq
C73A015C095     7509 Mon Oct 13 14:56:17 MAILER-DAEMON
(connect to mx5.ancientaward.com[64.156.166.211]: Connection refused)
 
National_Nosepicking_Month@mx5.ancientaward.com

Notice that the sender is identified as <MAILER-DAEMON> here. To remove these bounces, run delete-from-mailq as root:

# delete-from-mailq MAILER-DAEMON
postsuper: C73A015C095: removed
postsuper: Deleted: 1 message

About the Authors:

Ralf Hildebrandt and Patrick Koetter are active and well-known figures in the Postfix community. Hildebrandt is a systems engineer for T-NetPro, a German telecommunications company, and Koetter runs his own company consulting and developing corporate communication for customers in Europe and Africa. Both have spoken about Postfix at industry conferences and contribute regularly to a number of open source mailing lists.

security

This section contains information related for file system security

ssh tricks

SSH (secure shell) is a program enabling secure access to remote filesystems. Not everyone is aware of other powerful SSH capabilities, such as passwordless login, automatic execution of commands on a remote system or even mounting a remote folder using SSH! In this article we’ll cover these features and much more.

SSH works in a client-server mode. It means that there must be an SSH daemon running on the server we want to connect to from our workstation. The SSH server is usually installed by default in modern Linux distributions. The server is started with a command like /etc/init.d/ssh start. It uses the communication port 22 by default, so if we have an active firewall, the port needs to be opened. After installing and starting the SSH server, we should be able to access it remotely. A simple command to log in as user1 to the remote_server (identified by a domain name or an IP address) looks like this:

ssh user1@remote_server

After entering the password to access the remote machine, a changed command prompt should appear, looking similar to user1@remote_server:~$. If this is the case, it means that the login was successful and we’re working in a remote server environment now. Any command we run from this point on, will be executed on the remote server, with the rights of the user we logged in with.

SCP - secure file copying

SCP is an integral part of the OpenSSH package. It is a simple command allowing to copy any file or folder to or from a remote machine using the SSH protocol. The SSH+SCP duo is a great replacement of the non-secure FTP protocol which is widely used by the Internet users nowadays. Not everyone is aware of the fact though, that all the passwords sent while using the FTP protocol are transferred over the network in a plain text format (making it dead easy for crackers to take over) - SCP is a much more reliable alternative. The simplest usage of SCP looks like on the following example:

scp file.txt user1@remote_server:~/

This will copy the local file.txt to the remote server and put it in the home folder of user1. Instead of ~/, a different path can be supplied, i.e. /tmp, /home/public, and any other path we have write access to.

In order to copy a file from a remote server to the local computer, we can use another SCP syntax:

scp user1@remote_server:~/file.txt .

This will copy a file file.txt located in a home folder of user user1 of a remote system to the local folder (the one we are currently in).

Other interesting SCP options:

  • -r - to copy folders recursively (including subfolders),
  • -P port - to use a non-standard port (the default is 22) - of course this option should be used if the server listens on a non-standard port. The option can be helpful when connecting from a firewall-protected network. Setting the SSH server to listen on 443 port (used for secure HTTP connections) is the best way to by-pass the administrator’s restrictions.

GUIs for SCP

If we do not like the console and we prefer GUI (graphical user interface), we can use a graphical (or pseudo-graphical) SCP client. Midnight Commander is one of the programs that provides an SCP client (option shell link). Nautilus and Konqueror are the SCP-capable file managers as well. Entering ssh://user1@remote_server:~/ in the URI field results in a secure shell connection to the remote system. The files can be then copied just as they were available locally.
In the MS Windows environment, we have a great app called WinSCP. The interface of this program looks very much like Total Commander. By the way, there is a plug-in allowing for SCP connections from TC as well.

SSH without passwords - generating keys

Entering passwords upon every SSH connection can be annoying. On the other hand, unprotected remote connection is a huge security risk. The solution to this problem is authorization using the private-public key-pair.

The pair of keys is usually generated using the ssh-keygen command. Below, there is a sample effect of such key generation. RSA or DSA keys can be used.

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key
(/home/user1/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in
/home/user1/.ssh/id_rsa.
Your public key has been saved in
/home/user1/.ssh/id_rsa.pub.
The key fingerprint is:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx

When the program asks for the key password, we should just press ENTER - this way, a passwordless key will be created. Remember that this is always a security hole to have a passwordless key (in simple words, doing that downgrades your remote system security to the security of your local system) so do it on your own risk. As the ssh-keygen finishes its work, you can see that two keys have been generated. The private key landed in /home/user1/.ssh/id_rsa and we should never make this public. The second public key appeared in /home/user1/.ssh/id_rsa.pub and this is the one we can show the entire world.

Now, if we want to access a remote system from our local computer without passwords (only using the keys), we have to add the information about our public key to the authorized_keys file located in ~/.ssh folder on the remote system. This can be done using the following commands:

Remote SSH login
Pic 1. Passwordless SSH login

$ scp /home/user1/.ssh/id_rsa.pub \\
user1@remote_server:~/
$ ssh user1@remote_server
$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

The third command will be obviously executed on a remote server. After this operation, all actions performed on the remote server with SSH will not need any password whatsoever. This will certainly make our work easier.

Notice that if you need passwordless access from the remote server to the local one, the similar procedure has to be performed from the remote server. Authorization using keys is a one-way process. The private key can verify the public one, not vice-versa.

Executing commands on a remote system

Well, now when we can already log into remote OS without the password, why wouldn’t we want to execute some command remotely? There can be multiple useful appliances of this, especially when we have to execute some command on a daily basis, and it could not be automated before, because of the need to enter the password manually (or enter it as plain text which is not very secure).

One interesting case is a “remote alert”. Let’s say that we have some crucial process running on the remote system, i.e. a website running on Apache server. We want be be warned when the system gets out of resources (i.e. the disk space is getting short or the system load is too high). We could obviously send an e-mail in such cases. But additionally, we can execute a remote command which plays a warning sound on our local OS! The code for such event would look something like that:

ssh user1@local_server 'play \\
/usr/share/sounds/gaim/arrive.wav'

This command, executed in a script from the remote server would cause a passwordless login of user1 to the local_server (the one we’re usually working on) and play a wave file with the play command (which is usually available in Linux). The actual case in which we execute this remote command should obviously be specified in a script, but we’re not going to provide a scripting course here, but a way to execute remote commands with passwordless SSH :).

X11 forwarding - running graphical apps remotely

One of the least known functions of SSH is X protocol forwarding. This enables us to run almost every X application remotely! It’s enough to connect to the remote server using the -X option:

ssh -X user1@remote_serwer

and the display of every X application executed from now on will be forwarded to our local X server. We can configure the X11 Forwarding permanently by editing the /etc/ssh/ssh_config file (relevant option is ForwardX11 yes). Of course for the option to work, the remote SSH server needs to support X11 forwarding as well. The /etc/ssh/sshd_config file is responsible for that. This option is however configured by default in most of the Linux distros.

If we just need to execute one single command, we can use the syntax we learned before:

ssh -X user1@remote_serwer 'psi'

- this will execute PSI instant messenger on the remote server, passing the display to the local screen.

Of course the speed of applications executed remotely depends mostly on the network connection speed. It works almost flawlessly in local networks (even things like forwarding Totem playing a DivX movie). In case of Internet connection, a DSL seems reasonable to get apps like Skype or Thunderbird work quite well with a remote call.

Notice that it’s also possible to connect to the remote server without the X11 forwarding enabled, export the DISPLAY variable to point to the local machine and then run the X application. This way, the application would be executed with a remote display, using the generic X server functionality. SSH security would not be applied in such case since this kind of configuration has nothing to do with SSH. Depending on the configuration of the local X server, it may be that the authorization of the remote X applications needs to be turned on in such case. This is usually done by the command xhost. For example, xhost + hostname accepts all the remote applications from the specified hostname for a while. If we plan to use this option regularly, a more secure X server configuration is recommended.

SSHFS - mounting a remote folder

Working on a file located on some remote server via SSH can be quite annoying especially when we need often copy different files in both directions. Using a the fish:// protocol in Midnight Commander or Konqueror is a partly solution - fish tends to be much slower than pure SSH and it often slows down even more while copying files. The ideal solution would be a possibility to mount a remote resource available through SSH only. The good news is that… this option exists for a while already, thanks to sshfs and the fuse project.

Fuse is a kernel module (recently it has been adopted in the official 2.6 series) allowing for mounting different filesystems by an unprivileged user. SSHFS is a program created by the author of fuse himself which enables to mount remote folders/filesystems using SSH. The idea is very simple - a remote SSH folder is mounted as a local folder in the filesystem. Since then, almost all operations on this folder work exactly as if this was a normal local folder. The difference is that the files are silently transferred though SSH in the background.

Installing fuse and sshfs in Ubuntu is as easy as entering (as root):

# apt-get install sshfs

The only remaining action is adding the user that we want to give the permission to mount SSH folders to the fuse group (using a command like usermod -G -a fuse user1 or manually editing the /etc/group file). Eventually, the fuse module needs to be loaded:

# modprobe fuse

And then, after logging in, we can try to mount a remote folder using sshfs:

mkdir ~/remote_folder
sshfs user1@remote_server:/tmp ~/remote_folder

The command above will cause the folder /tmp on the remote server to be mounted as ~/remote_folder on the local machine. Copying any file to this folder will result in transparent copying over the network using SCP. Same concerns direct file editing, creating or removing.

When we’re done working with the remote filesystem, we can unmount the remote folder by issuing:

fusermount -u ~/remote_folder

If we work on this folder on a daily basis, it is wise to add it to the /etc/fstab table. This way is can be automatically mounted upon system boot or mounted manually (if noauto option is chosen) without the need to specify the remote location each time. Here is a sample entry in the table:

sshfs#user1@remote_server:/tmp \\
/home/user1/remote_folder/ fuse defaults,auto 0 0

If we want to use fuse and sshfs regularly, we need to edit the /etc/modules file adding the fuse entry. In other case we would have to load the module manually each time we want to use it.

Summary

As you can see, SSH is a powerful remote access tool. If we need to work with remote UNIX filesystems often, it’s really worth to learn a few powerful features of SSH and use them in practice. SSH can really make your daily work much more effective and pleasant at the same time. In the following article (to be published later this month) we’re going to cover another great feature of SSH: making different kinds of tunnels with port forwarding using transparent socks and a corkscrew

ssh tunnels

The goal of this article is to present a few effective methods to revamp the way you work in a restricted corporation-like network. In order to achieve it we’re going to use SSH tunneling to bypass the firewall rules applied by your system administrator. We’ll start with breaking through simple restrictions and gradually pass to more and more elaborate firewalls while we move on.

Author: Lukasz Usowicz
Translation: Lukasz Usowicz, Borys Musielak

Important note: It’s not our goal to encourage you to illegally bypass any restrictions set by the administrators of your network. We present a technology which is often helpful when working on a machine behind a firewall. If you are willing to use some tricks presented here to break through your company’s firewall, you have to understand that it may not be allowed in your corporation and you risk getting sacked. We take no responsibility for your actions. You’ve been warned.

This article is a continuation of a previous text: published in our vortal last month. The spirit of this article is a little bit different, though. It targets more experienced users, especially those who have to work in computer networks with harsh security rules. To make it clear - using SSH to tunnel insecure protocols like FTP or CVS is not in the scope. Perhaps another SSH article will cover this.

Preparation

Here are a few things that you need to know or prepare in order to benefit from this article.

  • Basic SSH and Linux knowledge.
  • A local workstation (in a restricted network) with GNU/Linux installed.
  • A remote Linux machine, with a public IP address (let’s assume it’s static to simplify the situation).
  • Patience and no fear to use the command line.

For simplicity reasons, throughout this text we’re going to use some default names. The workstation which is located in a restricted network eg. on our desk at work (the one we are going to revamp) will be called LOCAL_HOST. The second one should be outside the restricted network eg. at our house and will be called REMOTE_HOST. Let’s assume that on the home workstation there is a user named user and on the work machine there is a user worker. On the REMOTE_HOST with a public, static IP an SSH server is installed. Although all the solutions presented in this article can be applied in any GNU/Linux distribution or even in MS Windows to make it simpler, we will consider a Debian-like system only.

If you don’t have the SSH server installed and running, open up a terminal and type (as root or using sudo) the following command:

REMOTE_HOST:~# aptitude install openssh-server

The server should start automatically after being installed (as well as on system start-up). We should also check whether we’re not blocking the port 22 on our firewall (and open it if we do). We should also note down our IP address (we’ll call it IP_NUMBER in text; try /sbin/ifconfig command to figure it out).

All right, let’s leave our home computer (REMOTE_HOST) now on and go visit our office. First, we need to analyze our network restrictions. Sounds serious but don’t worry - I’m not going to mess with network sniffers and other types of hacker tools. We are going to simply try to connect to some outside networks and depending on the level of restrictions we’ll see whether we fail or not. Looks good? Let’s start then.

Creating a simple tunnel

At the beginning let’s assume that SSH connections are not blocked, but we can receive e-mails only from our local office account. This means that ports 25 and 110 (SMTP and POP) are open only for our local network. But what if we want to be able to receive mail from external servers (EXT_POP_SVR) and send it using external accounts as well (EXT_SMTP_SVR)? Here is where the tunnels enter the stage. We just need to add a parameter while connecting to the REMOTE_HOST via SSH. So, we’re digging the tunnel from our work machine to home with the following command:

worker@LOCAL_HOST:~$ ssh user@IP_NUMBER \\
-L 10025:EXT_SMTP_SVR:25 -L 10110:EXT_POP_SVR:110

Let’s try to decode this. The option -L can be read as “listen on local host”. After a space bar we put the port on which SSH has to listen (in our case respectively 10025 and 10110, but it’s just an example; we can choose different ones but in order to tunnel ports with numbers lower than 1024 we need root privileges). After first colon we point where our REMOTE_HOST should forward the connection. After second colon we state on which port the final server/computer awaits our connection. I emphasize that just after the first colon we give an address relative to REMOTE_HOST. If we want to connect via tunnel with REMOTE_HOST on port 25 (and not further than there) we should use something like:

worker@LOCAL_HOST:~$ ssh user@IP_NUMBER -L 10025:localhost:25

The relation between REMOTE_HOST and… REMOTE_HOST is the following: this is the very same host ;), so it’s localhost for itself.

Let’s get back to our tunnels. We can now configure an e-mail client to connect to an external server. As we’ve mentioned earlier, our LOCAL_HOST listening on port 10025 is now “EXT_SMTP_SVR server listening on port 25”. By analogy, we can say that localhost:10110 is an EXT_POP_SVR:110. In our e-mail client we shall set an incoming server to localhost and port to 10110 - SSH will carry on further communication. Naturally, localhost set on LOCAL_HOST will point to itself. And again by analogy outgoing server should be set to localhost and port to 10025.

In this quite simple (I hope!) way we can bypass not very complex restrictions only. But our network administrator is not sleeping so…

Note that you don’t have to use your IP_NUMBER all the time. If you want to use REMOTE_HOST by its name you need to put a line like this

IP_NUMBER REMOTE_HOST

to your /etc/hosts file (on the machine at work), so that your work machine translates the REMOTE_HOST to IP_NUMBER on the fly. You don’t need to do this only if the REMOTE_HOST is a domain name (or if you’re fine with using your IP_NUMBER all the time). In this text we use IP_NUMBER nevertheless.

Let’s swing into a higher gear

Our present situation has changed. It seems that somebody in our work abuses usage of WWW. Access via HTTP has been cut to the minimum allowed by the boss. Right now we are not interested in how it has been done. Port 22 is still open, but we can’t say the same about port 80 (responsible for HTTP communication). Now when we know how the tunnels work, this is not a big problem for us.

It seems impossible but even the Google search has been blocked. So, to solve this unfortunate situation, we sit down and log onto our REMOTE_HOST like that:

worker@LOCAL_HOST:~$ ssh user@IP_NUMBER \\
-L 10080:www.google.com:80

Just a few clicks in Firefox: Edit -> Preferences -> Connection Settings -> Manual proxy configuration. Here we can put in the HTTP proxy server field: localhost and 10080 for port. If there has been some other values in those fields, we shall write them down. We may need to use them later on. I’ll call those extra settings PROXY_SVR and PROXY_PORT.

Now, we can type http://www.google.com in the address bar and… hip hip hooray – the WWW is wide open again. Don’t be so happy though. Try http://www.altavista.com. And what you’ve got – Google search again. Well, what else can we expect if we’re forwarding all traffic to www.google.com via SSH! To visit AltaVista we should reconnect again with:

worker@LOCAL_HOST:~$ ssh user@IP_NUMBER \\
-L 10080:www.altavista.com:80

This is rather a pretty non-effective way to work with the Internet, don’t you think?

SSH as a proxy

In this situation let’s look into the SSH manual and find a parameter -D. As we can read there, SSH can act as a (specific) proxy server. This is a SOCKS-type (pseudo)server. We won’t be concerned how it works, just remember the name. Type the following in your text terminal:

worker@LOCAL_HOST:~$ ssh user@IP_NUMBER -D 8080

From now on, SSH listens on port 8080. Looking back into Firefox’s proxy settings we can find a SOCKS Host field. There we put localhost and port 8080 (server type should be set to 5). Don’t forget to remove the previous entries in HTTP Proxy that we’ve set earlier. And what we’ve got? Well, now SSH will intercept everything on this port and dynamically open a tunnel (via REMOTE_HOST) to the final target typed in the Firefox address bar. From now on we can surf over the whole Internet! Vualla!

Putting on transparent socks

There is one little issue. And you know what? I think that Opera users will rise it first. That’s because currently Opera does NOT support SOCKS. I’m an Opera user too and I can’t understand that, just like you ;). This is the right time and place to introduce one of the SSH friends: tsock (abbr. transparent SOCKS). Yet again we won’t look deeper in how SOCKS server works but with tsocks we’re going to use some of its features instead. We’ll need root account privilege on LOCAL_HOST to do this. This is not always available but here it’s required. Let’s install tsocks (again on Debian):

LOCAL_HOST:~# aptitude install tsocks

Assuming that SSH still listens on port 8080 as a proxy, we should perform the following steps:

  • edit tsocks configuration file /etc/tsocks.conf,
  • find an option called local and put there our local network(s) address(es) eg.
    local = 192.168.0.*
    local = 10.0.0.0/255.255.255.0
  • if we want to create a custom path, we can do this with the option path, I’ll omit this part for now,
  • here is the most important thing: options server and server_port. We’ve got to set them to our proxy server. In our example it will look like this:
    server = localhost
    server_port = 8080
  • we should also set SOCKS server type; set it to server_type = 5 and don’t ask me why ;)

It’s time to put those socks on. We can do this as a normal user. Again in a terminal:

worker@LOCAL_HOST:~$ tsocks opera

Here tsocks are used to run Opera. But it will also intercept all network queries generated by the browser and forward them directly to the SOCKS server (except for the local network queries). Our proxy server (ie. SSH) will then forward those queries further on to REMOTE_HOST. All in all, Opera will act as if it has been run in the REMOTE_HOST environment. This way, the browser won’t be vulnerable on any network restrictions. If REMOTE_HOST is connected directly to the Internet, Opera should also be configured as Directly connected. The whole “dirty job” is done by the tsocks+SSH tandem. In fact we can run practically any net application with tsocks program_name.

That’s how we’ve met first good SSH friend, but…

We’re in trouble now…

… just because our admin closed port 22. Loser! Well, we need to adjust to the new environment now. First, we should find a port which is usually open. Let’s try the one responsible for secure web pages (SSL connections) which is usually left open in all networks. Its number is 443. As there is no possibility to change anything remotely for now, we need to go back home. Sitting in front of our REMOTE_HOST as root we need to edit /etc/ssh/sshd_config file. Find the place with entry Port 22 and put Port 443 just below. All we have to do now is to restart SSH server with:

REMOTE_HOST:~# /etc/init.d/ssh restart

Sample command to connect to REMOTE_HOST from LOCAL_HOST in the present situation may look like that:

worker@LOCAL_HOST:~$ ssh -p 443 user@REMOTE_HOST -D 8080 \\
-L 10025:smtp.gmail.com:25 -L 10110:pop.gmail.com:110

As you can see, option -p 443 is a proper switch to force SSH to use a non-default port for a connection. And again we are “free as a bird”.

Battle continues with a corkscrew

Oh, no! Our network administrator got really furious now. “It’s time to finish these abuses” – he said. But he was not allowed to block all HTTPS traffic (fortunately!). So he figured out that the best thing in this situation is to control all traffic with an HTTP proxy server. He has set it up to listen on port 3128 and opened this port to connect only to a proxy server (naturally port 443 has been blocked). Outside connections on port 3128 are blocked too. Is there any way to bypass this? Well, try to remind some settings you’ve written down earlier: PROXY_SVR, PROXY_PORT. We’ll assume now that these values point to admins’ proxy server (here PROXY_PORT = 3128). We need to find a proper tool to use these values. Let’s look into our repositories:

worker@REMOTE_HOST:~$ apt-cache search proxy ssh tunnel

Among the results we should probably see a corkscrew app. Quick installation:

REMOTE_HOST:~# aptitude install corkscrew

Corkscrew manual reveals an easy way to “teleport” SSH to the other side of the HTTP proxy. To generate such a “hoop” we need to know which types of connections are passed directly through the proxy. All encrypted connections usually fulfill this condition. That’s why we again concentrate on HTTPS (port 443). To force SSH skip the proxy we should edit ~/.ssh/config and add the entry shown below:

Host IP_NUMBER
ProtocolKeepAlives 30
ProxyCommand /usr/bin/corkscrew PROXY_SRV \
PROXY_PORT IP_NUMBER 443

Having such settings we should be able to connect to REMOTE_HOST again with:

worker@LOCAL_HOST:~# ssh -p 443 user@IP_NUMBER

All those switches like -L and -D still work, so we can use them in a suitable way for us. So please welcome another good friend of SSHcorkscrew.

Once again we can feel the breath of freedom, but …

And so on, and so on

We could continue our speculations further and further. A well-prepared administrator will find a way to block all methods shown above. But one truth is uncontested: if there is any hole in a restricted network, it automatically becomes a wide open window to the whole world. Here we talked only about the HTTPS protocol abuse and a HTTP proxy. But there are other environments and protocols we could possibly use.

Post Scriptum

  • There is another useful option for SSH. It’s -C which compresses all traffic on-the-fly. It’s especially useful while using corkscrew.
  • I haven’t mentioned the reverse tunnels (option -R), but they are very useful as well.
  • Another method to efficiently bypass restrictions when we don’t have root access on LOCAL_HOST is (our) proxy server installed on REMOTE_HOST
  • As I’ve mentioned in the beginning, SSH is widely used to secure “plain text” protocols, too.
  • If you have the knowledge and would like to describe the above issues precisely for this vortal, feel free to contact michuk, I’m sure he’ll be very pleased with that :)

 

Appendix (for the tenacious ones): using httptunnel

The above text is an almost-direct translation from the original. But I’ve got something special for those who are not bored (or confused) with all those tunnels, yet. So, let’s met the…

Absolutely extreme conditions

Here I need to be more precise. Imagine that the traffic in our network is allowed only via port 3128 and only to one specific IP number which points to a proxy server. What’s more, the proxy doesn’t allow for http_connect (i.e. forwarding encrypted protocols). This excludes the usage of corkscrew. And to make it even harder, the firewall blocks all packages that don’t have an HTTP header. Conditions described above mean no more than that we are only allowed to view “classical” web pages and only with a proxy. What shall we do to bypass such restrictions? To effectively overcome this “not so fortunate” situation, we’ll still need SSH. But this time SSH is going to have a special carrier to bypass the proxy. This carrier needs to have an HTTP header to do its job. You can probably figure out the name of this third SSH friend – yes, it’s an httptunnel. Installation is needed on both hosts (LOCAL_HOST and REMOTE_HOST) and as you’ve noticed earlier, in Debian this is as simple as:

REMOTE/LOCAL_HOST:~# aptitude install httptunnel

The application contains both an httptunnel server (hts) and an httptunnel client (htc). I encourage you to take a look at the manual to see how it works in detail, but the usage is very similar to SSH tunneling. On the REMOTE_HOST we need to run the server side of the application. The server is responsible for deciding where the connections should be forwarded. If we want to tunnel the connection to REMOTE_HOST we simply point it by using localhost.

In our example we only want to forward all connections to an SSH server running on REMOTE_HOST. To accomplish this task, the httptunnel server should be started as follows:

REMOTE_HOST:~# hts -F localhost:22 80

A word of explanation: -F localhost:22 means that each connection is going to be forwarded to REMOTE_HOST’s port 22 (i.e to an SSH server on REMOTE_HOST). And 80 is the port on which hts should await our connections from the outside (just remember to open it on the firewall and/or stop any other services that may be running and listening on this port).

The appropriate command to connect to hts on REMOTE_HOST from LOCAL_HOST using the proxy is:

worker@LOCAL_HOST:~$ htc -P PROXY_SVR:PROXY_PORT \\
-F 10022 IP_NUMBER:80

From now on, LOCAL_HOST listening on port 10022 should forward all connections to port 22 on REMOTE_HOST. To establish a desired SSH connection we can type:

worker@LOCAL_HOST:~$ ssh -p 10022 user@localhost -C -D 8080 \\
-L 13389:somewhere.else.com:3389 -L \\
13306:here.or.there.net:3306

Although this is a double-tunneled connection and may be a little bit slower than a direct one, it allows us to navigate all over the net, not only to the addresses set by the administrator. And you know what? We are free again!

I just hope that each of you won’t need to apply all of those tricks in real conditions. But… some day, somewhere… it may even save your life :)

ssh-keygen

authentication key generation, management and conversion

SSH-KEYGEN(1) OpenBSD Reference Manual SSH-KEYGEN(1)
NAME
ssh-keygen - authentication key generation, management and conversion
SYNOPSIS
ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment]
[-f output_keyfile]
ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
ssh-keygen -i [-f input_keyfile]
ssh-keygen -e [-f input_keyfile]
ssh-keygen -y [-f input_keyfile]
ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]
ssh-keygen -l [-f input_keyfile]
ssh-keygen -B [-f input_keyfile]
ssh-keygen -D reader
ssh-keygen -F hostname [-f known_hosts_file] [-l]
ssh-keygen -H [-f known_hosts_file]
ssh-keygen -R hostname [-f known_hosts_file]
ssh-keygen -U reader [-f input_keyfile]
ssh-keygen -r hostname [-f input_keyfile] [-g]
ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]
ssh-keygen -T output_file -f input_file [-v] [-a num_trials] [-W
generator]

DESCRIPTION
ssh-keygen generates, manages and converts authentication keys for
ssh(1). ssh-keygen can create RSA keys for use by SSH protocol version 1
and RSA or DSA keys for use by SSH protocol version 2. The type of key
to be generated is specified with the -t option. If invoked without any
arguments, ssh-keygen will generate an RSA key for use in SSH protocol 2
connections.

ssh-keygen is also used to generate groups for use in Diffie-Hellman
group exchange (DH-GEX). See the MODULI GENERATION section for details.

Normally each user wishing to use SSH with RSA or DSA authentication runs
this once to create the authentication key in ~/.ssh/identity,
~/.ssh/id_dsa or ~/.ssh/id_rsa. Additionally, the system administrator
may use this to generate host keys, as seen in /etc/rc.

Normally this program generates the key and asks for a file in which to
store the private key. The public key is stored in a file with the same
name but ``.pub'' appended. The program also asks for a passphrase. The
passphrase may be empty to indicate no passphrase (host keys must have an
empty passphrase), or it may be a string of arbitrary length. A
passphrase is similar to a password, except it can be a phrase with a se-
ries of words, punctuation, numbers, whitespace, or any string of charac-
ters you want. Good passphrases are 10-30 characters long, are not sim-
ple sentences or otherwise easily guessable (English prose has only 1-2
bits of entropy per character, and provides very bad passphrases), and
contain a mix of upper and lowercase letters, numbers, and non-alphanu-
meric characters. The passphrase can be changed later by using the -p
option.

There is no way to recover a lost passphrase. If the passphrase is lost
or forgotten, a new key must be generated and copied to the corresponding
public key to other machines.

For RSA1 keys, there is also a comment field in the key file that is only
for convenience to the user to help identify the key. The comment can
tell what the key is for, or whatever is useful. The comment is initial-
ized to ``user@host'' when the key is created, but can be changed using
the -c option.

After a key is generated, instructions below detail where the keys should
be placed to be activated.

The options are as follows:

-a trials
Specifies the number of primality tests to perform when screening
DH-GEX candidates using the -T command.

-B Show the bubblebabble digest of specified private or public key
file.

-b bits
Specifies the number of bits in the key to create. For RSA keys,
the minimum size is 768 bits and the default is 2048 bits. Gen-
erally, 2048 bits is considered sufficient. DSA keys must be ex-
actly 1024 bits as specified by FIPS 186-2.

-C comment
Provides a new comment.

-c Requests changing the comment in the private and public key
files. This operation is only supported for RSA1 keys. The pro-
gram will prompt for the file containing the private keys, for
the passphrase if the key has one, and for the new comment.

-D reader
Download the RSA public key stored in the smartcard in reader.

-e This option will read a private or public OpenSSH key file and
print the key in RFC 4716 SSH Public Key File Format to stdout.
This option allows exporting keys for use by several commercial
SSH implementations.

-F hostname
Search for the specified hostname in a known_hosts file, listing
any occurrences found. This option is useful to find hashed host
names or addresses and may also be used in conjunction with the
-H option to print found keys in a hashed format.

-f filename
Specifies the filename of the key file.

-G output_file
Generate candidate primes for DH-GEX. These primes must be
screened for safety (using the -T option) before use.

-g Use generic DNS format when printing fingerprint resource records
using the -r command.

-H Hash a known_hosts file. This replaces all hostnames and ad-
dresses with hashed representations within the specified file;
the original content is moved to a file with a .old suffix.
These hashes may be used normally by ssh and sshd, but they do
not reveal identifying information should the file's contents be
disclosed. This option will not modify existing hashed hostnames
and is therefore safe to use on files that mix hashed and non-
hashed names.

-i This option will read an unencrypted private (or public) key file
in SSH2-compatible format and print an OpenSSH compatible private
(or public) key to stdout. ssh-keygen also reads the RFC 4716
SSH Public Key File Format. This option allows importing keys
from several commercial SSH implementations.

-l Show fingerprint of specified public key file. Private RSA1 keys
are also supported. For RSA and DSA keys ssh-keygen tries to
find the matching public key file and prints its fingerprint. If
combined with -v, an ASCII art representation of the key is sup-
plied with the fingerprint.

-M memory
Specify the amount of memory to use (in megabytes) when generat-
ing candidate moduli for DH-GEX.

-N new_passphrase
Provides the new passphrase.

-P passphrase
Provides the (old) passphrase.

-p Requests changing the passphrase of a private key file instead of
creating a new private key. The program will prompt for the file
containing the private key, for the old passphrase, and twice for
the new passphrase.

-q Silence ssh-keygen. Used by /etc/rc when creating a new key.

-R hostname
Removes all keys belonging to hostname from a known_hosts file.
This option is useful to delete hashed hosts (see the -H option
above).

-r hostname
Print the SSHFP fingerprint resource record named hostname for
the specified public key file.

-S start
Specify start point (in hex) when generating candidate moduli for
DH-GEX.

-T output_file
Test DH group exchange candidate primes (generated using the -G
option) for safety.

-t type
Specifies the type of key to create. The possible values are
``rsa1'' for protocol version 1 and ``rsa'' or ``dsa'' for proto-
col version 2.

-U reader
Upload an existing RSA private key into the smartcard in reader.

-v Verbose mode. Causes ssh-keygen to print debugging messages
about its progress. This is helpful for debugging moduli genera-
tion. Multiple -v options increase the verbosity. The maximum
is 3.

-W generator
Specify desired generator when testing candidate moduli for DH-
GEX.

-y This option will read a private OpenSSH format file and print an
OpenSSH public key to stdout.

MODULI GENERATION
ssh-keygen may be used to generate groups for the Diffie-Hellman Group
Exchange (DH-GEX) protocol. Generating these groups is a two-step pro-
cess: first, candidate primes are generated using a fast, but memory in-
tensive process. These candidate primes are then tested for suitability
(a CPU-intensive process).

Generation of primes is performed using the -G option. The desired
length of the primes may be specified by the -b option. For example:

# ssh-keygen -G moduli-2048.candidates -b 2048

By default, the search for primes begins at a random point in the desired
length range. This may be overridden using the -S option, which speci-
fies a different start point (in hex).

Once a set of candidates have been generated, they must be tested for
suitability. This may be performed using the -T option. In this mode
ssh-keygen will read candidates from standard input (or a file specified
using the -f option). For example:

# ssh-keygen -T moduli-2048 -f moduli-2048.candidates

By default, each candidate will be subjected to 100 primality tests.
This may be overridden using the -a option. The DH generator value will
be chosen automatically for the prime under consideration. If a specific
generator is desired, it may be requested using the -W option. Valid
generator values are 2, 3, and 5.

Screened DH groups may be installed in /etc/moduli. It is important that
this file contains moduli of a range of bit lengths and that both ends of
a connection share common moduli.

FILES
~/.ssh/identity
Contains the protocol version 1 RSA authentication identity of
the user. This file should not be readable by anyone but the us-
er. It is possible to specify a passphrase when generating the
key; that passphrase will be used to encrypt the private part of
this file using 3DES. This file is not automatically accessed by
ssh-keygen but it is offered as the default file for the private
key. ssh(1) will read this file when a login attempt is made.

~/.ssh/identity.pub
Contains the protocol version 1 RSA public key for authentica-
tion. The contents of this file should be added to
~/.ssh/authorized_keys on all machines where the user wishes to
log in using RSA authentication. There is no need to keep the
contents of this file secret.

~/.ssh/id_dsa
Contains the protocol version 2 DSA authentication identity of
the user. This file should not be readable by anyone but the us-
er. It is possible to specify a passphrase when generating the
key; that passphrase will be used to encrypt the private part of
this file using 3DES. This file is not automatically accessed by
ssh-keygen but it is offered as the default file for the private
key. ssh(1) will read this file when a login attempt is made.

~/.ssh/id_dsa.pub
Contains the protocol version 2 DSA public key for authentica-
tion. The contents of this file should be added to
~/.ssh/authorized_keys on all machines where the user wishes to
log in using public key authentication. There is no need to keep
the contents of this file secret.

~/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of
the user. This file should not be readable by anyone but the us-
er. It is possible to specify a passphrase when generating the
key; that passphrase will be used to encrypt the private part of
this file using 3DES. This file is not automatically accessed by
ssh-keygen but it is offered as the default file for the private
key. ssh(1) will read this file when a login attempt is made.

~/.ssh/id_rsa.pub
Contains the protocol version 2 RSA public key for authentica-
tion. The contents of this file should be added to
~/.ssh/authorized_keys on all machines where the user wishes to
log in using public key authentication. There is no need to keep
the contents of this file secret.

/etc/moduli
Contains Diffie-Hellman groups used for DH-GEX. The file format
is described in moduli(5).

SEE ALSO
ssh(1), ssh-add(1), ssh-agent(1), moduli(5), sshd(8)

The Secure Shell (SSH) Public Key File Format, RFC 4716, 2006.

AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.

OpenBSD 4.4 July 24, 2008 5

rssh

Restrict Users to SCP and SFTP and Block SSH Shell Access with rssh

Posted By vivek On December 31, 2007 @ 6:59 am In Howto, Linux, RedHat/Fedora Linux, Security, Sys

FTP is insecure protocol, but file-transfer is required all time. You can use OpenSSH Server to transfer file using SCP and SFTP (secure ftp) without setting up an FTP server. However, this feature also grants ssh shell access to a user. Basically OpenSSH requires a valid shell. Here is how sftp works:

SCP/SFTP -> SSHD -> Call sftpd subsystem -> Requires a shell -> User can login to server and run other commands.

In this [3] article series we will help you provide secure restricted file-transfer services to your users without resorting to FTP. It also covers chroot jail setup instructions to lock down users to their own home directories (allow users to transfer files but not browse the entire Linux / UNIX file system of the server) as well as per user configurations.
rssh ~ a restricted shell

rssh is a restricted shell for use with OpenSSH, allowing only scp and/or sftp. It now also includes support for rdist, rsync, and cvs. For example, if you have a server which you only want to allow users to copy files off of via scp, without providing shell access, you can use rssh to do that.
Supported operations using rssh

Restricted shell only allows following operations only:

* scp - Secure file copy
* sftp - Secure FTP
* cvs - Concurrent Versions System ~ you can easily retrieve old versions to see exactly which change caused the bug
* rsync - Backup and sync file system
* rdist - Backup / RDist program maintains identical copies of files on multiple hosts.

Install rssh
CentOS / Fedora / RHEL Linux rssh installation

Visit Dag's repo to grab [4] rssh package
# cd /tmp
# wget http://dag.wieers.com/rpm/packages/rssh/rssh-2.3.2-1.2.el5.rf.i386.rpm
# rpm -ivh rssh-2.3.2-1.2.el5.rf.i386.rpm

- nixCraft - http://www.cyberciti.biz/tips -

How to: Configure User Account to Use a Restricted Shell ( rssh )

Posted By vivek On November 27, 2007 @ 1:02 pm In Linux, Security, Sys admin, Tips, UNIX | 3 Comments
[1] Next in series » »
[2] « « Previous in series

[3] Now rssh is installed. Next logical step is configure user to use rssh. All you have to do is set a user account shell to /usr/bin/rssh. The following examples adds user didi to system with /usr/bin/rssh.
Create a new user with /usr/bin/rssh

Login as the root user

Type the following command to create a new user called didi:
# useradd -m -d /home/didi -s /usr/bin/rssh didi
# passwd didi
Change existing user shell to /usr/bin/rssh

Use [4] chsh command or usermod command to change user login shell:
# usermod -s /usr/bin/rssh old-user-name
# usermod -s /usr/bin/rssh vivek
# chsh -s /usr/bin/rssh vivek
Try login via ssh or sftp

Now try login via ssh or sftp using username didi:
$ sftp didi@my.backup.server.com
OR
$ ssh didi@my.backup.server.com
Output:

didi@my.backup.server.com's password: TYPE-THE-PASSWORD
Linux my.backup.server.com 2.6.22-14-generic #1 SMP Tue Dec 18 08:02:57 UTC 2007 i686

Last login: Thu Dec 27 16:35:04 2007 from localhost

This account is restricted by rssh.
This user is locked out.

If you believe this is in error, please contact your system administrator.

Connection to my.backup.server.com closed.

By default rssh configuration locks down everything including any sort of access.
Grant access to sftp and scp for all users

The default action for rssh to lock down everything. To grant access to scp or sftp open /etc/rssh.conf file:
# vi /etc/rssh.conf
Append or uncomment following two lines
allowscp
allowsftp

Save and close the file. rssh reads configuration file on fly (there is no rssh service exists). Now user should able to run scp and sftp commands, but no shell access is granted:
$ scp /path/to/file didi@my.backup.server.com:/.
OR
$ sftp didi@my.backup.server.com:/.
Output:

Connecting to lmy.backup.server.com...
didi@my.backup.server.com's password:
sftp> pwd
Remote working directory: /home/didi
sftp>

Understanding command configuration options

You need to add following keywords / directives to allow or disallow scp / sftp and other commands:

* allowscp : Tells the shell that scp is allowed.
* allowsftp : Tells the shell that sftp is allowed.
* allowcvs : Tells the shell that cvs is allowed.
* allowrdist : Tells the shell that rdist is allowed.
* allowrsync : Tells the shell that rsync is allowed.

Tip: Create a group for rssh users, and limit executable access to the binaries to users in that group to improve security. Please use standard file permissions carefully and appropriately.

- nixCraft - http://www.cyberciti.biz/tips -

Linux Configure rssh Chroot Jail To Lock Users To Their Home Directories Only

Posted By vivek On November 27, 2007 @ 1:28 pm In Security, Sys admin, Tips, UNIX, Ubuntu Linux | 5 Comments
[1] Next in series » »
[2] « « Previous in series

[3]

rssh support chrooting option. If you want to chroot users, use chrootpath option. It is used to set the directory where the root of the chroot jail will be located. This is a security feature.

A chroot on Linux or Unix OS is an operation that changes the root directory. It affects only the current process and its children. If your default home directory is /home/vivek normal user can access files in /etc, /sbin or /bin directory. This allows an attacker to install programs / backdoor via your web server in /tmp. chroot allows to restrict file system access and locks down user to their own directory.
Configuring rssh chroot

=> Chroot directory: /users.
Tip: If possible mount /users filesystem with the noexec/nosuid option to improve security.

=> Required directories in jail:

* /users/dev - Device file
* /users/etc - Configuration file such as passwd
* /users/lib - Shared libs
* /users/usr - rssh and other binaries
* /users/bin - Copy default shell such as /bin/csh or /bin/bash

=> Required files in jail at /users directory (default for RHEL / CentOS / Debian Linux):

* /etc/ld.so.cache
* /etc/ld.so.cache.d/*
* /etc/ld.so.conf
* /etc/nsswitch.conf
* /etc/passwd
* /etc/group
* /etc/hosts
* /etc/resolv.conf
* /usr/bin/scp
* /usr/bin/rssh
* /usr/bin/sftp
* /usr/libexec/openssh/sftp-server OR /usr/lib/openssh/sftp-server
* /usr/libexec/rssh_chroot_helper OR /usr/lib/rssh/rssh_chroot_helper (suid must be set on this binary)
* /bin/sh or /bin/bash (default shell)

Tip: Limit the binaries which live in the jail to the absolute minimum required to improve security. Usually /bin/bash and /bin/sh is not required but some system may give out error.
A note about jail file system

Note: The files need to be placed in the jail directory (such as /users) in directories that mimic their placement in the root (/) file system. So you need to copy all required files. For example, /usr/bin/rssh is located on / file system. If your jail is located at /users, then copy /usr/bin/rssh to /users/usr/bin/rssh. Following instuctions are tested on:

* FreeBSD
* Solaris UNIX
* RHEL / Redhat / Fedora / CentOS Linux
* Debian Linux

Building the Chrooted Jail

Create all required directories:
# mkdir -p /users/{dev,etc,lib,usr,bin}
# mkdir -p /users/usr/bin
# mkdir -p /users/libexec/openssh

Create /users/dev/null:
# mknod -m 666 /users/dev/null c 1 3
Copy required /etc/ configuration files, as described above to your jail directory /users/etc:
# cd /users/etc
# cp /etc/ld.so.cache .
# cp -avr /etc/ld.so.cache.d/ .
# cp /etc/ld.so.conf .
# cp /etc/nsswitch.conf .
# cp /etc/passwd .
# cp /etc/group .
# cp /etc/hosts .
# cp /etc/resolv.conf .
Open /usres/group and /users/passwd file and remove root and all other accounts.

Copy required binary files, as described above to your jail directory /users/bin and other locations:
# cd /users/usr/bin
# cp /usr/bin/scp .
# cp /usr/bin/rssh .
# cp /usr/bin/sftp .
# cd /users/usr/libexec/openssh/
# cp /usr/libexec/openssh/sftp-server .
OR
# cp /usr/lib/openssh/sftp-server .
# cd /users/usr/libexec/
# cp /usr/libexec/rssh_chroot_helper
OR
# cp /usr/lib/rssh/rssh_chroot_helper
# cd /users/bin/
# cp /bin/sh .
OR
# cp /bin/bash .
Copy all shared library files

The library files that any of these binary files need can be found by using the ldd / strace command. For example, running ldd against /usr/bin/sftp provides the following output:
ldd /usr/bin/sftp
Output:

linux-gate.so.1 =>  (0x00456000)
libresolv.so.2 => /lib/libresolv.so.2 (0x0050e000)
libcrypto.so.6 => /lib/libcrypto.so.6 (0x0013e000)
libutil.so.1 => /lib/libutil.so.1 (0x008ba000)
libz.so.1 => /usr/lib/libz.so.1 (0x00110000)
libnsl.so.1 => /lib/libnsl.so.1 (0x0080e000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x00a8c000)
libgssapi_krb5.so.2 => /usr/lib/libgssapi_krb5.so.2 (0x00656000)
libkrb5.so.3 => /usr/lib/libkrb5.so.3 (0x00271000)
libk5crypto.so.3 => /usr/lib/libk5crypto.so.3 (0x00304000)
libcom_err.so.2 => /lib/libcom_err.so.2 (0x00777000)
libdl.so.2 => /lib/libdl.so.2 (0x00123000)
libnss3.so => /usr/lib/libnss3.so (0x00569000)
libc.so.6 => /lib/libc.so.6 (0x00b6c000)
libkrb5support.so.0 => /usr/lib/libkrb5support.so.0 (0x00127000)
libkeyutils.so.1 => /lib/libkeyutils.so.1 (0x00130000)
/lib/ld-linux.so.2 (0x00525000)
libplc4.so => /usr/lib/libplc4.so (0x008c9000)
libplds4.so => /usr/lib/libplds4.so (0x00133000)
libnspr4.so => /usr/lib/libnspr4.so (0x00d04000)
libpthread.so.0 => /lib/libpthread.so.0 (0x0032a000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00341000)
libsepol.so.1 => /lib/libsepol.so.1 (0x00964000)

You need to copy all those libraries to /lib and other appropriate location. However, I recommend using my automated script called [4] l2chroot:
# cd /sbin
# wget -O l2chroot http://www.cyberciti.biz/files/lighttpd/l2chroot.txt
# chmod +x l2chroot
Open l2chroot and set BASE variable to point to chroot directory (jail) location:
BASE="/users"
Now copy all shared library files
# l2chroot /usr/bin/scp
# l2chroot /usr/bin/rssh
# l2chroot /usr/bin/sftp
# l2chroot /usr/libexec/openssh/sftp-server
OR
# l2chroot /usr/lib/openssh/sftp-server
# l2chroot /usr/libexec/rssh_chroot_helper
OR
# l2chroot /usr/lib/rssh/rssh_chroot_helper
# l2chroot /bin/sh
OR
# l2chroot /bin/bash
Modify syslogd configuration

The syslog library function works by writing messages into a FIFO file such as /dev/log. You need to pass -a /path/to/chroot/dev/log option. Using this argument you can specify additional sockets from that syslogd has to listen to. This is needed if you’re going to let some daemon run within a chroot() environment. You can use up to 19 additional sockets. If your environment needs even more, you have to increase the symbol MAXFUNIX within the syslogd.c source file. Open /etc/sysconfig/syslog file:
# vi /etc/sysconfig/syslog
Find line that read as follows:
SYSLOGD_OPTIONS="-m 0"
Append -a /users/dev/log
SYSLOGD_OPTIONS="-m 0 -a /users/dev/log"
Save and close the file. Restart syslog:
# /etc/init.d/syslog restart
If you are using Debian / Ubuntu Linux apply changes to /etc/default/syslogd file.
Set chroot path

Open configuration file /etc/rssh.conf:
# vi /etc/rssh.conf
Set chrootpath to /users
chrootpath=/users
Save and close the file. If sshd is not running start it:
# /etc/init.d/sshd start
Add user to jail

As explained eariler, [2] configure rssh user account. For example, add user vivek in chrooted jail with the following command:
# useradd -m -d /users/vivek -s /usr/bin/rssh vivek
# passwd vivek
Now vivek can login using sftp or copy files using scp:

sftp vivek@my-server.com
vivek@my-server.com's password:
sftp> ls
sftp> pwd
Remote working directory: /vivek
sftp> cd /tmp
Couldn't canonicalise: No such file or directory

User vivek is allowed to login to server to trasfer files, but not allowed to browse entier file system.

- nixCraft - http://www.cyberciti.biz/tips -

rssh: Per User Configuration Options For Chroot Jail

Posted By vivek On December 22, 2007 @ 12:00 am In Debian Linux, File system, FreeBSD, Howto, Linux, Networking, RedHat/Fedora Linux, Security, Suse Linux, Sys admin, Tuning, UNIX, Ubuntu Linux, User Management | 1 Comment
[1] « « Previous in series

[2]

rssh is a restricted shell for providing limited access to a host via ssh. It also allows system wide configuration and per user configuration. From the man page:
The user configuration directive allows for the configuration of options on a per-user basis. THIS KEYWORD OVERRIDES ALL OTHER KEYWORDS FOR THE SPECIFIED USER. That is, if you use a user keyword for user foo, then foo will use only the settings in that user line, and not any of the settings set with the keywords above. The user keyword’s argument consists of a group of fields separated by a colon (:), as shown below. The fields are, in order:

* username : The username of the user for whom the entry provides options
* umask : The umask for this user, in octal, just as it would be specified to the shell access bits. Five binary digits, which indicate whether the user is allowed to use rsync, rdist, cvs, sftp, and scp, in that order. One means the command is allowed, zero means it is not.
* path : The directory to which this user should be chrooted (this is not a command, it is a directory name).

rssh examples of configuring per-user options

Open /etc/rssh.conf file:
# vi /etc/rssh.conf
All user tom to bypass our chroot jail:
user=tom:077:00010
Provide jerry cvs access with no chroot:
user=jerry:011:00100
Provide spike rsync access with no chroot:
user=spike:011:10000
Provide tyke access with chroot jail located at /users
user="tyke:011:00001:/users" # whole user string can be quoted
if your chroot_path contains spaces, it must be quoted. Provide nibbles scp access with chroot directory:
user=nibbles:011:00001:"/usr/local/tv/shows/tom and jerry"

web servers

This book will explain configuration settings for apache, tomcat, jboss, php, etc.

building a secure redhat apache server

The purpose of this guide is to assist RedHat Linux users with the installation of server (SSL) certificates using the Apache web server. The goal is to provide a clear procedure that will save time and, in many cases, money!

First, I will cover what you need to know about the SSL protocol and digital certificates. In my experience, building an Apache web server with ModSSL and OpenSSL is the most beneficial software combination. OpenSSL is a general-purpose cryptography library that supports the SSL v2/v3 and TLS v1 protocols. ModSSL is an Apache API module designed to act as an interface between Apache and OpenSSL. The biggest advantage is that all three packages are free.

Then, beginning with Section 4, I will go through the step-by-step procedures for generating keys and installing certificates on a RedHat-Apache server compiled with ModSSL and OpenSSL. The procedures in Section 4 will also work with commercial SSL-server packages such as Stronghold and Raven that are closely related to Apache.

Disclaimer: I am a technical support engineer for Equifax Secure Inc., a Certificate Authority. Therefore, I use Equifax Secure certificates and examples geared towards installing Equifax Secure certificates. However, the instructions will also work with certificates issued by other Certificate Authorities. Since this document was written at my own initiative, Equifax Secure Inc. is neither liable nor accountable for any consequences resulting from the use of these procedures.

<!-- (your index root)!introduction -->

My comments to the reader is in this style (emphasized).

Example lines are in plain roman style.

Note that extra comments and advice is found in comments within the SGML source.

1.1 About Secure Sockets Layer (SSL)

SSL is a presentation layer service, located between the TCP and the application layer. It is platform and application independent. SSL is responsible for the management of a secure communications channel between the client and server. SSL provides a strong mechanism for encrypting data transferred between a client and a server.

1.2 FeedBack

Comments on this guide may be directed to the author (richard.sigle@equifax.com).

1.3 Copyrights and Trademarks

Copyright (c) 2001 by Richard L. Sigle

Please freely copy and distribute this document in any format. It's requested that corrections and/or comments be forwarded to the document maintainer. You may create a derivative work and distribute it provided that you:

  • Send your derivative work (in the most suitable format such as sgml) to the LDP (Linux Documentation Project) or the like for posting on the Internet. If not the LDP, then let the LDP know where it is available.
  • License the derivative work with this same license or use GPL. Include a copyright notice and at least a pointer to the license used.
  • Give due credit to previous authors and major contributors.

If you're considering making a derived work other than a translation, it's requested that you discuss your plans with the current maintainer.

<!-- (your index root)!news on -->

1.4 Acknowledgements and Thanks

I would like to thank Tony Villasenor for tirelessly reading my drafts and offering his input and advice. Without Tony, this document would never have been finished.

introduction to secure sockets layer/private key infrastructure

PKI is an asymmetric key system which consists of a public key (which is sent to clients) and a private key (stays local on the server). PKI differs from a symmetric key system in which both the client and server use the same key for encryption/decryption.

2.1 Responsibilities of SSL/PKI

SSL sets out to fulfill requirements that make it acceptable for use in the transmission of even the most sensitive of transactions, such as credit card information, medical records, legal documents, and e-commerce applications. Each application can choose to utilize some or all of the following criteria depending on the sensitivity and value of the transactions it will be processing.

Privacy

Let's say that a message is to be coded for transmission from A to B. A uses B's public key to encrypt the message. In this way B will be the only person who can decode and read this message using his private key. We cannot however be sure that A is the person who he claims to be.

Authenticity

In order to be sure that A is the person who he claims to be, we want guaranteed authenticity. This requires a slightly more complex coding process. In this case, A's message to B is first encrypted with A's private key and then with B's public key. B now has to decrypt it first with his private key and then with A's public key. Now B can be sure that A is who he claims to be as nobody else could create a message encrypted with his private key. SSL achieves this with the use of certificates (PKI). A certificate is issued by a neutral third party - such as a certificate authority (CA) - and includes a digital signature and/or a time stamp in addition to the public key of the certified party. A self-signed digital certificate can be created by anyone with the correct SSL tools, but self-signed certificates lack the weight of validation performed by a mutually respected neutral third party.

integrity

In SSL, integrity is guaranteed by using a MAC (Message Authentication Code) with the necessary hash table functions. Upon generation of a message, the MAC is obtained by applying a hash function and the result is then added to the message. After the message has been received, validity is then checked by comparing the message's embedded MAC with a new MAC computed from the received message. This would immediately reveal messages that have been altered by a third party.

Non-Repudiation

Non-repudiation protects both parties from each other during online transactions. It prevents one or the other from saying that they did not send a particular piece of information. Non-repudiation does not allow either party to alter the transaction after it has been made. Digital non-repudiation is the equivalent of signing a contract, in the traditional sense.

 

2.2 How SSL Works

The SSL protocol includes two sub-protocols: the SSL record protocol and the SSL handshake protocol. The SSL record protocol defines the format used to transmit data. The SSL handshake protocol involves using the SSL record protocol to exchange a series of messages between an SSL-enabled server and an SSL-enabled client when they first establish an SSL connection. This exchange of messages is designed to facilitate the following actions:

  • Authenticate the server to the client. The server certificate is signed by a Certificate Authority to insure that it is not corrupted and establishes a chain of trust.
  • Allow the client and server to select the cryptographic algorithms, or ciphers, that they both support.
  • Optionally authenticate the client to the server.
  • Use public-key encryption techniques to generate shared secrets.
  • Establish an encrypted SSL connection.

SSL Handshake Protocol

The Handshake Protocol is used to co-ordinate the state of the client and the server. During the handshake, the following events take place:

  • Certificates are exchanged between the client and server (asymmetric keys). The server sends its public key to the client. If the server is set to verify client authentication via a certificate, the client sends its public key to the server. The validity dates on the certificates are verified and they are checked for the digital signature of a trusted certificate authority. If the validity date and/or digital signature are not correct, the browser will issue a warning to the user. The user is then given the option to trust the certificate holder.
  • The client then generates a random key (symmetric key). These will be used for encryption and for calculating MACs. They are encrypted using the server's public key and sent to the server. Only the server has the ability to decrypt the new random key. The new symmetric key is used for encrypting the data that is sent between client and server.

    Note: The use of a symmetric key after server-browser authentication greatly enhances subsequent throughput performance.

  • A message encryption algorithm and a hash function for integrity are negotiated. This negotiation process could be carried out such that the client presents a list of supported algorithms to the server, which, in turn, selects the strongest cipher available to both of them. Identifiers for the chosen encryption algorithm and hash function are stored in the cipher spec field of the current state for use by the record protocol.
  • All of the following fields are set during handshaking: Protocol Version, Session ID, Cipher Suite, Compression Method and two random values ClientHello.random and ServerHello.random.

Note: An IP address is required for each SSL connection. Name based virtual hosts are resolved during the application layer. Remember Secure Sockets Layer resides below the application layer.

Session Key(Symmetric Code)

  • 40-bit, originally used only for export purposes
  • 56-bit, used by DES
  • 64-bit key - used by CAST, 256 times stronger than 56-bit
  • 80-bit key - used by CAST, 16 million times stronger than 56-bit (infeasible to break with current technology)
  • 128-bit key - used by CAST or RC2, exhaustive key search impossible now and for the foreseeable future

Public/Private Key Pair(Asymmetric Code)

  • 512-bit
  • 768-bit
  • 1024-bit
  • 2048-bit

2.3 How PKI Works

The client and the server each have a public key and a private key (the client's browser randomly creates a key pair for the SSL session, unless, a client certificate is held by the client and requested by the server).

The sender uses their private key to encrypt a message. This act authenticates the source of the message. The resulting cipher is encrypted once more with the receiving party's public key. This action provides confidentiality because only the receiving party is able to do the initial decryption of the message using their private key. The receiver uses the sender's public key to further decrypt the encrypted message. Because only the sender has access to their private key, the receiver is assured that the encrypted message originated from the sender.

A message digest is used to verify that neither party or a third party has tampered with or changed the message in any way. A message digest is obtained by applying a hash function (part of the private key known as the fingerprint) to the message. The digest (which is now known as the signature) is attached or appended to the message. The signature's length is constant (no matter how large the file is) and depends on what type of message digest the private key contains (md5 - 128 bit, sha1 - 160 bit, etc). Changing even one bit in the message will change the length of the signature and thus prove that the message has been tampered with.

2.4 Certificates(x509 Standard)

Digital certificates make it possible to trust an entity on the Internet. A digital certificate contains the user's credentials, which have been verified by a neutral third-party certificate authority.

A mathematical algorithm and a value (key) are used to encrypt data into an unreadable form. A second key is used to decrypt the data, using a complementary algorithm and a related value. The two keys must contain a related value and are known as a key pair.

Note: ITU-T Recommendation X.509 [CCI88c] specifies the authentication service for X.500 directories, as well as the X.509 certificate syntax. The certificate is signed by the issuer to authenticate the binding between the subject (user's) name and the user's public key. SSLv3 was adopted in 1994. The major difference between versions 2 and 3 is the addition of the extensions field. This field grants more flexibility as it can convey additional information beyond just the key and name binding. Standard extensions include subject and issuer attributes, certification policy information, and key usage restrictions.

An X.509 certificate consists of the following fields:

  • Version
  • serial number
  • signature algorithm ID
  • issuer name
  • validity period
  • subject (user) name
  • subject public key information
  • issuer unique identifier (version 2 and 3 only)
  • subject unique identifier (version 2 and 3 only)
  • extensions (version 3 only)
  • signature on the above fields

2.5 Digital Certificate Private Key

 

The private key is not embedded within a digital certificate. The private key does not include any server information. It contains encryption information and a fingerprint. It is generated locally on your system and should remain in a secure environment. If the private key is compromised, a perpetrator essentially has the code to your security system. The transmissions between client and server can be intercepted and decrypted. This type of vulnerability is why it is recommended to create a private key that is encrypted using triple DES technology. The file is then encrypted and password protected making it all but impossible to use without the correct pass phrase.

The security of a transaction is dependent on its private key. Should this key fall into the wrong hands then anyone can easily duplicate it and use it to compromise security. A compromised key could lead to messages meant for the server to be intercepted and manipulated by unscrupulous hackers. A fully secure system must be able to detect impostors and prevent the duplication of keys.

 

2.6 Digital Certificate Public Key

The public key is embedded in a digital certificate, which is sent by the server to a client when a secure connection is requested. This process identifies the server using the certificate. The public key validates the integrity, authenticity, and is also used to encrypt data to create a private data transmission.

 

2.7 Certificate Signing Request(CSR)

A CSR contains the information required by a certificate authority to create the certificate. The CSR contains an encrypted version of the private key's complimentary algorithm, common value, and information that identifies the server. This information includes, but is not limited to, country, state, organization, common name (domain name), and contact information.

working with certificates

The following section covers the steps involved in creating the private key file, certificate signing request, and a self-signed certificate. If you plan to obtain a certificate signed by a certificate authority, you will need to create a certificate signing request (CSR). Otherwise, you can create a self-signed certificate.

3.1 Create a Private Key

To create a private key, you must have the OpenSSL toolkit installed and configured with Apache. The following examples use the OpenSSL command line tool which is located in the /usr/local/ssl/bin directory by default. The examples assume that the directory containing the OpenSSL command line tool has been added to the $PATH.

To create a private key using the triple des encryption standard (recommended), use the following command:

openssl genrsa -des3 -out filename.key 1024

You will be prompted to enter and re-enter a pass phrase. If you choose to use triple des encryption, you will be prompted for the password each time you start the SSL server from a cold start. (When using the restart command, you will not be prompted for the password). Some of you may find this password prompt to be a nuisance, especially if you need to boot the system during off-hours. Or, you may believe that your system is already sufficiently secure. So, if you choose not to have a password prompt (hence no triple des encryption), use the command below. If you would rather create just a 512-bit key, then omit the 1024 at the end of the command and OpenSSL will default to 512 bits. Using the smaller key is slightly faster, but it is also less secure.

To create a private key without triple des encryption, use the following command:

openssl genrsa -out filename.key 1024

To add a password to an existing private key, use the following command:

openssl -in filename.key -des3 -out newfilename.key

To remove a password from an existing private key, use the following command:

openssl -in filename.key -out newfilename.key

Note: Your private key will be created in the current directory unless otherwise specified. There are 3 easy ways to deal with this. If OpenSSL is in your path, you can run it from the directory that you have designated to store your key files in (default is /etc/httpd/conf/ssl.key if you installed Apache using the RPM or /usr/local/apache/conf/ssl.key if you installed Apache using the source files). Another solution is to copy the files from the directory where they were created to the correct directory. And, last but not least, you can specify the path when running the command (eg. openssl genrsa -out /etc/httpd/conf/ssl.key/filename.key 1024). Doesn't matter how you do it as long as it gets done before you proceed.

For more information on the OpenSSL toolkit check out: OpenSSL Website.

3.2 Create a Certificate Signing Request

To obtain a certificate signed by a certificate authority, you will need to create a Certificate Signing Request (CSR). The purpose is to send the certificate authority enough information to create the certificate without sending the entire private key or compromising any sensitive information. The CSR also contains the information that will be included in the certificate, such as, domain name, locality information, etc.

  • Locate the private key that you would like to creat a CSR from. Enter the following command:

    openssl req -new -key filename.key -out filename.csr
  • You will be prompted for Locality information, common name (domain name), organizational information, etc. Check with the CA that you are applying to for information on required fields and invalid entries.
  • Send the CSR to the CA per their instructions.
  • Wait for your new certificate and/or create a self-signed certificate. A self-signed certificate can be used until you receive your certificate from the certificate authority.

Note: Use the following command to create a private key and request at the same time.

openssl genrsa -des3 -out filename.key 1024

3.3 Creating a Self-Signed Certificate

It is not necessary to create a self-signed certificate if you are obtaining a CA-signed certificate. However, creating a self-signed certificate is very simple. All you need is a private key and the name of the server (fully qualified domain name) that you want to secure. You will be prompted for information such as locality information, common name (domain name), organizational information, etc. OpenSSL gives you a great deal of freedom here. The only required field for the certificate to function correctly is the common name (domain name) field. If this is not present or incorrect, you will receive a Certificate Name Check warning from your browser.

To create a self-signed certificate:

openssl req -new -key filename.key -x509 -out filename.crt

3.4 Installing your Web Server Certificate

If you followed these instructions so far you shouldn't have any problems at this point. If you sent your CSR to a certificate authority and you have not gotten your certificate back yet, you can take a break now! If you are using a self-signed certificate, or you have received your certificate, you may continue.

  • Ensure that the private key file is in the directory that you have chosen to use. The following examples will be based on the RedHat RPM installation default of /etc/httpd/conf/ssl.key.
  • Ensure that the CA-signed or self-signed certificate is in its designated location. Again, I will be using the RPM default of /etc/httpd/conf/ssl.crt. If it is not there already, put it there.
  • If there is an intermediate (root) certificate to be installed, copy it to the /etc/httpd/conf/ssl.crt directory, also.
  • Now, you will be required to edit the httpd.conf file. Make a back-up of this file before you proceed to the next step, Configuring your Apache Server.

configuring your apache server

The Apache server must be configured with supplementary API modules in order to support SSL. There are many SSL software packages available. My examples are based on Apache configured with ModSSL and OpenSSL. There are countless mailing lists and newsgroups available to support these products. You may find these instructions helpful for some commercial SSL software packages that are based on the Apache web server.

A few things to keep in mind: You can have multiple virtual hosts on the same server. You can have numerous name-based virtual hosts on the same IP address. You can also have numerous name-based virtual hosts and one (1) secure virtual host on the same IP. But - you cannot have multiple secure virtual hosts on the same IP. The question that so many ask: Why? The answer is: SSL works below the application layer. Name based hosts are not defined until the application layer.

Specifically, you cannot have multiple secure virtual hosts on the same SOCKET (IP address + port). By default, a secure host will use port 443. You can change configure your virtual host to use a different port number with the same IP, thus creating another socket. There are many disadvantages to this approach. The most obvious disadvantage is that if you are not using the default port, your URL must also contain the port number to access the secure site.

Example:

  • Site using default port - www.something.com - would be accessed as https://www.something.com
  • A site using port 8888 would be accessed as https://www.something.com:8888

Another disadvantage is that if you introduce more ports, you will be providing more opportunities for port sniffing hackers. Last, if you select a port that is used by something else, you will create conflict problem.

 

4.1 Define a Secure Virtual Host

Setting up virtual hosts is fairly straightforward. I will go through the basics of setting up a secure virtual host.

In these examples, I use the .crt and .key file extensions. That is my personal way of avoiding confusion with the various files. With Apache, you can use any extension you choose - or no extension at all.

All of your secure virtual hosts should be contained within <IfDefine SSL> and </IfDefine SSL>, usually located towards the end of the httpd.conf file.

An example of a secure virtual host:

<VirtualHost 172.18.116.42:443>
DocumentRoot /etc/httpd/htdocs
ServerName www.somewhere.com
ServerAdmin someone@somewhere.com
ErrorLog /etc/httpd/logs/error_log
TransferLog /etc/httpd/logs/access_log
SSLEngine on
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
SSLCACertificateFile /etc/httpd/conf/ssl.crt/ca-bundle.crt
<Files ~ "\.(cgi|shtml)$">
SSLOptions +StdEnvVars
</Files>
<Directory "/etc/httpd/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
CustomLog /etc/httpd/logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

The directives that are the most important for SSL are the SSLEngine on, SSLCertificateFile, SSLCertificateKeyFile, and in many cases SSLCACertificateFile directives.

SSL Engine

"SSLEngine on" - this is ModSSL's command to start SSL.

SSLCertificateFile

SSLCertificateFile Tells Apache where to find the certificate file and what it is named. The example above shows "server.crt" as the certificate file name. This is the default that is added when you configure ModSSL with Apache. I personally don't recommend using the default names. Save yourself some frustration and name your certificates as servername.crt (domainname.crt). You may also decide to use an alternative directory than the default /etc/httpd/conf/ssl.crt or /usr/local/apache/conf/ssl.crt. Just remember to make the necessary changes to the path.

SSLCertificateKeyFile

SSLCertificateKeyFile tells Apache the name of the private key and where to find it. The directory defined here should have read/write permissions for root only. No one else should have access to this directory.

SSLCACertificateFile

The SSLCACertificateFile directive tells Apache where to find the Intermediate (root) certificate. This directive may or may not be necessary depending on the CA that you are using. This certificate is essentially a ring of trust.

Intermediate Certificate - A Certificate Authority obtains a certificate in much the same way as you. This is known as an intermediate certificate. It basically says that the holder of the intermediate certificate is whom they say they are and is authorized to issue certificates to customers. Web browsers have a list of "trusted" certificate authorities that is updated with each release. If a Certificate authority is fairly new, its intermediate certificate may not be in the browser's list of trusted CA's. Combine this with the fact that most people don't update their browsers very often; it could take years before a CA is recognized as trusted automatically. The solution is to install the intermediate certificate on the server using the SSLCACertificateFile directive. Usually, a "trusted" CA issues the intermediate certificate. If it is not, then you may need to use the SSLCertificateChainFile directive, although this is unlikely.

4.2 Certificate Examples

Server Certificate File

-----BEGIN CERTIFICATE-----
MIIC8DCCAlmgAwIBAgIBEDANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTkwNTI1
MDMwMDAwWhcNMDIwNjEwMDMwMDAwWjBTMQswCQYDVQQGEwJVUzEbMBkGA1UEChMS
RXF1aWZheCBTZWN1cmUgSW5jMScwJQYDVQQDEx5FcXVpZmF4IFNlY3VyZSBFLUJ1
c2luZXNzIENBLTIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYna8GjS9mG
q4Cb8L0VwDBMZ+ztPI05urQb8F0t1Dp4I3gOFUs2WZJJv9Y1zCFwQbQbfJuBuXmZ
QKIZJOw3jwPbfcvoTyqQhM0Yyb1YzgM2ghuv8Zz/+LYrjBo2yrmf86zvMhDVOD7z
dhDzyTxCh5F6+K6Mcmmar+ncFMmIum2bAgMBAAGjYjBgMBIGA1UdEwEB/wQIMAYB
Af8CAQAwSgYDVR0lBEMwQQYIKwYBBQUHAwEGCCsGAQUFBwMDBgorBgEEAYI3CgMD
BglghkgBhvhCBAEGCCsGAQUFBwMIBgorBgEEAYI3CgMCMA0GCSqGSIb3DQEBBAUA
A4GBALIfbC0RQ9g4Zxf/Y8IA2jWm8Tt+jvFWPt5wT3n5k0orRAvbmTROVPHGSLw7
oMNeapH1eRG5yn+erwqYazcoFXJ6AsIC5WUjAnClsSrHBCAnEn6rDU080F38xIQ3
j1FBvwMOxAq/JR5eZZcBHlSpJad88Twfd7E+0fQcqgk+nnjH
-----END CERTIFICATE-----

 

Contents of the Certificate File

Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1516 (0x5ec)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=US, O=Equifax Secure Inc, CN=Equifax Secure E-Business CA
Validity
Not Before: Jul 12 15:21:01 2000 GMT
Not After : Jun 2 22:42:34 2001 GMT
Subject: C=us, ST=ga, L=atlanta, O=Equifax, OU=Rick, CN=172.18.116.44/Email=richard.sigle@equifax.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c8:eb:93:26:97:ca:00:ce:4c:e4:f3:fd:43:31:
cd:53:ed:b4:8a:ad:93:84:dc:7a:48:39:b5:28:57:
03:7f:a9:ac:3e:58:6a:7a:e3:52:3e:1e:52:58:a2:
6f:23:ad:bb:84:d8:88:ed:6d:a5:da:08:6b:c8:6c:
a5:4c:34:67:d8:46:1c:ca:20:50:b0:e8:54:7f:ca:
5e:ef:09:ff:6e:8d:a6:2b:02:f5:54:0f:c2:d0:45:
12:ad:66:e7:8b:dd:68:be:64:a4:9b:69:bd:a4:1a:
5e:ef:09:ff:6e:8d:a6:2b:02:f5:54:0f:c2:d0:45:
12:ad:66:e7:8b:dd:68:be:64:a4:9b:69:bd:a4:1a:
5a:2f:3b:6e:73:84:d8:d6:17:bd:12:39:34:fa:3d:
d8:a9:e8:59:3c:c2:61:c5:b3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
Netscape Cert Type:
SSL Server
X509v3 Authority Key Identifier:
keyid:5B:E0:A8:75:1C:78:02:47:71:AB:CE:27:32:E7:24:88:42:28:48:56
Signature Algorithm: md5WithRSAEncryption
87:53:74:e9:e1:a6:10:56:8c:fa:63:0e:7b:72:ff:76:4b:79:
0e:49:2a:58:ed:71:7a:bf:77:61:fa:e8:74:04:37:8c:d3:6a:
9a:3d:80:76:7a:c3:64:30:e7:1b:40:25:4e:2a:81:8b:e5:ac:
76:a4:38:67:cc:3f:93:43:e1:1d:c3:8d:ba:ed:cc:d7:aa:a4:
ab:d3:84:77:7c:8f:26:f6:dd:ba:3b:6a:99:81:e1:9e:7e:0f:
ca:a6:ff:c0:c3:59:6e:dc:a6:03:23:bf:8f:24:ff:15:ad:ac:
0d:85:fc:38:bf:d1:24:2d:1a:d3:72:55:12:95:5f:65:f0:60:
df:b1

 

Private Key File

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,124F61450D85A480

ELz64SV+tFSRybsHjY9NH7CP7yDHXP6xcd9FY6MVgQykTkq2h0n7j+tmpfUPbStT
6jCgm/dTYM9mpkQ3jYZBALiVD5JNJ9t1dWisxQXY/nsak8LSTN7LhUtZSfk5xSmV
Zsl4gwQS20UdBzFiJ+4qDajP/pzocSdSuQvxIHq7UzNwJsW8UYxR3I1qrDgyNXKS
db41BWH4QdNtE0p+pi9VndDzXktqZGHEvtrQTV+39DV/dwOdnGBpYBETljMO5X6t
D42xcVs0Doa1vZ6PiMCkwFNPXsPlKHZtHwEL4I3CQdiH4E0oYh3klBzlXBY4YldN
A+s4xU44FpXp5xwt9nnVPUKHPo+NpdaRK7dAcRNO3GN3+ek1ggzvEjjuWKes3RQh
PlHPuF7VWo4KeaTfTIwJWfGxz4nvwlVByPJ6Z73Mn0VcDXCkVm6+h3PLlYL0FMqM
baUyQPpw6bhfW71FO/IIQxz3R1EqkxW7OHv74uuYl8kjHXf3S6qRZEGUG/zOGLGr
mI5s2qnU69HlBObFkc6WQq0QxMq4PiUi7HhCLMkH8+wBsNNMnb75+7lQKkEhdOeE
iUMKe5kgQqfd9w8jsBH5nu+J/nCfvPdp0isQW+P3/Rrh6YMwdKnlVfNZWdGiTzpQ
ngThAGq5lit4uf4zdTIYYrs+T9I5ltjj0KgCUD4VL5/7OfnR3gcphpbHXQf0E2cz
Qwq7q7ppKwCf/x92pHi8oVevlV5Dx9NQbGhEOA5pooqD6S2xZBbPLzkUKWDEO2il
oBZ5L1jClR5jjdF2U61w7aRrL0t6luDU/aRv/fcoYes=
-----END RSA PRIVATE KEY-----

 

Contents of the Private Key

read RSA key
Enter PEM pass phrase:
Private-Key: (1024 bit)
modulus:
00:c8:eb:93:26:97:ca:00:ce:4c:e4:f3:fd:43:31:
cd:53:ed:b4:8a:ad:93:84:dc:7a:48:39:b5:28:57:
03:7f:a9:ac:3e:58:6a:7a:e3:52:3e:1e:52:58:a2:
6f:23:ad:bb:84:d8:88:ed:6d:a5:da:08:6b:c8:6c:
a5:4c:34:67:d8:46:1c:ca:20:50:b0:e8:54:7f:ca:
5e:ef:09:ff:6e:8d:a6:2b:02:f5:54:0f:c2:d0:45:
12:ad:66:e7:8b:dd:68:be:64:a4:9b:69:bd:a4:1a:
5a:2f:3b:6e:73:84:d8:d6:17:bd:12:39:34:fa:3d:
d8:a9:e8:59:3c:c2:61:c5:b3
publicExponent: 65537 (0x10001)
privateExponent:
00:b6:57:7d:3b:58:24:1e:a9:1b:85:e9:9c:9e:5f:
d3:3d:69:0c:21:93:37:bf:2b:2c:da:e1:6c:74:48:
cb:c7:0f:60:5f:50:74:8a:44:45:be:54:5c:5d:4e:
45:58:f6:f1:a8:b5:af:46:f2:ec:c2:bc:43:bd:28:
44:b7:ad:13:d3:ca:de:59:24:e8:fa:f8:e5:5f:45:
38:2c:a0:a3:de:98:13:d8:80:38:e1:47:53:4c:ea:
e4:66:c3:82:93:89:c3:90:83:44:e1:13:4f:74:76:
e2:c0:89:97:77:5f:33:d8:7d:27:21:52:55:c2:d7:
dc:01:f9:bc:21:8d:a3:f5:c1
prime1:
00:e3:2d:6b:5e:05:6b:e1:46:e6:ab:ae:f3:8b:d0:
5f:94:5c:6f:f5:47:46:1d:4e:66:d3:7e:98:18:e0:
2c:0d:08:ca:b7:29:72:af:53:62:30:ec:be:26:1f:
cc:5a:ed:65:62:65:70:1e:18:19:61:e3:77:00:a7:
3a:9e:4e:12:93
prime2:
00:e2:69:56:78:e8:39:ff:17:db:cc:39:d7:7f:70:
41:dc:c5:59:43:16:c1:84:4c:ae:e7:5d:8a:c5:4b:
da:88:8e:03:99:7c:88:f2:8a:13:31:57:44:e0:b5:
c8:0a:60:b0:05:de:f6:9e:f2:00:ec:37:21:8d:3b:
dc:8e:c9:d4:61
exponent1:
1a:ad:6a:be:4f:c4:ab:5f:b8:16:d1:24:a8:76:7f:
c2:dc:58:09:65:a5:46:2b:be:c7:77:46:45:25:8e:
06:b9:d1:94:50:b9:b6:fd:03:ba:db:12:39:47:e2:
a7:8a:d9:2d:04:dc:75:ac:3e:ce:cf:f7:59:8c:49:
c5:ed:45:21
exponent2:
2d:4e:fd:32:06:ef:0c:40:7f:08:d8:8e:6a:7f:51:
7e:d7:b3:6c:3c:92:8f:62:35:22:31:d3:02:76:92:
8d:ff:35:73:32:bb:c9:25:9e:7f:a2:42:33:61:cd:
5d:5e:49:fb:72:ca:11:b6:c6:3e:7f:2d:e4:b0:95:
0b:b2:12:21
coefficient:
50:52:09:22:cb:fb:b2:b8:58:85:ab:1d:82:b9:6e:
d0:f6:dc:e8:ce:a6:5d:a1:ff:c8:4d:3b:2b:1c:19:
64:f0:c4:4a:bc:b2:1d:2b:2d:09:59:83:a3:9a:89:
f8:db:2c:2c:8a:bd:fd:a3:16:51:76:aa:ce:ea:85:
6b:1c:9f:f7

 

4.3 Restart the Web Server

The script to restart the webserver may be located in /usr/local/sbin, /usr/sbin, (where the script is called httpd) or /usr/local/apache/bin (where the script is called apachectl). If you are not running the server with SSL enabled, you will need to stop and start the server. You may also write your own customized scripts to start, restart, and stop your server. As long as it starts the SSL engine, you should be OK.

The commands are:

httpd stop
httpd startssl
httpd restart

or

apachectl stop
apachectl startssl
apachectl restart

 

building a secure redhat apache server - troubleshooting

Here are some common problems that may arise.

5.1 Server Appears to start, but you cannot access the secure site

Check the error_log file. If you did not set your virtual host to write to an error log, you may want to reconsider. The example SSL virtual host writes to an error log file. Most likely you will have a few warnings and an error at the end of the log that basically say that the private key does not match the certificate. Example:

[Tue Nov 21 09:09:02 2000] [notice] Apache/1.3.14 (Unix) mod_ssl/2.7.1
OpenSSL/0.9.6 configured -- resuming normal operations
[Tue Nov 21 09:09:16 2000] [notice] caught SIGTERM, shutting down
[Tue Nov 21 14:39:54 2000] [notice] Apache/1.3.14 (Unix) mod_ssl/2.7.1
OpenSSL/0.9.6 configured -- resuming normal operations
[Tue Nov 21 14:40:31 2000] [notice] caught SIGTERM, shutting down
[Tue Nov 21 14:43:53 2000] [error] mod_ssl: Init: (esi.fin.equifax.com:443)
Unable to configure RSA server private key (OpenSSL library error follows)
[Tue Nov 21 14:43:53 2000] [error] OpenSSL: error:0B080074:x509 certificate
routines:X509_check_private_key:key values mismatch

If you get the error messages above, chances are the key and certificate do not match. Make sure you aren't using the default server.key file. You should also check the httpd.conf file to make sure that the directives are pointing to the correct private key and certificate.

You can check to make sure that you your private key and certificate are in the correct format and match each other. To do this, give the commands below to decrypt the private key in one terminal window and decrypt the certificate in the other. What you will be comparing are the Modulus and the Exponent of each key. If the modulus and exponent from the key matches the set from the certificate, you have just confirmed that your certificate and key are correctly paired.

If all else fails, create a new private key, CSR or self-signed certificate. Before you do this, check your CA's re-issue policy. You may be charged for a re-issue.

To view the contents of the certificate:

openssl x509 -noout -text -in filename.crt

To view the contents of the private key:

openssl rsa -noout -text -in filename.key

 

5.2 Certificate Name Check Warning is issued by the client's browser

The most common cause for this is omitting the "www" at the beginning of the domain name when creating the CSR. The name defined by the "ServerName" directive for that virtual host must match the domain name presented by the certificate exactly or the browser will let the client know. The exception is a wild card certificate. A wild card certificate's domain name field would look like *.somedomain.com. This enables you to use one certificate for any number of sub-domains of somedomain.com (e.g. host1.somedomain.com and host2.somedomain.com).

 

5.3 Certificate was Signed by an Untrusted Certificate Authority Warning is issued by the client's browser

If you are using a self-signed certificate, you will get this warning. Your clients will be given the option to trust your certificate or not. If you have a CA signed certificate and are getting the untrusted warning, you probably need to install their intermediate (root) certificate.

 

5.4 SSLEngine on is an un-recognized command (when starting Apache)

This error message is issued if you do not have ModSSL compiled with Apache. Some SSL packages use a different directive to start SSL within a virtual host. If you are using a package that does use a different directive, you will also receive this error message.

 

5.5 You have forgotten your "PEM Passphrase" and you would like to know how to reset it

There is no way to reset this passphrase. The only solution is to remember the passphrase or create a new private key. You will then need to obtain a new certificate or create a new self-signed certificate.

 

apache tomcat

This book is for installation and configuration of Tomcat

Installing apache and tomcat on redhat enterprise linux 4

1.0 Introduction

Java servlets are a powerful tool for building websites and web based applications. One skill that every Java web developer should have is the ability to install and configure the Tomcat servlet engine. Many thanks to the Apache Software Foundation for providing this mature, stable, open source software. It was recently voted the Best Application Server of 2003 by InfoWorld readers.

This article discusses how to integrate Tomcat with the Apache web server on Red Hat Linux 9 or Red Hat Enterprise Linux 3. The goal is to provide a simple, stable configuration that will allow users to gain confidence using Tomcat in a development environment. Setting up a production Tomcat server is outside the scope of this article.

Please note the following conventions:

  • All commands are issued as root unless otherwise noted.
  • {YOUR_DOMAIN} and {YOUR_APPLICATION} are placeholder values that should be customized to your setup. For example, {YOUR_DOMAIN} might be "localhost.test" and {YOUR_APPLICATION} might be "test".

2.0 Installing Apache

I chose to install Apache using the Red Hat RPM. Using the RPM instead of compiling Apache from source simplifies system administration in the following ways:

  • Updates and bug fixes can be installed automatically from the Red Hat Network.
  • Startup and shutdown scripts are already configured and available.

I recommend using the Red Hat up2date command line utility to install Red Hat RPMs. It eliminates a multitude of headaches by ensuring the software you install is the correct version and you have the right dependencies installed on your system.

Install the following Red Hat RPMs if they are not already installed:

  • httpd: the Apache web server
  • httpd-devel: development tools that will be needed to create the mod_jk connector

To install these packages using up2date, make sure you are connected to the Internet, and enter the following:

up2date -i httpd httpd-devel

You should now be able to start/stop/restart Apache as follows:

service httpd start
service httpd stop
service httpd restart

Verify that Apache is working by starting Apache and typing http://localhost/ into your browser. You should see the default Apache install page with links to documentation.

3.0 Installing Tomcat

The only requirements to run Tomcat are that a Java Development Kit (JDK), also called a Java Software Development Kit (SDK), be installed and the JAVA_HOME environment variable be set.

3.1 Java SDK

I chose to install Sun's Java 2 Platform, Standard Edition, which can be downloaded from http://java.sun.com/j2se/). I chose the J2SE v1.4.2 SDK Linux self-extracting binary file.

Change to the directory where you downloaded the SDK and make the self-extracting binary executable:

chmod +x j2sdk-1_4_2-linux-i586.bin

Run the self-extracting binary:

./j2sdk-1_4_2-linux-i586.bin

There should now be a directory called j2sdk1.4.2 in the download directory. Move the SDK directory to where you want it to be installed. I chose to install it in /usr/java. Create /usr/java if it doesn't exist. Here is the command I used from inside the download directory:

mv j2sdk1.4.2 /usr/java

Set the JAVA_HOME environment variable, by modifying /etc/profile so it includes the following:

JAVA_HOME="/usr/java/j2sdk1.4.2"
export JAVA_HOME

/etc/profile is run at startup and when a user logs into the system, so you will need to log out and log back in for JAVA_HOME to be defined.

exit
su -

Check to make sure JAVA_HOME is defined correctly using the command below. You should see the path to your Java SDK.

echo $JAVA_HOME

3.2 Tomcat Account

You will install and configure Tomcat as root; however, you should create a dedicated group and user account for Tomcat to run under as follows:

groupadd tomcat
useradd -g tomcat tomcat

3.3 Download Tomcat

Download the latest release binary build from http://www.apache.org/dist/jakarta/tomcat-5/. Since Tomcat runs directly on top of a standard JDK, I cannot think of any reason to building it from source. There are a number of different download formats. I chose the gnu zipped tar file (jakarta-tomcat-5.0.28.tar.gz).

3.4 Tomcat Standalone

Unzip Tomcat by issuing the following command from your download directory:

tar xvzf jakarta-tomcat-5.0.28.tar.gz

This will create a directory called jakarta-tomcat-5.0.28. Move this directory to wherever you would like to install Tomcat. I chose /usr/local. Here is the command I issued from inside the download directory:

mv jakarta-tomcat-5.0.28 /usr/local/

The directory where Tomcat is installed is referred to as CATALINA_HOME in the Tomcat documentation. In this installation CATALINA_HOME=/usr/local/jakarta-tomcat-5.0.28.

I recommend setting up a symbolic link to point to your current Tomcat version. This will save you from having to make changes to startup and shutdown scripts each time you upgrade Tomcat. It also allows you to keep several versions of Tomcat on your system and easily switch amongst them. Here is the command I issued from inside /usr/local to create a symbolic link called /usr/local/jakarta-tomcat that points to /usr/local/jakarta-tomcat-5.0.28:

ln -s jakarta-tomcat-5.0.28 jakarta-tomcat

Change the group and owner of the /usr/local/jakarta-tomcat and /usr/local/jakarta-tomcat-5.0.28 directories to tomcat:

chown tomcat.tomcat /usr/local/jakarta-tomcat
chown -R tomcat.tomcat /usr/local/jakarta-tomcat-5.0.28

It is not necessary to set the CATALINA_HOME environment variable. Tomcat is smart enough to figure out CATALINA_HOME on its own.

You should now be able to start and stop Tomcat from the CATALINA_HOME/bin directory by typing ./startup.sh and ./shutdown.sh respectively. Test that Tomcat is working by starting it and typing http://localhost:8080 into your browser. You should see the Tomcat welcome page with links to documentation and sample code. Verify Tomcat is working by running some of the examples.

4.0 Installing the Connector

4.1 Connector Benefits

At this point, Apache and Tomcat should be working separately in standalone mode. You can run Tomcat in standalone mode as an alternative to Apache. In fact, in some cases, it is said that Tomcat standalone is faster than serving static content from Apache and dynamic content from Tomcat. However, there are the following compelling reasons to use Apache as the front end:

  1. You can use Apache to buffer slow connections. Tomcat uses java.io, which uses a thread for each request, so Tomcat can run out of connections as the number of slow requests grows. This could be an issue if your application supports a large number of dial-up users.
  2. You can use a connector such as mod_jk to load balance amongst several Tomcat instances.
  3. You can take advantage of Apache features such as cgi and PHP.
  4. You can take advantage of Apache modules such as mod_rewrite, mod_headers, and mod_expire.
  5. You can isolate virtual hosts in their own Tomcat instances.

The increased functionality obtained by using Apache on the front end can outweigh the effort required to install and configure a connector.

4.2 Selecting a Connector

Development on the mod_jk2 connector was discontinued on 11/15/2004; therefore, you no longer have to decide between the mod_jk and mod_jk2 connectors. Use the mod_jk connector. It has been around a long while and is very stable.

4.3 Building the mod_jk Connector

The mod_jk connector is the communication link between Apache and Tomcat. It listens on a defined port for requests from Apache and forwards those requests to Tomcat.

Install the following Red Hat RPMs if they are not already installed:

  • libtool
  • automake
  • autoconf

Download the jk connector source from http://www.apache.org/dist/jakarta/tomcat-connectors/jk/. I used jakarta-tomcat-connectors-1.2.8-src.tar.gz.

Unzip the contents of the file into your download directory as follows:

tar xvzf jakarta-tomcat-connectors-1.2.8-src.tar.gz

This will create a folder called jakarta-tomcat-connectors-1.2.8-src. Move this folder to wherever you store source files on your system. I chose /usr/src. Here is the command I issued from inside the download directory:

mv jakarta-tomcat-connectors-1.2.8-src /usr/src

I refer to the folder where the connector source is installed as CONN_SRC_HOME. In my case CONN_SRC_HOME = /usr/src/jakarta-tomcat-connectors-1.2.8-src.

Change to directory CONN_SRC_HOME/jk/native and run the buildconf.sh script as follows:

./buildconf.sh

This will create the CONN_SRC_HOME/jk/native/configure file. Run the configure script with the path to the apxs file on your system. If you installed Apache using the Red Hat RPM, apxs should be located at /usr/sbin/apxs.

./configure --with-apxs=/usr/sbin/apxs

Build mod_jk with the following command:

make

If you see missing object errors, try this alternate command:

make LIBTOOL=/etc/httpd/build/libtool

If all went well, the mod_jk.so file was successfully created. Manually copy it to Apache's shared object files directory:

cp CONN_SRC_HOME/jk/native/apache-2.0/mod_jk.so /etc/httpd/modules

5.0 Creating the Application Directories

Both Apache and Tomcat application files will be installed under the /home/tomcat/webapps directory. This setup will allow you to easily upgrade Tomcat and back up your application files.

Create your application directories as follows:

mkdir /home/tomcat/webapps
mkdir /home/tomcat/webapps/{YOUR_DOMAIN}
mkdir /home/tomcat/webapps/{YOUR_DOMAIN}/logs
mkdir /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}
mkdir /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}/WEB-INF
mkdir /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}/WEB-INF/classes

Set directory permissions as follows:

chmod 755 /home/tomcat/webapps
chmod 755 /home/tomcat/webapps/{YOUR_DOMAIN}
chmod 755 /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}

6.0 Configuring Tomcat

6.1 workers.properties

The workers.properties file contains information so mod_jk can connect to the Tomcat worker processes.

Place the following workers.properties file in the /etc/httpd/conf directory:

# workers.properties - ajp13
#
# List workers
worker.list=wrkr
#
# Define wrkr
worker.wrkr.port=8009
worker.wrkr.host=localhost
worker.wrkr.type=ajp13
worker.wrkr.cachesize=10
worker.wrkr.cache_timeout=600
worker.wrkr.socket_timeout=300

Notes

  1. There is an example workers.properties file located in the CONN_SRC_HOME/jk/conf directory. The example file provides a lot of useful information and insight into the workers.properties file, but it contains so much information that it can be confusing. I recommend using it as a learning tool but creating your own workers.properties file from scratch.
  2. The configuration above assumes Apache and Tomcat are located on the same box and requests are forwarded to Tomcat using type ajp13 workers. Type ajp13 workers forward requests to out-of-process Tomcat workers using the ajpv13 protocol over TCP/IP sockets.
  3. The name of the worker in the JkMount directive in httpd.conf must match the name of the worker in worker.list ("wrkr" in the configuration above).

6.2 server.xml

The CATALINA_HOME/conf/server.xml file contains Tomcat server configuration information. The default server.xml is great for verifying that Tomcat works in standalone mode and for viewing the examples that come with the application, but it contains so much information that it can be confusing. I recommend saving it for future reference and creating a new server.xml.

Save the default server.xml as follows:

mv CATALINA_HOME/conf/server.xml CATALINA_HOME/conf/server.xml.orig

Copy the following into a new server.xml file:

<Server port="8005" shutdown="0fbb9aebcbfbef203eca71b6be367859" debug="0">

<Service name="Tomcat-Apache">

<Connector address="127.0.0.1"
port="8009"
minProcessors="5"
maxProcessors="75"
enableLookups="false"
protocol="AJP/1.3"
debug="0"/>

<Engine name="appserver"
debug="0"
defaultHost="{YOUR_DOMAIN}">

<Host name="{YOUR_DOMAIN}"
appBase="/home/tomcat/webapps"
autoDeploy="false"
deployOnStartup="false"
unpackWARs="false"
deployXML="true"
debug="0"/>

</Engine>

</Service>

</Server>

If you do keep the default server.xml, make sure you comment out any other connectors besides mod_jk that are listening on port 8009. The default file comes with the Coyote/JK2 connector enabled for the Tomcat-Standalone service. This will conflict with the mod_jk connector in your Tomcat-Apache service. You should comment this connector out. It isn't needed when you connect directly to Tomcat in standalone mode (port 8080), so I'm not sure why this connector is enabled by default.

The Connector address defines the interface that Tomcat will listen on for mod_jk requests from Apache. In my configuration, Apache and Tomcat reside on the same box, so I have set the address to the loopback address. The default is for Tomcat to listen on all interfaces, so restricting it to the loopback interface improves security.

The Server shutdown property is the text string that is sent over a socket connection to stop Tomcat. The default value is "SHUTDOWN". The shutdown port is always on the loopback interface, which provides host-level protection. However, there is the possibility that the host could be compromised and someone could send the command SHUTDOWN to all ports and knock Tomcat offline. To prevent this, replace the default value with one that is difficult to guess. Do not use the example string above. Create your own by feeding random bytes into md5sum as follows:

head -1024c /dev/random | md5sum

Change the permissions on server.xml to prevent unprivileged users from reading the shutdown string:

chmod 600 CATALINA_HOME/conf/server.xml

6.3 Configuring the Context

It is recommended that contexts be defined in separate files, not in server.xml. The context configuration directory has the same name as the Engine in server.xml.

Create the context configuration directory as follows:

mkdir CATALINA_HOME/conf/appserver

The host context configuration directory has the same name as the corresponding Host in server.xml.

Create the context configuration directory for your domain as follows:

mkdir CATALINA_HOME/conf/appserver/{YOUR_DOMAIN}

Create the context configuration file as follows:

touch CATALINA_HOME/conf/appserver/{YOUR_DOMAIN}/{YOUR_APPLICATION}.xml

Copy the following text into {YOUR_APPLICATION}.xml:

<Context path=""
docBase="{YOUR_APPLICATION}"
reloadable="true"
debug="0"/>

Setting the Context reloadable property to true tells Tomcat to automatically load new and changed application class files found in /WEB-INF/classes and /WEB-INF/lib. This feature is very useful during development. However, it is recommended to set reloadable to false in production environments because monitoring class file changes requires significant server resources.

6.4 log4j

Download the latest log4j and install log4j.jar in CATALINA_HOME/common/lib.

Download the latest commons logging and install commons-logging.jar in CATALINA_HOME/common/lib.

Create a file called log4j.properties as follows and place it in the CATALINA_HOME/common/classes directory:

log4j.rootLogger=WARN, R
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=/usr/local/jakarta-tomcat/logs/tomcat.log
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{DATE} - %p %c - %m%n
log4j.logger.org.apache.catalina=WARN, R

7.0 Configuring Apache

Apache is configured with directives placed in the main Apache configuration file, /etc/httpd/conf/httpd.conf. In addition, Apache 2 has configuration files for perl, php, and ssl located in /etc/httpd/conf.d/.

Rename the /etc/httpd/conf.d/ssl.conf file to ssl.conf.bak. The default Red Hat Apache 2 installation comes with ssl support enabled. If ssl is needed, you can re-enable it after you have successfully integrated Apache and Tomcat.

7.1 httpd.conf

You will notice that there are three sections labeled in the httpd.conf file supplied by Red Hat: (1) Global Environment, (2) Main Server Configuration, and (3) Virtual Hosts.

Add the following to the bottom of the existing LoadModule directives in the Global Environment section:

LoadModule jk_module modules/mod_jk.so

Add the following to the bottom of the Main Server Configuration section:

JkWorkersFile "/etc/httpd/conf/workers.properties"
JkLogFile "/etc/httpd/logs/mod_jk.log"
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

Set up a Virtual Host directive in the Virtual Hosts section of httpd.conf. Below is an example of how to set up the {YOUR_DOMAIN} website so Tomcat handles all jsp pages and requests with "servlet" in the path:

NameVirtualHost 127.0.0.1:80

<VirtualHost 127.0.0.1:80>
ServerAdmin webmaster@{YOUR_DOMAIN}
ServerName {YOUR_DOMAIN}
DocumentRoot /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}
ErrorLog /home/tomcat/webapps/{YOUR_DOMAIN}/logs/error_log
CustomLog /home/tomcat/webapps/{YOUR_DOMAIN}/logs/access_log common
JkMount /*.jsp wrkr
JkMount /servlet/* wrkr
# Deny direct access to WEB-INF
<LocationMatch ".*WEB-INF.*">
AllowOverride None
deny from all
</LocationMatch>
</VirtualHost>

The argument for the NameVirtualHost directive must match exactly the argument for the VirtualHost directive (127.0.0.1:80).

The JkMount directive specifies url patterns of requests that will be forwarded to Tomcat for processing.

You can test your Apache configuration by typing the following:

httpd -t -D DUMP_VHOSTS

You should get something like the following response:

127.0.0.1:80           is a NameVirtualHost
default server {YOUR_DOMAIN} (/etc/httpd/conf/httpd.conf:1056)
port 80 namevhost {YOUR_DOMAIN} (/etc/httpd/conf/httpd.conf:1056)
Syntax OK

8.0 Setting Up {YOUR_DOMAIN}

{YOUR_DOMAIN} does not need to be a domain name with a DNS entry. For testing purposes, you can set up any domain you want in the /etc/hosts file of the machine that you will be using to access your application.

The example below shows the entry for {YOUR_DOMAIN} when running Apache and Tomcat on a single machine, typical for a development computer.

127.0.0.1	{YOUR_DOMAIN}

9.0 Testing Apache

We will create and install a simple Hello World html page so we can test to make sure Apache handles requests for static html pages.

9.1 Hello World HTML

Copy the following text into a file called HelloWorld.html and install the file in the /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION} directory.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello World HTML!</title>
</head>
<body>
<h1>Hello World HTML!</h1>
</body>
</html>

If Apache has not been restarted since you added your virtual host, do so as follows:

service httpd restart

You should now be able to type http://{YOUR_DOMAIN}/HelloWorld.html into your browser and see the always-exciting "Hello World" message.

10.0 Testing Tomcat

We will create and install a simple Hello World jsp page and servlet so we can test to make sure Apache forwards servlet requests to Tomcat for handling.

10.1 Hello World JSP

Copy the following text into a file called HelloWorld.jsp and install the file in the /home/tomcat/webapps/{YOUR_DOMAIN} directory.

<%@ page contentType="text/html;charset=WINDOWS-1252"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Hello World JSP</title>
</head>
<body>
<h1><% out.println(" Hello World JSP!"); %></h1>
</body>
</html>

10.2 Hello World Servlet

Copy the following into a file called HelloWorld.java:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld
extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

response.setContentType("text/html");
PrintWriter out = response.getWriter();

out.println("Hello World Servlet!");

}

}

Compile the source into a class file as follows:

javac -classpath /usr/local/jakarta-tomcat/common/lib/servlet.jar HelloWorld.java

This will create a file called HelloWorld.class. Copy the HelloWorld.class file to the /home/tomcat/webapps/{YOUR_DOMAIN}/{YOUR_APPLICATION}/WEB-INF/classes directory.

10.3 Tomcat Application

The web.xml file is where a servlet name is mapped to a URL pattern so Tomcat can run your servlet when requested. Below is the web.xml file that runs the HelloWorld servlet whenever the URL http://{YOUR_DOMAIN}/servlet/HelloWorld is entered in the browser:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/servlet/HelloWorld</url-pattern>
</servlet-mapping>

</web-app>

Restart Tomcat as follows:

/CATALINA_HOME/bin/shutdown.sh
/CATALINA_HOME/bin/startup.sh

Restart Apache as follows:

service httpd restart

You should now be able to type the following into your browser and see the always-exciting "Hello World" message:
http://{YOUR_DOMAIN}/HelloWorld.jsp
http://{YOUR_DOMAIN}/servlet/HelloWorld

11.0 Advanced Configuration

The following steps are not mandatory, but are suggested for a better, tighter Tomcat installation.

11.1 Tomcat Startup Script

If you want to automatically start Tomcat when your system boots and manage it using the service command as we do Apache, you must create an initialization script.

Copy the following text into a file called tomcat and install the file in the /etc/rc.d/init.d directory.

#!/bin/sh
#
# Startup script for Tomcat Servlet Engine
#
# chkconfig: 345 86 14
# description: Tomcat Servlet Engine
# processname: tomcat
# pidfile: /usr/local/jakarta-tomcat/bin/tomcat.pid
#

# User under which tomcat will run
TOMCAT_USER=tomcat

RETVAL=0

# start, debug, stop, and status functions
start() {
# Start Tomcat in normal mode
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
if [ $SHUTDOWN_PORT -ne 0 ]; then
echo "Tomcat already started"
else
echo "Starting tomcat..."
chown -R $TOMCAT_USER:$TOMCAT_USER /usr/local/jakarta-tomcat/*
chown -R $TOMCAT_USER:$TOMCAT_USER /home/tomcat/*
su -l $TOMCAT_USER -c '/usr/local/jakarta-tomcat/bin/startup.sh'
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
while [ $SHUTDOWN_PORT -eq 0 ]; do
sleep 1
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
done
RETVAL=$?
echo "Tomcat started in normal mode"
[ $RETVAL=0 ] && touch /var/lock/subsys/tomcat
fi
}

debug() {
# Start Tomcat in debug mode
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
if [ $SHUTDOWN_PORT -ne 0 ]; then
echo "Tomcat already started"
else
echo "Starting tomcat in debug mode..."
chown -R $TOMCAT_USER:$TOMCAT_USER /usr/local/jakarta-tomcat/*
chown -R $TOMCAT_USER:$TOMCAT_USER /home/tomcat/*
su -l $TOMCAT_USER -c '/usr/local/jakarta-tomcat/bin/catalina.sh jpda start'
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
while [ $SHUTDOWN_PORT -eq 0 ]; do
sleep 1
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
done
RETVAL=$?
echo "Tomcat started in debug mode"
[ $RETVAL=0 ] && touch /var/lock/subsys/tomcat
fi
}

stop() {
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
if [ $SHUTDOWN_PORT -eq 0 ]; then
echo "Tomcat already stopped"
else
echo "Stopping tomcat..."
su -l $TOMCAT_USER -c '/usr/local/jakarta-tomcat/bin/shutdown.sh'
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
while [ $SHUTDOWN_PORT -ne 0 ]; do
sleep 1
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
done
RETVAL=$?
echo "Tomcat stopped"
[ $RETVAL=0 ] && rm -f /var/lock/subsys/tomcat /usr/local/jakarta-tomcat/bin/tomcat.pid
fi
}

status() {
SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
if [ $SHUTDOWN_PORT -eq 0 ]; then
echo "Tomcat stopped"
else
MODE="normal"
JPDA_PORT=`netstat -vatn|grep LISTEN|grep 8000|wc -l`
if [ $JPDA_PORT -ne 0 ]; then
MODE="debug"
fi
echo "Tomcat running in $MODE mode"
fi
}

case "$1" in
start)
start
;;
debug)
debug
;;
stop)
stop
;;
restart)
stop
start
;;
redebug)
stop
debug
;;
status)
status
;;
*)
echo "Usage: $0 {start|debug|stop|restart|redebug|status}"
exit 1
esac

exit $RETVAL

Add the startup script to your system as follows:

chkconfig --add tomcat

The path of the file that contains the pid of the catalina startup java process can be set with the CATALINA_PID environment variable. CATALINA_HOME/bin/catalina.sh automatically calls a file called setenv.sh if it exists, so this is a good place to set environment variables.

Create setenv.sh as follows:

cd CATALINA_HOME/bin
touch setenv.sh
chmod 644 setenv.sh

Copy the following text into setenv.sh:

CATALINA_PID=/usr/local/jakarta-tomcat/bin/tomcat.pid

Now you will be able to start/stop/restart/status Tomcat using the following commands:

service tomcat start
service tomcat stop
service tomcat restart
service tomcat status

If you want Tomcat to start automatically when your system boots, you need to add tomcat to your runlevel as follows:

chkconfig --level 5 tomcat on

Runlevel 5 is the X Window System, typical for a development computer. Runlevel 3 is typical for a dedicated web server.

Apache and Tomcat can be started and restarted in any order. In the past (specifically with the 1.2.5 connector), if Tomcat was restarted, Apache would have to be restarted. This was because the AJP13 protocol maintains open sockets between Apache and Tomcat, and when Tomcat was restarted the connections would be hung in CLOSE_WAIT status until Apache was restarted. This has been fixed starting with the 1.2.6 connector.

11.2 Development Setup

During development, you will need access to your tomcat application directory. Add the user account under which you will be doing development to the tomcat group in /etc/group. For example, this is what the tomcat entry might look like in /etc/group if you do development under the yourname account:

tomcat:x:502:yourname

Make sure the tomcat group has permission to publish files (e.g. using ant) to your Tomcat application in /home/tomcat/webapps/{YOUR_DOMAIN}. Issue the following commands as root:

chmod g+x /home/tomcat
chmod -R g+rw /home/tomcat

12.0 Troubleshooting

12.1 Log Files To Watch

/home/tomcat/webapps/{YOUR_DOMAIN}/logs/error_log

Look here for clues to Apache httpd.conf configuration issues, for example VirtualHost setup.

CATALINA_HOME/logs/catalina.out

Look here for clues to Tomcat server.xml configuration issues. This file is written to when Tomcat starts and stops. It also catches System.out and System.err.

CATALINA_HOME/logs/tomcat.log

Look here for clues to all Tomcat issues. This is the main Tomcat log file.

/etc/httpd/logs/mod_jk.log

Look here for clues to mod_jk configuration issues.

12.2 Monitoring Connections

The following command can be used to monitor the Apache, Tomcat, and mod_jk connections:

netstat -vatn | grep 80

Below is output from running this command. Line numbers have been added to the beginning of each line for discussion purposes.

1 tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN
2 tcp 0 0 127.0.0.1:8009 0.0.0.0:* LISTEN
3 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
4 tcp 0 0 127.0.0.1:8009 127.0.0.1:34449 ESTABLISHED
5 tcp 0 0 127.0.0.1:34449 127.0.0.1:8009 ESTABLISHED

Notes

  1. Line 1 shows Tomcat listening on port 8005 for the shutdown command.
  2. Line 2 shows Tomcat listening on port 8009 for requests from Apache.
  3. Line 3 shows Apache listening on port 80 for user requests.
  4. Line 4 shows the Tomcat end of a mod_jk connection.
  5. Line 5 shows the Apache end of a mod_jk connection.

13.0 Disclaimer

This document is provided as is without any express or implied warranties. While every effort has been taken to ensure the accuracy of the information contained in this document, the author assumes no responsibility for errors, omissions, or damages resulting from the use of the information contained herein. Use of the concepts, examples, and/or other content of this document is entirely at your own risk.

 

apache tomcat logging tutorial

This document is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non infringement. In no event shall the author be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with this document or the use or other dealings in this document.

Primer On java.util.logging and JULI

The goal of this primer is to demonstrate how to to log with java.util.logging, as implemented by JULI, as a backdrop to the rest of the tutorial, in particular the sections related to configuring Tomcat logging with the configuration file. One may think it's wise to skip this section and proceed directly to the section on the configuration file, but all the concepts talked about here and necessary to understand the configuration file. The examples used in this section show programmatically how logging is configured. The section on Tomcat's configuration file discusses how to accomplish declaratively what is done programmatically in this section.

The following concepts (Classes) are important:

  • LogManager

  • Loggers

  • Handlers

  • Levels

  • Root Logger

  • Root Handler

The official Tomcat logging documentation refers to the above concepts / classes extensively.

Lets start with Loggers. What's the purpose of a Logger? A Logger is what a developer uses to write a log statements to the console, to a file, to the network, etc. If you wanted to log something from your web application's class CriticalComponent using java.util.logging you would first create a logger like this:


private String nameOfLogger = 'com.example.myapp.CriticalComponent';

or

private String nameOfLogger = CriticalComponent.class.getName();

private static Logger myLogger = Logger.getLogger(nameOfLogger);


 

Pay attention to how we defined the name of the Logger. This is important to the material explaining Tomcat's logging configuration. You may also want to think about why the myLogger is a static field (Hint myLogger is shared among all instances of CriticalComponent).

Now you have a logger to create logging messages from your class CriticalComponent. For example you could now try something like this:

public void wasssup() {

  • myLogger.info("Ah Yeah Baby - that's the end of System.out.println");

}

If you ran this code with a deployed web application you would see this statement on the console or in catalina.out:


INFO; 322125105255ms; 4407662;# 1; com.example.myapp.CriticalComponent; wasssup; Ah Yeah Baby - that's the end of System.out.println


 

Notice that both the name of the Logger and the method that logged the message are mentioned in the log statement. This is important to know when you want to alter the configuration of the Logger. For example you might want to turn this logger off, because it's not that useful.

What if you wanted the output to appear in a file and on the console? For that you need to define 2 Handlers. Create the two like this:


Handler fileHandler = new FileHandler("/var/log/tomcat/myapp.log");

Handler consoleHandler = new ConsoleHandler();

myLogger.addHandler(fileHandler);

myLogger.addHandler(consoleHandler);


 

Now myLogger will log to both the console and the file /var/log/tomcat/myapp.log.

So now we understand Loggers and Handlers, but we have not touched on Levels, Root Loggers, and Root Handlers yet. What are those?

Lets start with a root Logger. A root logger is a logger whose name is "". What's the purpose of it? Suppose you tried to do some logging with myLogger like this:


myLogger.finest("Sooooo Fine");


 

And nothing shows up in your log, but you know that this statement is being called. What's going on? The answer is that the JULI root logger's Level is set to INFO by default. The level INFO has a corresponding integer assigned to it, which is 3. When myLogger attempts to log it first checks its level. If myLogger's level is greater than the level intrinsic to the method doing the logging (finest), then the record will be logged. In this case the logging method finest corresponds to Level zero. Zero is less than 3, hence the logger does not log the message. My logger will only log messages with a level that is greater than or equal to 3. So for instance if


myLogger.severe("Oohhh %#$@#$!!!")


 

is called, it will get logged because the level intrinsic to the method severe is greater than 3. So you are following this, but wondering how myLogger's level got set to 3 (INFO), since we never explicitly set it. The answer is that it comes the root Logger. Now suppose you created logger named 'com.example.myapp' and set its level. Would myLogger still get its level from the root Logger. It would not. The reason is that the logger named 'com.example.myapp' is now a parent logger to myLogger, and myLogger gets its level from it instead. How did the 'com.example.myapp' Logger become a parent? It's because of its name 'com.example.myapp'. If it were named 'org.charity.generous', it would not be a parent logger. Do you see the pattern (myLogger includes 'com.example.myapp' in its name)?

Now that we mulled that over you have an idea of what a level is as well. The Level determines what gets logged. You can set the level directly on myLogger like this:

myLogger.setLevel(Level.WARNING);

In this case only messages with a level of WARNING or SEVERE will get logged by myLogger.

Now remember that once something gets logged by myLogger, it's handed over to myLogger's Handlers. But what if we never assigned any Handlers to myLogger. How would it get its Handler?

The answer is the root Handlers. The root logger has root Handlers. So if you don't explicitly define any Handlers for myLogger, it will use the Handlers attached to the root Logger. Now if you did attach Handler(s) to the logger named 'com.example.myapp', but not to myLogger, then myLogger would use the Handler(s) attached to 'com.example.myapp', instead of the Handlers attached to the root Logger. In other words myLogger uses the Handlers of the closest Logger ancestor, which in this case is either the 'com.example.myapp' Logger or the root Logger.

So all of the above is important to understand in order to be able to configure Tomcat logging with JULI. Now we can talk about doing so via the configuration file.

Configuring Tomcat JULI

Configuring Loggers

Suppose we wanted to configure myLogger via a logging.properties file, rather than programmatically as we did earlier, and simply set its Level to SEVERE. We would put the following in the configuration file:


com.example.myapp.CriticalComponent.level = SEVERE


 

That's how Loggers are configured. We specified the name of the Logger followed by followed by a period followed by the name of the property we wanted to set, which is 'level' in this case. If we had several classes with corresponding loggers, and we did not want to set the logging level for each class individually, we could set the logging level on the root Logger like this:


.level = SEVERE


 

This will set the level on all loggers to SEVERE, unless the Logger uses a non-default level (Either programmatically or via configuration).

So if you wished to turn logging off all together simply configure the root logger like this and make sure that there are no child loggers that override this setting:


.level = OFF


 

On the flip side to log everything set it like this:


.level = ALL


 

Configuring Handlers

Suppose that we also wanted to add a Handler to the Logger named com.example.myapp.CriticalComponent.

We could define our handler like this:

handlers = org.apache.juli.FileHandler

And configure it like this: org.apache.juli.FileHandler.level = WARNING org.apache.juli.FileHandler.directory = /var/log/tomcat/ org.apache.juli.FileHandler.prefix = mywebapp

Then assign it to our Logger like this:

com.example.myapp.CriticalComponent.handlers = org.apache.juli.FileHandler

Now we've done the same thing declaratively in our logging.properties file that we did programmatically earlier.

What if we wanted to make the Handler we just configured the root Handler? We could configure it as the root Handler like this: .handlers = org.apache.juli.FileHandler.

Now all Tomcat Loggers that do not have a Handler assigned to them directly, either programmatically or declaratively via the logging.properties file, will delegate to this Handler.

Configuring Context Loggers

So you now had a look at the example logging.properties file in the official documentation again, and you understand most of it.

Then you get to these lines:


org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \


 

These don't follow the same syntax we've been using thus far to configure Loggers and Handlers.

These are for configuring Context loggers. What's a context logger? First you need to know a little about the ServletContext.

For a description of what a Servlet Context is see:


[WWW] http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContext.html


You'll notice specifically that it mentions that there is one ServletContext per webapp, and that this ServletContext can be used to perform logging.

Looking down a little further in the ServletContext.html document we see that the ServletContext has a log method that takes a String.

If a developer working on the manager application were to use the ServletContext.log method, without the corresponding configuration lines shown above, output would go to standard out, and end up on the console or catalina.out. However now that the ServletContext Logger has been configured for the manager application, ServletContext.log("...") statements made within the /manager application will end up in manager.dd.mm.yyy.log.