How to 'chroot' an Apache tree with Linux and Solaris
I have set up and used chroot-ed web trees
in the past with the CERN httpd. There are various advantages and
disadvantages to chroot-ing a web tree. In the early days of the 'web'
this technique provided some valuable extra security. In this
Apache-dominated era there seems to be less need. However the techique
is still interesting and relevant.
I provide example chroot-ed Linux and Solaris setups, with options to
do a standard compilation (which is marked
non-DSO where necessary), or a
Dynamic Shared Object (DSO) compilation (which is marked
DSO where necessary). The solaris example with
DSO options is not yet documented, since I haven't tested it (and
want to play with Solaris 8 as well when I do it :-)
It is relatively simple to set up a chroot-ed apache tree on Linux. This
example uses Red Hat 6.* and Apache 1.3.12. This example also
includes PHP 4 (as an apache module), and an installation of
perl 5 in the chrooted tree. Additionally mod_ssl
and mod_perl are installed.
This example assumes that
Red Hat was installed with a decent development environment (ie: sufficient
include files, libraries and development tools). Note that you will
typically have a complete development environment if you installed the
Red Hat custom (preferred!) configuration and selected the
'development' option; or the server configuration.
MySQL 3.22.27 is not installed in the chroot-ed tree, but is added
here for completeness.
Standard Disclaimer
I am not an expert (IANAE ? :-), especially for issues related to
encryption (openssl, mod_ssl and company). I am human and I make mistakes.
Please let me know if you find any, or if you have any other constructive
suggestions.
This how-to is provided in the hope that it will help you, and that you
may learn something from it. I could always just provide an RPM, but it
is far more interesting (I think) to know that you can construct a modern
web server from scratch, yourself. But it is up to you to learn and
understand the issues, the problems and the risks of running a web server
in today's internet!
The Solaris Example
The Solaris example for chroot-ing a web tree is very similar to the Linux
case. Of course, if you don't have a current GNU development environment
installed then it will be not be as easy as the Linux case.
The Solaris example is documented here,
in a separate web document (but note that DSO options, mod_perl
and mod_ssl are not yet documented).
- To discover necessary shared libraries use the tool:
ldd
- In these examples the users have 'prompts' like the
following:
root user:
ROOT#
ordinary user:
$
- I nearly always compile and install software as an
'ordinary user' rather than as root. This helps me to avoid
accidentally stomping on the file system (especially with software
I am unfamiliar with). It also helps to alert me about makefiles that
want to do dangerous things, like 'setuid' on installed binaries;
or install files in unusual places.
In these examples I compile and install as user
softs:softs
Just make sure that the software owner is NOT
the same user
as the apache tree user id (user id 888 in these examples).
- The default Red Hat root environment has the interactive
switch '-i' set on the commands: 'cp', 'mv' and 'rm'. If your root
environment does not have this, then you are advised to set
them. To check:
ROOT# alias |grep '\-i'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
- You should keep your configuration simple -- do not install modules
that you will not use or do not need. A standard non-DSO apache
configuration with perl installed is adequate for many people...
- An important note about DSO
and mod_ssl:
If you plan to compile everything as DSO
modules and you will be building mod_ssl then you really should
build your apache tree in the following order. mod_ssl
significantly modifies the apache build tree, and in my experience with
the versions mentioned in this how-to it is easier to proceed in this order:
- Build Apache
- Build and add mod_ssl to Apache
- Build and add php and/or mod_perl to Apache
- You should jot down somewhere how you compiled your tree, in case
you have to redo it (print these pages out and annotate them).
- The final chroot-ed tree with everything weights in at about
23 MBytes, including
about 8 MB each for shared libraries and for perl. Following are
file size summaries in kilobytes for a DSO-based install:
ROOT# pwd
/www
ROOT# du -s .
22737 .
ROOT# du -s *
6832 apache
0 bin
1 dev
7 etc
6679 lib
1 tmp
9215 usr
1 webhome
ROOT# du -s apache/*
600 apache/bin
3 apache/cgi-bin
125 apache/conf
1560 apache/htdocs
133 apache/icons
392 apache/include
3925 apache/libexec
64 apache/man
29 apache/var
ROOT# du -s usr/*
8410 usr/Local
336 usr/bin
340 usr/lib
128 usr/share
You will need to pick up the source files for any packages you intend
to integrate into your chroot-ed tree. Many of these source files
can be extracted from the corresponding linux distribution SOURCE cdroms
as SRPMs (RPM source packages) or tarball (.tar.gz) files.
(This is very handy if you have limited bandwidth).
For a Red Hat
system you install the source (as root):
ROOT# rpm -i /path/to/SRPMfile.src.rpm
and pick the source out of the
/usr/src/redhat/SOURCES/ directory.
But for these examples I indicate where to go to get the sources
on the internet (and the versions that were used for these
examples):
Prepare a Chroot-ed File System
-
Set up the tree anywhere (preferably another disk or
a non-system partition to discourage others from making
hard links to files outside your web tree),
but use a symlink (eg /www) to reference it.
ROOT# mkdir /export/misc/www
ROOT# ln -s /export/misc/www /www
-
Create the basic directories; bin will be a
link to usr/bin
!! NOTE the lack of leading slashes in this example,
except where I copy files from the regular file system. Do NOT mix up your
chroot-ed tree with your real '/'!
You have been
warned!
I have indicated the chroot-ed files in
magenta
ROOT# cd /www
ROOT# mkdir -p usr/bin usr/lib lib
etc tmp dev webhome
ROOT# ln -s usr/bin bin
-
/tmp is given special perms.
ROOT# chmod 777 tmp
ROOT# chmod +t tmp
-
Make the special device /dev/null
ROOT# mknod -m 666 dev/null
c 1 3
-
Set up the timezone info for YOUR timezone
(this example uses MET):
ROOT# mkdir -p
usr/share/zoneinfo
ROOT# cp -pi /usr/share/zoneinfo/MET
usr/share/zoneinfo/
ROOT# cd etc
ROOT# ln -s
../usr/share/zoneinfo/MET localtime
ROOT# cd ..
-
You will find that perl and/or mod_perl will complain
about the lack of locale settings. To fix this install your
locale files in the chroot-ed tree:
ROOT# set |grep LANG
LANG=en_US
ROOT# mkdir /www/usr/share/locale
ROOT# cp -a /usr/share/locale/en_US
/www/usr/share/locale/
-
Now copy in the shared libraries that provide a very
basic chroot-ed file system
ROOT# cp -pi /lib/libtermcap.so.2 /lib/ld-linux.so.2
/lib/libc.so.6 lib/
-
Test your tree ('cat' will be needed by 'apachectl'
later, but is not strictly necessary):
ROOT# cp -pi /bin/ls /bin/sh /bin/cat
bin/
ROOT# chroot /www /bin/ls -l /
lrwxrwxrwx 1 0 0 7 Jan 29 09:24 bin -> usr/bin
drwxr-xr-x 2 0 0 1024 Jan 29 09:28 dev
drwxr-xr-x 2 0 0 3072 Jan 29 13:17 etc
drwxr-xr-x 2 0 0 1024 Jan 29 13:12 lib
drwxrwxrwt 2 0 0 1024 Jan 29 09:23 tmp
drwxr-xr-x 5 0 0 1024 Jan 29 09:23 usr
drwxr-xr-x 2 0 0 1024 Jan 29 10:41 webhome
-
You can remove 'ls'; it was only used for testing:
ROOT# rm bin/ls
Here we create the user whom apache will run as, and the necessary naming
services for this configuration.
-
Create a new user that doesn't exist on the system, and
give the user a unique name (eg: www) and user id
(eg:888). Note that it isn't actually necessary for the
user:group to exist in the real authentication (/etc/passwd /etc/group)
files. It's up to you..
ROOT# cd /www
ROOT# touch etc/passwd etc/group
etc/shadow
ROOT# chmod 400 etc/shadow
-
Edit these three files. For the sake of this example I
am just echoing the data into the files:
ROOT# echo
'www:x:888:888:Web Account:/webhome:/usr/bin/False' >
etc/passwd
ROOT# echo 'www:x:888:' >
etc/group
ROOT# echo 'www:*:10882:-1:99999:-1:-1:-1:134537804' >
etc/shadow
-
I have given this user no login, and no shell. Just to
be complete, compile a 'no-go' shell called False:
ROOT# echo 'int main(int argc, char *argv[])
{ return(1); }' > /tmp/False.c
ROOT# cc -o /www/usr/bin/False
/tmp/False.c
-
While we are at it, lets mark the binaries as
execute-only:
ROOT# chmod 111 usr/bin/*
-
Some naming services will be required. With glibc and
the Name Service Switch libraries the necessary libraries are not
immediately obvious. See 'man nsswitch' for details.
I chose to rely on files and DNS, even though I also run NIS on my home
machines.
Note: The libresolv library will
be needed as well (This will become evident when PHP is installed).
ROOT# cp -pi /lib/libnss_files.so.2
lib/
ROOT# cp -pi /lib/libnss_dns.so.2
lib/
-
We will need 3 files to complete the configuration
for Naming Service. The contents of these files will depend on your
IP and DNS setup. Here we assume that the web server is named
ns.mynet.home with IP address 192.168.196.2
(it is actually also my naming server):
# ---- Contents of   
etc/nsswitch.conf ----#
passwd: files
shadow: files
group: files
hosts: files dns
# ---- Contents of   
etc/resolv.conf ----#
domain mynet.home
## use the IP address of your naming server
## if bind is not installed on your web server
#nameserver 192.168.196.xxx
## use this if your web server is a (caching) name server
nameserver 127.0.0.1
# ---- Contents of   
etc/hosts ----#
127.0.0.1 localhost loopback
192.168.196.2 ns.mynet.home ns www
-
Make the top-level directory for the apache install
(in this example: /apache); and create a symlink to it in the
real tree:
ROOT# mkdir /www/apache
ROOT# ln -s /www/apache
/apache
-
I normally compile and install as an ordinary user
(in this example: softs), rather than as 'root'. Note, however,
that the installation of apache should be done as root. (See the
'security tips' in the online apache documentation)
In this case I compile sources in
/usr/local/src/chr, which is owned by softs:softs
$ cd /usr/local/src/chr
$ tar zxf /path/to/apache_1.3.12.tar.gz
$ cd apache_1.3.12
-
Edit config.layout so that it includes a
special layout called chroot
# chroot layout.
<Layout chroot>
prefix: /apache
exec_prefix: $prefix
bindir: $exec_prefix/bin
sbindir: $exec_prefix/bin
libexecdir: $exec_prefix/libexec
mandir: $prefix/man
sysconfdir: $prefix/conf
datadir: $prefix
iconsdir: $datadir/icons
htdocsdir: $datadir/htdocs
cgidir: $datadir/cgi-bin
includedir: $prefix/include
localstatedir: $prefix/var
runtimedir: $localstatedir/logs
logfiledir: $localstatedir/logs
proxycachedir: $localstatedir/proxy
</Layout>
-
Now configure and make:
- non-DSO:
$ ./configure --with-layout=chroot \
--enable-module=most --enable-module=so
By enabling the module 'so' you have the possibility of
extending your Apache installation later via 3rd-party modules through the
DSO+APXS mechanism.
- DSO:
$ ./configure --with-layout=chroot \
--enable-module=most --enable-shared=max
$ make
ROOT# make install ## I am root!
-
Copy the other shared libraries that will be needed by
Apache as configured in this example. NOTE that other configurations
may require other libraries (use ldd to find out).
ROOT# cd /www
ROOT# cp -pi /lib/libm.so.6 /lib/libcrypt.so.1 /lib/libdb.so.3
lib/
ROOT# cp -pi /lib/libdl.so.2
lib/
-
Do a quick test to see that it worked. The main fields
to edit in the configuration file
/www//apache/conf/httpd.conf
for a quick test are:
User www
Group www
ServerName yourserver.yourdomain.here
Port 8088 ## pick your favourite test port
Here are sample configuration files:
-
Start the daemon (you need to be root):
ROOT# chroot /www /apache/bin/apachectl start
-
Test the URL:
$ lynx -dump http://yourserver/
Test the URL if on another port, eg: 8088:
$ lynx -dump http://yourserver:8088/
-
Here is a small perl script
that removes most of the comments from the generated config files, for
those who want to simplify the file.
-
This would be a good time to give ownership of the
htdocs tree to the web tree 'owner':
ROOT# chown -R 888:888
/www/apache/htdocs
MySQL is not installed in the chroot-ed tree; indeed, it should probably
be installed on another system. But on my home system it is installed on the
same server as apache.
This example includes creating the user and the place where
the database will reside, and the creation of the initial database.
-
Create the user who will own the mysql database --
for example, 777:777 in /home/mysql:
ROOT# groupadd -g 777 mysqldba
ROOT# useradd -c "mysql DBA" -d /home/mysql
-u 777 -g 777 -m -n mysql
-
unpack the source and give ownership of the mysql source
tree to the mysql user:
ROOT# mkdir /usr/local/mysql
ROOT# chown mysql:mysqldba /usr/local/mysql
ROOT# cd /usr/local/src
ROOT# tar zxf /path/to/mysql-3.22.27.tar.gz
ROOT# chown -R mysql:mysqldba
/usr/local/src/mysql-3.22.27
-
Now as the mysql user, make a directory for the
database, and compile and install mysql:
$ mkdir ~/db ## where the DB will reside
$ cd /usr/local/src/mysql-3.22.27
$ ./configure --localstatedir=/home/mysql/db
--prefix=/usr/local/mysql
$ make
$ make install
-
Create the *MySQL* grant tables (necessary only if you
haven't installed *MySQL* before):
$ ./scripts/mysql_install_db
-
Install and modify the database startup script,
changing the database owner from root to 'mysql':
ROOT# cd /usr/local/src/mysql-3.22.27/
ROOT# cp support-files/mysql.server /etc/rc.d/init.d/
ROOT# chmod 755 /etc/rc.d/init.d/mysql.server
ROOT# [ edit /etc/rc.d/init.d/mysql.server: ]
mysql_daemon_user=mysql ## so we can run mysqld as this user.
ROOT# chkconfig --add mysql.server
## permanently add server to rc scripts
-
It may be necessary to refresh the shared library cache
after installing mysql:
ROOT# /sbin/ldconfig -nv /usr/local/lib
-
Edit the PATH variable for the mysql owner, and set up
the 'root' password for the database (read the documentation!)
(and you will probably want to delete the test database and associated
entries):
$ [ Edit shell login script .bash_profile: ]
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin
$ . ~/.bash_profile
## source it!
$ mysqladmin -u root password '2mUch!data'
## pick your own password!
-
Stop the apache daemon, if it is running:
ROOT# chroot /www /apache/bin/apachectl stop
-
You must first compile PHP, then for
non-DSO installs only you must recompile
Apache. (You will need to do this each time you upgrade either
software package for non-DSO installs.)
$ cd /usr/local/src/chr ## I am NOT root!
$ tar zxf /path/to/php-4.02.tar.gz
$ cd php-4.02
- non-DSO:
$ ./configure --with-mysql=/usr/local/mysql \
--with-apache=../apache_1.3.12 --enable-track-vars \
--with-config-file-path=/apache/conf --sharedstatedir=/tmp
- DSO:
$ ./configure --with-mysql=/usr/local/mysql \
--with-apxs=/apache/bin/apxs --enable-track-vars \
--with-config-file-path=/apache/conf --sharedstatedir=/tmp
- DSO:
(or add CFLAGS switch when mod_ssl was also
configured as a DSO module)
$ CFLAGS=-DEAPI ./configure
--with-mysql=/usr/local/mysql \
--with-apxs=/apache/bin/apxs --enable-track-vars \
--with-config-file-path=/apache/conf --sharedstatedir=/tmp
$ make
- non-DSO:
$ make install
- DSO:
ROOT# make install
(You will need to be root for the
DSO 'make install' of PHP, since the module goes
directly into the module tree: /apache/libexec/ and additionally
the apache configuration file is altered.)
-
Now for the non-DSO
installation only, recompile Apache, activating the PHP module:
$ cd ../apache_1.3.12/
$ ./configure --with-layout=chroot \
--enable-module=most --enable-module=so \
--activate-module=src/modules/php4/libphp4.a
$ make
ROOT# make install ## I am root!
-
More shared libraries (for PHP) are needed in the
chrooted tree; check with 'ldd':
- For non-DSO:
ldd /apache/bin/httpd
- For DSO:
ldd /apache/apache/libexec/libphp4.so
A little for-loop can be used to copy the needed files
from /lib and from /usr/lib:
ROOT# cd /www
ROOT# for i in libresolv.so.2 libnsl.so.1
libpam.so.0 ; do
> cp -pi /lib/$i /www/lib/ ; done
ROOT# for i in libgd.so.1 libgdbm.so.2 libz.so.1; do
> cp -pi /usr/lib/$i /www/usr/lib/ ; done
-
If you will be needing mysql, you must install that
library as well from the place it was compiled into:
ROOT#
cp -pi /usr/local/mysql/lib/mysql/libmysqlclient.so.6
/www/usr/lib/
-
You must edit httpd.conf so that it
recognizes .php files, if
you have not already done so:
ROOT# cd /apache/conf
ROOT# [ edit
/apache/conf/httpd.conf ]
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
-
Restart the daemon:
ROOT# chroot /www /apache/bin/apachectl start
-
For non-DSO installs
you can check for compiled-in PHP:
ROOT# chroot /www /apache/bin/httpd -l | grep php
mod_php4.c
-
Here is a 'hello world' script
to test PHP. It should be installed as 'hello.php' (save as type 'text'
from netscape), with a copy or a
symlink as 'hello.phps' for source-code viewing if you wish. Do not
leave it lying around for the public after you have finished testing!
You can get away with simply copying
/usr/lib/perl5 into /www/usr/lib/
; and copying /usr/bin/perl5.00503 (assuming Red Hat 6.0)
into /www/usr/bin/. You would need
to check for, and install any missing shared libraries. You should also
make a hard link from usr/bin/perl5.00503
to usr/bin/perl in
/www as well.
The easy way:
ROOT# cp -a /usr/lib/perl5
/www/usr/lib/perl
ROOT# cp -p /usr/bin/perl5.00503
/www/usr/bin/
ROOT# cd /www/usr/bin
ROOT# ln perl5.00503 perl
Nonetheless (the slightly less easy way :o), I show how to compile and
install perl. If you are going to install mod_perl then you
really must compile perl here:
-
Make the nessary links to install into the
chroot-ed tree. This example uses /usr/Local inside the
tree. The choice of /usr/Local is deliberate -- do not
confuse it with /usr/local.
Ever fearful :-O, I installed as 'softs':
ROOT# mkdir /www/usr/Local
ROOT# ln -s /www/usr/Local
/usr/Local
ROOT# chown softs:softs
/www/usr/Local
-
Get the source RPM from the redhat sources:
ROOT# rpm -i /path/to/perl-5.00503-2.src.rpm
-
As the owner (softs) of the source tree, unpack perl.
$ cd /usr/local/src/chr
$ tar zxf /usr/src/redhat/SOURCES/perl5.005_03.tar.gz
-
Red Hat supplies some patches in the SRPM. You can
apply these patches for this distribution as well. This exemple
illustrates patching perl from a Red Hat 6.0 distribution.
$ cp /usr/src/redhat/SOURCES/perl*.patch .
$ cd perl5.005_03
$ patch -p1 <../perl5-installman.patch
$ patch -p1 <../perl5.005_02-buildsys.patch
$ patch -p1 <../perl5.005_03-db1.patch
-
You need to run Configure, accepting
most of the defaults from the script. You will also probably
want to specify 'none' for the man pages. A few of the defaults to
change in my example are listed below:
$ ./Configure
- architecture name? i386-linux
- Installation prefix to use? /usr/Local
- Directories to use for library searches? /lib /usr/lib /usr/Local/lib
- install perl as /usr/bin/perl? n
-
Compile and install it.
$ make
$ make test
$ make install
-
Create symlink to perl in the usr/bin tree.
If you are not installing mod_perl (see ahead), then you could change
ownership of the perl tree to root (but not necessary as long as the
permissions on the perl tree are read-only for the web-tree owner:
uid '888' in this example):
ROOT# cd /www/usr/bin
ROOT# ln -s ../Local/bin/perl
perl
-
Check the shared libraries and install any missing
libraries (depends on your configuration options). No extra libraries
are needed in this example:
ROOT# ldd
/www/usr/bin/perl
libnsl.so.1 => /lib/libnsl.so.1 (0x4001b000)
libdl.so.2 => /lib/libdl.so.2 (0x40031000)
libm.so.6 => /lib/libm.so.6 (0x40035000)
libc.so.6 => /lib/libc.so.6 (0x40052000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x40147000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
-
Test your installation:
ROOT# chroot /www /usr/bin/perl -v
This is perl, version 5.005_03 built for i386-linux
...
-
Set up the example perl cgi bin script installed
with the apache server:
ROOT# cd /www/apache/cgi-bin
ROOT# chmod ugo+x *
-
Start your apache server, and test the example
perl cgi bin script installed with the server:
ROOT# chroot /www /apache/bin/apachectl start
$ lynx -dump http://yourserver/cgi-bin/printenv
While you are at it, check test-cgi for
shell CGI access as well:
$ lynx -dump http://yourserver/cgi-bin/test-cgi
-
Finally, REMOVE the execute bit from the example
cgi-scripts, or remove them entirely. Don't let the general public
have access to these scripts:
ROOT# chmod ugo-x
/www/apache/cgi-bin/*
-
This process assumes that your chroot-ed perl tree
is owned by your source-code owner. It this is not the case then
change ownership:
ROOT# chown -R softs:softs
/www/usr/Local
-
Extract the source code for mod_perl:
$ cd /usr/local/src/chr
$ tar zxf /path/to/mod_perl-1.24.tar.gz
$ cd mod_perl-1.24
-
IMPORTANT: Put /usr/Local/bin first
in the path before starting configuration. This helps to avoid
problems with the configuration finding /usr/bin/perl or
/usr/local/bin/perl first in your environment:
$ which perl
/usr/bin/perl
$ export PATH=/usr/Local/bin:$PATH
## assuming a bourne shell
$ which perl
/usr/Local/bin/perl
-
Now configure mod_perl; configure the Perl-side of
mod_perl, and prepare the mod_perl subdirectory inside apache:
- non-DSO:
$ perl Makefile.PL APACHE_SRC=../apache_1.3.12/src \
DO_HTTPD=1 USE_APACI=1 PREP_HTTPD=1 EVERYTHING=1
- DSO:
$ perl Makefile.PL USE_APXS=/apache/bin/apxs \
EVERYTHING=1
- DSO:
( or add the CFLAGS switch when mod_ssl was also
configured as a DSO module [and respect any message about
apache include files being in unusal places!] )
$ CFLAGS=-DEAPI perl Makefile.PL USE_APXS=/apache/bin/apxs \
EVERYTHING=1
-
Now make and install mod_perl into the chroot-ed tree:
$ pwd
/usr/local/src/chr/mod_perl-1.24
$ make
- non-DSO:
$ make install
- DSO:
ROOT# make install
(You will need to be root for the
DSO 'make install' of mod_perl, since the
module goes directly into the module tree: /apache/libexec/
and additionally the apache configuration file is altered.)
-
For the non-DSO installs
only you must recompile apache and reinstall it:
$ cd /usr/local/src/chr/apache_1.3.12/
$ ./configure --with-layout=chroot \
--enable-module=most --enable-module=so \
--activate-module=src/modules/php4/libphp4.a \
--activate-module=src/modules/perl/libperl.a
$ make
Stop apache if it was
previously running, and install it:
ROOT# chroot /www /apache/bin/apachectl stop
ROOT# make install ## I am root!
-
For non-DSO installs
you can check for compiled-in PHP and mod_perl:
ROOT# chroot /www /apache/bin/httpd -l |
grep -E '(php|perl)'
mod_php4.c
mod_perl.c
-
Test your mod_perl setup with the
Hello.pm.
perl module written by Doug MacEachern. You need to install
it, edit httpd.conf and restart apache:
$ cp -i Hello.pm \
/www/usr/Local/lib/perl5/site_perl/5.005/i386-linux/Apache/
Insert the mod_perl configuration necessary for
Hello.pm into httpd.conf -- example:
<Location /hello>
SetHandler perl-script
PerlHandler Apache::Hello
</Location>
### Section 3: Virtual Hosts
ROOT# chroot /www /apache/bin/apachectl restart
$ lynx -dump http://yourserver:yourPort/hello
Hello, I see you see me with Lynx/2.8.3dev.18 libwww-FM/2.14.
-
If you are finished testing then comment out
this entry in httpd.conf.
Don't leave unnecessary functionality enabled in your apache configuration.
-
NOTE: If you need to install other perl modules, you
must put /usr/Local/bin first in your path before running
perl Makefile.PL:
$ export PATH=/usr/Local/bin:$PATH
## assuming a bourne shell
I hope you have read the
additional notes section if you are planning a DSO install of mod_ssl.
You must compile both openSSL and
mod_ssl. I have also elected
to compile rsaref version 2.0. You should read the documentation
for mod_ssl
in the source code table to understand
the issues and the options for mod_ssl.
Note that openssl and rsaref provide the include files,
libraries and tools to allow you to compile mod_ssl and generate
keys, and therefore they are not part of, nor installed into, the chroot-ed
tree.
-
Extract the source code for mod_ssl, openssl and
rsaref20:
$ cd /usr/local/src/chr
$ tar zxf /path/to/mod_ssl-2.6.6-1.3.12.tar.gz
$ tar zxf /path/to/openssl-0.9.5a.tar.gz
$ mkdir rsaref-2.0
$ cd rsaref-2.0
$ tar Zxf /path/to/rsaref20.1996.tar.Z
-
Configure and build the RSA Reference library. Note
that on 64-bit architectures you MUST read the
documentation in the INSTALL file in the mod_ssl package
about portability problems/solutions with rsaref.
$ cd /usr/local/src/chr/rsaref-2.0
$ cp -rpi install/unix local
$ cd local
$ make
$ mv rsaref.a librsaref.a
-
Configure and build the OpenSSL library.
$ cd /usr/local/src/chr/openssl-0.9.5a
$ ./config -L/usr/local/src/chr/rsaref-2.0/local -fPIC
$ make
$ make test
# inspect output for anomolies
- You may want to install the package. Of course,
it is not installed in the chroot-ed tree. Here I assume that
softs:softs owns the /usr/local/ tree, because the default
install prefix for openssl is /usr/local/ssl. However, it is not
necessary to install this package; you can operate out of the src tree
for building mod_ssl (but do NOT run make clean!)
$ make install
-
Configure mod_ssl:
$ cd /usr/local/src/chr/mod_ssl-2.6.6-1.3.12
$ ./configure --with-apache=../apache_1.3.12
-
Go into the apache tree to complete the build. Run
configure and then make:
$ cd /usr/local/src/chr/apache_1.3.12
- non-DSO:
$ SSL_BASE=../openssl-0.9.5a
RSA_BASE=../rsaref-2.0/local \
./configure --prefix=/apache --with-layout=chroot \
--enable-module=most --enable-module=so --enable-module=ssl \
--disable-rule=SSL_COMPAT --enable-rule=SSL_SDBM \
--activate-module=src/modules/php4/libphp4.a \
--activate-module=src/modules/perl/libperl.a
- DSO:
$ cd src/modules
$ make clean ## seems to be necessary if you
previously compiled in the apache tree
$ cd ../../
$ SSL_BASE=../openssl-0.9.5a
RSA_BASE=../rsaref-2.0/local \
./configure --prefix=/apache --with-layout=chroot \
--enable-module=most --enable-shared=max --enable-shared=ssl \
--disable-rule=SSL_COMPAT --enable-rule=SSL_SDBM
$ make
-
Install apache again. Stop apache if it was
previously running, and then install it:
ROOT# chroot /www /apache/bin/apachectl stop
ROOT# make install ## I am root!
-
For non-DSO installs
you can check for the compiled-in modules:
ROOT# chroot /www /apache/bin/httpd -l |
grep -E '(php|perl|ssl)'
mod_ssl.c
mod_php4.c
mod_perl.c
-
Create the random devices in the chroot-ed tree:
ROOT# cd /www/dev
ROOT# mknod random
c 1 8
ROOT# mknod urandom
c 1 9
-
Merge the default configuration file into your current
httpd.conf file. I test on a different port from the standard
port 80 because I usually already have a web server running on
port 80. But for the secure port (port 443) I have no web server
running, so I use it immediately.
For the default configuration file
the main fields to change for this example follow (and
here is an example httpd.conf file):
- User www
- Group www
- ServerName yourserver.yourdomain.here
- Port 8088 ## pick a test port
- Listen 8088 ## in 'IfDefine SSL' section
- Listen 443
## this is the standard secure port!
- <VirtualHost _default_:443>
-
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
- # your Hello.pm script for mod_perl testing:
<Location /hello>
SetHandler perl-script
PerlHandler Apache::Hello
</Location>
- SSLCertificateFile /apache/conf/server.crt
- SSLCertificateKeyFile /apache/conf/server.key
# in this example I generate the key and crt files into
/apache/conf
-
If you do not already have a server key and certificate
then create them. In this example I assume that openssl is in
your path because you have installed it. If not, then you should add
it to your path (according to this example it is in
/usr/local/src/chr/openssl-0.9.5a/apps).
Note also that I am certifying my own key. Presumably
you will get a Certifying Authority to sign your key if you are doing any
serious work with your web tree (eg: commericial work):
- ROOT# cd
/www/apache/conf
- # set up a path of random files:
ROOT#
randfiles='/var/log/messages:/proc/net/unix:/proc/stat:/proc/ksyms'
- # generate the server key
ROOT#
openssl genrsa -rand $randfiles -out server.key 1024
- # generate the signing request
(don't add a password when certifying it yourself).
Note that it is important that the Common Name match your
fully-qualified web server name!
ROOT#
openssl req -new -nodes -out request.pem -key server.key
- # sign your own key (validity for one year in this example):
ROOT#
openssl x509 -in request.pem -out server.crt -req \
-signkey server.key -days 365
- Protect your key and certificate:
ROOT# chmod 400 server.*
- Delete the request file:
ROOT# rm request.pem
- Optionally encrypt your key (you will have to provide the password
each time your start apache, but you may have a very good reason for
doing this!):
ROOT# mv server.key server.key.unencrypted
ROOT# openssl rsa -des3 -in server.key.unencrypted
-out server.key
ROOT# chmod 000 server.key.unencrypted ## better yet
delete it!
- Oops, you changed your mind. You decide to remove the encryption
password from your key:
ROOT# openssl rsa -in server.key -out server.key.un
ROOT# mv server.key.un server.key
ROOT# chmod 400 server.key
-
Start apache first without ssl to make sure
it still works:
ROOT# chroot /www /apache/bin/apachectl start
$ lynx -dump http://yourserver:8088/
-
Re-start apache with ssl and test it with
netscape (note that the URL is specified as https):
ROOT# chroot /www /apache/bin/apachectl stop
ROOT# chroot /www /apache/bin/apachectl startssl
$ netscape https://yourserver/
-
At this point you probably want to edit your web server
configuration and set the server on the standard ports 80 and 443 if
your test configuration did not use these ports.
-
See the
'security tips' in the online apache documentation for some help in
this area. One extra precaution to take is to change the permissions on
the httpd scripts and binaries:
ROOT# chmod ugo-rw
/www/apache/bin/*
-
You should be very careful when you set about deliberately escaping
from your chroot-ed environment -- you need to assess the risks and
benefits. In the UNIX world there is always more than one way to
accomplish a task, and you should think about other ways of solving your
problem.
Never the less, I provide an example C-utility that implements a
customised remote-shell command to email a file generated by forms output
to someone. It might be invoked via a cgi-bin script, or via PHP.
Example:
<?php
...
/** construct the file name as $f **/
$cmd = "/bin/mail \"-s Some-subject-line -t webmaster@localhost -f $f\"";
$op = exec( $cmd, $arr, $retval );
...
?>
The file is called wwwmail.c and it
is linked here.
Almost anything can be done this way if you code-up your own small
utility. I have written a similar utility to exec sqlplus macros for
example. But these sorts of utilities are risky, and need to be
carefully evaluated.
For this particular problem (emailing forms-output to someone) you might
be better off putting files to be mailed in a directory and having a cron
job pass through every few minutes and process them...
-
Remove temporary links needed for installation of
apache and perl ( remember to put them back if you need to rebuild
or upgrade any package ):
ROOT# rm /apache /usr/Local
-
Automate the startup of Apache by installing a
startup script called httpd in /etc/rc.d/init.d/
Here are two examples:
Then run chkconfig on it to set the runlevel symbolic
links (and verify it with '--list'):
ROOT# chkconfig --add httpd
ROOT# chkconfig --list httpd
httpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
-
Automate log file trimming. On a Red Hat system
you can specify which log files and which parameters to use in
/etc/logrotate.conf. Here is an
example file
I haven't had time to totally document this, but you can use the RPM
contents from RPMs and create a chroot-ed web tree without
compiling the sources. To this end, I have these scripts. I will document
this technique more completely later...
- Script file based on Red Hat 7.0 that will
harvest the RPMs (RPMs must be installed on system)
- Script file for creating temporary SSL
key and certificate (testing purposes only!!!)
- Script file based on Fedora Core 2 that will
harvest the RPMs (RPMs are NOT installed on system with this version!)
- Example httpd startup file for FC 2 to be placed
in /etc/init.d/ and enabled with
ROOT# chkconfig --add httpd
- Script file 'apachectl' for FC 2 called
from /etc/init.d/httpd that does the actual chroot - modified slightly
by adding path to chroot tree. It also adds the mysql libraries to the
library path.
Denice Deatrich
Last modified: Wed Jan 5 11:59:32 PST 2005