David Lechnyr <davidrl * at * comcast * dot * net>
April 01, 2004
13:10:20
It was all so different before everything changed.
Apache is an open-source web server. Currently, there are three main flavors of Apache available: Apache 1.3.x, Apache 2.x, and Apache-SSL. Since it is not recommended to run Apache 2.x with PHP, and Apache-SSL tends to drag behind in version releases, we'll be building Apache 1.3.x. However, don't worry -- we'll be adding SSL support into our Apache build shortly. Apache is available for download from http://httpd.apache.org/.
To start, we need to configure the source tree for Apache first before installing any of the other associated programs. You'll get a warning message about compiling with default settings; don't worry; we will do the actual configuration of apache later. This is just a preliminary configure, required just to get things going. Without this, some of your other packages won't install into the apache source tree correctly. At this stage in the game, we don't actually make the binaries as we haven't integrated all the other software bits (like PHP) yet. Simply run:
$ ./configure
Ignore any warnings you get. Again, we won't actually build Apache yet; we just want to prepare it so that we can graft in our other programs first.
OpenSSL is essentially a set of cryptographic routines and libraries for the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols. Programs that typically make use of these routines and libraries include anything that can use SSL, including Apache, imapd/ipop3d, and OpenSSH. By itself, OpenSSL won't do much. Its chief benefit is that it provides these libraries for use by other applications which can take advantage of its functionality. OpenSSL is available for download from http://www.openssl.org/source/.
$ ./config --prefix=/usr/local/openssl --openssldir=/etc/ssl shared zlib threads $ make $ make test # make install # echo "/usr/local/openssl/lib" >> /etc/ld.so.conf # ldconfig -v
To run a SSL Server, you'll need to first generate your server's SSL Private Key. This is an RSA 1024 bit key. No one should have access to this file other than yourself. RSA is a public-key encryption technology developed by RSA Data Security, Inc. The acronym stands for Rivest, Shamir, and Adelman, the inventors of the technique. The RSA algorithm is based on the assumption that there is no efficient way to factor very large numbers. Deducing an RSA key therefore requires an extraordinary amount of computer processing power and time. You will never want to delete this key. To creatue it, use:
# cd /usr/local/openssl/bin
# ./openssl genrsa -des3 -out /etc/ssl/certs/myserver.key 1024
# chmod 400 /etc/ssl/certs/myserver.key
Next, generating your server's Certificate Signing Request:
# ./openssl -req -new -key /etc/ssl/certs/myserver.key -out /etc/ssl/certs/myserver.csr
Finally, you must submit the myserver.csr file to a valid Certificate Authority (CA) in order to receive your server's authorized SSL certificate. You can either submit this to a valid certificate authority (such as VeriSign or Thawte) or pretend to be your own Certificate Authority. If you plan on interacting with the rest of the world, you'll probably want to purchase a valid certificate rather than make your own. Otherwise, see the Appendix for additional details on becomming your own Certificate Authority. Regardless of the method you use to procure your server's SSL certificate, once you have it, store it in /etc/ssl/certs/myserver.crt with a chmod value of 400.
ModSSL allows you to add SSL support for Apache. Here, we will apply the ModSSL source extension and source patches to the Apache source tree. The actual installation of ModSSL is done when you install Apache.
$ ./configure --with-apache=../apache-1.3.x \ --with-crt=/etc/ssl/certs/myserver.crt \ --with-key=/etc/ssl/certs/myserver.key
ModSecurity is an open source intrusion detection and prevention engine for web applications. Operating as an Apache Web server module, the purpose of ModSecurity is to increase web application security, protecting web applications from known and unknown attacks. Some of its features include:
Download the program from http://www.modsecurity.org/ and verify that it hasn't been tampered with:
$ wget http://www.modsecurity.org/download/mod_security-1.7.6.tar.gz $ wget http://www.modsecurity.org/download/mod_security-1.7.6.tar.gz.asc $ wget http://www.webkreator.com/download/ivanr_webkreator_com.pub $ gpg --import ivanr_webkreator_com.pub $ gpg --verify mod_security-1.7.6.tar.gz.asc
Uncompress it and copy the module directly into your Apache source code:
$ tar xzvf mod_security-1.7.6.tar.gz $ cp mod_security-1.7.6/apache1/mod_security.c ../apache_1.3.x/src/modules/extra/
This will allow mod_security to be installed statically into Apache. When we finish compiling Apache later on, we'll be using two new directives (--activate-module=src/modules/extra/mod_security and --enable-module=security) to enable this new code.
Of course, you will ultimately need to add specific directives to your Apache configuration file to make mod_security actually do anything. Take a look at files httpd.conf.example-minimal or httpd.conf.example-full in the mod_security tarball to get some idea of what to do. Or even better, read the PDF manual included in the tarball.
imapd is a POP3/IMAP server from the folks at the University of Washington. As an added bonus, it provides access via SSL if configured correctly for use with OpenSSL. It is also commonly referred to as the "c-client library". It is available for download at ftp://ftp.cac.washington.edu/imap/.
Setting up imapd can be really frustrating. Actually, I take that back; setting up secure imapd is the frustrating bit. This is mostly due to the apparent lack of any customer-service talent from the folks who produce imapd. Reading the documentation is akin to an experience with a lurking singular, sinister attitude of mind. For example:
"We can NOT provide you with support in building/installing OpenSSL, or in obtaining certificates. If you need help in doing this, try the contacts mentioned in the OpenSSL README." -- docs/SSLBUILD
Never mind the vagueness with the contacts or the lack of said references in the OpenSSL README. Granted, most of what they implement, they implement well. But where it doesn't work on the client end, or where it relies on outside sources (i.e., the not us syndrome), they deflect, deny, and blame others for not following the "official IMAP standards". Given that type of tone, I have to agree with the following philosophy regarding such things:
"Take TCP for example. The TCP protocol is specified in a series of documents. If you make a formally correct implementation of the base TCP RFC you won't even make connections. Much of the flow control behaviour, the queueing and the detail is learned only by being directly part of the TCP implementing community. You can read all the scientific papers you like, it will not make you a good TCP implementor." -- Linux-kernel posting by Alan Cox
Current versions of imapd are now built with TLS/SSL encryption support by default. Since imapd incorrectly assumes we installed OpenSSL in /usr/local/openssl, we need to pass on a few other arguments to our make command. Assuming you're building for a generic Linux system, you can run:
# make slx SSLDIR=/usr/local/openssl \ SSLCERTS=/etc/ssl/certs \ SSLINCLUDE=/usr/local/openssl/include/openssl # cp -fa imapd/imapd /usr/sbin/ # cp -fa ipopd/ipop3d /usr/sbin/
Modify your mail spool permissions. We'll assume your mail spool is located in /var/spool/mail; if not, adjust the following command to fit:
# chmod 1777 /var/spool/mail
Next, update /etc/services if necessary with:
imaps 993/tcp
pop3s 995/tcp
Finally, update /etc/xinetd.conf with:
service pop3s
{
socket_type = stream
protocol = tcp
wait = no
user = root
server = /usr/sbin/ipop3d
}
service imaps
{
socket_type = stream
protocol = tcp
wait = no
user = root
server = /usr/sbin/imapd
}
If you're using inetd instead of xinetd, update /etc/inetd.conf with:
pop3s stream tcp nowait root /usr/sbin/ipop3d ipop3d
imaps stream tcp nowait root /usr/sbin/imapd imapd
You'll need to run a "kill -HUP inetd" or "kill -HUP xinetd" to activate your changes.
Generate your PEM Private Key. Essentially, this is the same file as your webserver's Private Key saved in a different format. PEM stands for Privacy Enhanced Mail.
# cd /etc/ssl/certs
# openssl rsa -outform PEM -in myserver.key -out temp.pem
# chmod 400 temp.pem
Next, generate your PEM Public Key. This is actually just a copy of your PEM Private Key and your CRT Public Key concatenated into a single file. Without this, you can't do SSL email. You will never want to delete this key
# cd /etc/ssl/certs
# cat temp.pem myserver.crt > imapd.pem# chmod 400 imapd.pem
# ln -sf imapd.pem ipop3d.pem
# rm -f temp.pem
To integrate POP/IMAP support into PHP, you'll need to copy the following file to your system. The commands below work for imap-2002e. Note: This gets more tricky each time there's a new revision of imapd, so your mileage may vary.
# mkdir -p /usr/include/imap/{lib,include}
# cp c-client/linkage.h c-client/osdep.h /usr/include/imap/include/
# cp c-client/auths.c /usr/include/imap/lib/ # cp src/c-client/*.h /usr/include/imap/include/ # cp src/osdep/unix/*.h /usr/include/imap/include/
# cp src/c-client/*.c /usr/include/imap/lib/ # cp src/osdep/unix/*.c /usr/include/imap/lib/ # cp c-client/c-client.a /usr/include/imap/lib/libc-client.a
# ln -s /usr/include/imap/include/os_slx.h /usr/include/imap/include/osdep.h
MySQL is a fast, multi-threaded, multi-user and robust SQL (Structured Query Language) database server. It comes with a nice API which makes it easy to integrate into other applications, including PHP. Version 4 has additional advantages such as faster transactions and the default use of InnoDB tables. If you don't install MySQL, PHP will instead use a scaled-down version of SQL. This is probably not what you want if you plan to do web-based database integration with PHP
Prior to installing MySQL, you must first create a mysql user and group:
# groupadd mysql
# useradd -g mysql -d /dev/null -s /bin/false mysql
Then, build MySQL with:
$ CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" \ CFLAGS="-O3" CC=gcc CXX=gcc \ ./configure --prefix=/usr/local/mysql \ --localstatedir=/var/lib/mysql \ --with-extra-charsets=none \ --without-bench \ --without-debug \ --without-readline \ --with-mysqld-user=mysql \ --enable-assembler \ --enable-thread-safe-client \ --with-client-ldflags=-all-static $ make # make install # cp support-files/my-medium.cnf /etc/my.cnf # echo "/usr/local/mysql/lib" >> /etc/ld.so.conf # ldconfig -v
The meaning of the configuration switches are:
To have MySQL start automatically when your system boots, copy support-files/mysql.server to the location where your system has its startup files and make it executable with chmod 755. If you plan to run MySQL and Apache on the same server, you can disable the networking options in MySQL since you'll never need them (everything's on the same server). This is generally considered a good idea since it cuts down on security issues across the network, and is probably what you want. Edit the mysql.server startup script and make sure to add --skip-networking to the safe_mysqld command.
To prepare the necessary database format for MySQL, run:
# mkdir -p /var/lib/mysql
# chown -R mysql /var/lib/mysql
# chgrp -R mysql /var/lib/mysql
# scripts/mysql_install_db
$ mysqladmin -u root -p password '<new-password>'
$ mysqladmin -u root -h <hostname> -p password '<new-password>'
To backup your MySQL database, you should run something similar to this:
$ mysqldump --all-databases -u root -p > all_databases.sql
$ chmod 400 all_databases.sql
To restore your database from a backup file, you can use:
mysql -u root -p < all_databases.sql
To analyze, check and optimize (respectively) your tables, you can run:
$ mysqlcheck --all-databases -u root -avp
$ mysqlcheck --all-databases -u root -cvp
$ mysqlcheck --all-databases -u root -ovp
PHP is a general-purpose scripting language that is especially suited for creating dynamic web pages. What distinguishes PHP from something like client-side JavaScript is that the code is executed on the server. The best things in using PHP are that it is extremely simple for a newcomer, but offers many advanced features for a professional programmer.
Download PHP from http://www.php.net/ and verify that it hasn't been tampered with. Since they only provide the MD5 signatures, and not a PGP key, we'll need to compare the md5 signature of our downloaded file with what is listed on their website download page.
$ wget http://us1.php.net/distributions/php-4.3.5.tar.bz2 $ md5sum php-4.3.5.tar.bz2
Uncompress the PHP source code and run the configuration instructions. Note that some of these configuration parameters require some common sense. For example, if you specify "--with-mysql=/usr/local/mysql", then you'd better have already installed MySQL!
$ tar xjvf php-4.3.5.tar.bz2 $ cd php-4.3.5 $ ./configure --prefix=/usr \ --sysconfdir=/etc \ --with-config-file-path=/etc \ --with-mysql=/usr/local/mysql \ --with-apache=../apache_x.y.z \ --with-openssl \ --with-imap=/usr/include/imap \ --with-imap-ssl \ --enable-memory-limit \ --enable-inline-optimization \ --disable-debug \ --enable-track-vars \ --disable-cgi \ --with-gettext \ --enable-ftp $ make # make install # cp php.ini-recommended /etc/php.ini
These configuration options roughly translate to:
--prefix=/usr | Install library, header, pear & manpage files in /usr instead of /usr/local |
--sysconfdir=/etc | Install PEAR system configuration file in /etc instead of /usr/etc |
--with-config-file-path=/etc | Store the main php.ini configuration file in /etc rather than /usr/lib |
--with-mysql=/usr/local/mysql | Include PHP code for integrating with MySQL |
--with-apache=../apache_x.y.z | Include PHP code for integrating with Apache. Since this is generally considered a good idea, just say yes. |
--with-openssl | Include PHP code for integrating generic SSL support |
--with-imap=/usr/include/imap | Include PHP code for integrating with POP/IMAP |
--with-imap-ssl | Include PHP code for integrating with secure (SSL) POP/IMAP |
--enable-memory-limit | Allows you to control the maximum amount of memory that a script can use. This helps to prevent buffer overflows (security). |
--enable-inline-optimization | Recommended by the PHP team if you have "lots of memory" and are using gcc as your compiler |
--disable-debug | Do not compile in debugging symbols |
--enable-track-vars | Just say yes. |
--disable-cgi | Do not create a stand-alone PHP cgi-binary (security). |
--with-gettext | Include PHP code to support internationalization |
--enable-ftp | Include PHP code to support built-in ftp functionality |
This is where we tie all our various and assorted parts into the final product. Our philosophy is simple: Only compile in what you need, and nothing more! We use static modules for the added speed benefit.
You'll also need to create an apache user and group if you want to run Apache as a user other than root, which is highly recommended:
# groupadd apache
# useradd -g apache -d /dev/null -s
/bin/false apache
$ SSL_BASE=SYSTEM ./configure --prefix=/usr/local/apache \ --sysconfdir=/etc/apache \ --disable-module=all \ --enable-module=access --enable-module=actions \ --enable-module=alias --enable-module=asis \ --enable-module=auth --enable-module=autoindex \ --enable-module=cgi --enable-module=dir \ --enable-module=env --enable-module=setenvif \ --enable-module=log_config --enable-module=mime \ --enable-module=ssl --enable-module=speling \ --disable-rule=SSL_COMPAT --enable-rule=SSL_SDBM \ --activate-module=src/modules/php4/libphp4.a \ --activate-module=src/modules/extra/mod_security \ --enable-module=security \ --server-uid=apache --server-gid=apache $ make # make install # chmod 0511 /usr/local/apache/bin/httpd
These configuration options roughly translate to:
SSL_BASE=SYSTEM | This variable tells Apache that the OpenSSL libraries are already installed on the system. |
--prefix=/usr | Install Apache in /usr rather than /usr/local/apache |
--sysconfdir=/etc/apache | Install Apache's configuration files in /etc/apache rather than /usr/local/apache/conf or /usr/etc |
--enable-module=ssl | Compile Apache with SSL support. |
--enable-module=speling | This module attempts to correct misspellings of URLs that users might have entered, by ignoring capitalisation and by allowing up to one misspelling (and yes, it's spelled correctly). |
--disable-rule=SSL_COMPAT | Build the final code of mod_ssl without backward compatibility code for Apache-SSL 1.x, mod_ssl 2.0.x, Sioux 1.x and Stronghold 2.x. |
--enable-rule=SSL_SDBM | This controls whether the built-in SDBM library should be used instead of a custom defined or vendor supplied DBM library. Enable this to force the use of SDBM in case the vendor DBM library is buggy or restricts the data sizes too dramatically. |
--activate-module=src/modules/php4/libphp4.a | Build Apache with PHP support. This file doesn't yet exist; this is normal. |
--server-uid=apache | The username to run Apache as (security). |
--server-gid=apache | The group to run Apache as (security). |
Make sure your /etc/apache/httpd.conf file includes the following entries to support PHP:
AddType application/x-httpd-php .php .inc .class
AddType application/x-httpd-php-source .phps
Make sure your /etc/apache/httpd.conf file includes the following entries to support SSL:
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
SSLProtocol all
SSLPassPhraseDialog builtin
SSLMutex file:/var/run/ssl_mutexSSLSessionCache dbm:/var/run/ssl_scache
SSLSessionCacheTimeout 300
SSLRandomSeed startup file:/dev/urandom 1024
SSLRandomSeed connect file:/dev/urandom 1024
SSLLog /var/log/apache_ssl.log
SSLLogLevel warn
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/ssl/certs/myserver.crt
SSLCertificateKeyFile /etc/ssl/certs/myserver.key
To start Apache, without SSL, use:
Or, to start Apache with SSL support, run:
apachectl start
apachectl startssl
To abruptly stop Apache, which will affect anyone currently connected to your web page, run:
apachectl stop
And finally, to gracefully restart Apache without adversely affecting anyone connected to your web page, use:
apachectl graceful
# openssl genrsa -des3 -out /etc/ssl/certs/ca.key 1024
# chmod 400 /etc/ssl/certs/ca.key
# openssl req -new -x509 -days 365 -key /etc/ssl/certs/ca.key -out /etc/ssl/certs/ca.crt
# mkdir /etc/ssl/certs/ca.db.certs
# echo '01' > /etc/ssl/certs/ca.db.serial
# touch /etc/ssl/certs/ca.db.index
You'll also need to create the file /etc/ssl/certs/ca.config with:
[ ca ] default_ca = CA_own [ CA_own ] dir = . certs = $dir new_certs_dir = $dir/ca.db.certs database = $dir/ca.db.index serial = $dir/ca.db.serial RANDFILE = $dir/ca.db.rand certificate = $dir/ca.crt private_key = $dir/ca.key default_days = 365 default_crl_days = 30 default_md = md5 preserve = no policy = policy_anything [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional
Finally, pretending to be a Certificate Authority, we sign our own server's request for its own certificate:
# cd /etc/ssl/certs
# openssl ca -config ca.config -out myserver.crt -infiles myserver.csr
# openssl verify -CAfile ca.crt myserver.crt