The goal of this document is to provide assistance in building a Linux-based Apache, MySQL and PHP webserver, affectionately known as LAMP. We'll also cover the optional installation of bells and whistles including, but not limited to, secure imapd/ipop3d and cryptographic/hash libraries. Many documents assist you in building Apache with another single package, but for using more than one package the waters start to get a little murky and the instructions start to contradict.
Apache is an HTTP server designed as a plug-in replacement for the NCSA HTTP server. It fixes numerous bugs in the NCSA server and includes many frequently requested new features, and has an API which allows it to be extended to meet users' needs more easily. Apache is the most popular web server in the known universe; over half of the servers on the Internet are running Apache or one of its variants. Apache is available at http://httpd.apache.org.
You'll want to install the latest version of Apache 1.3.x. Currently, PHP support for Apache 2.x is experimental and not recommended by the PHP team. The main issue is thread safety, which requires a lot of code verification time and effort.
Next, 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. 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
OpenSSL is essentially a set of cryptographic routines and libraries for the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols. 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 at http://www.openssl.org/source/.
Note: If you have a SMP (multi-processor) machine, add the paramater threads to the config syntax line below to benefit from multi-threading support.
$ ./config --prefix=/usr --openssldir=/etc/ssl shared zlib
$ make
$ make test
# make install
# cp -fa /etc/ssl/man /usr && rm -rf /etc/ssl/man
# 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 /etc/ssl/certs
# openssl genrsa -des3 -out myserver.key 1024
# chmod 400 myserver.key
Next, generating your server's Certificate Signing Request:
# cd /etc/ssl/certs
# openssl -req -new -key myserver.key -out 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 Appendix 1 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. ModSSL is available at http://www.modssl.org/source/.
$ ./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. It operates embedded into the web server, acting as a powerful umbrella, shielding applications from attacks. ModSecurity is available from http://www.modsecurity.org/.
$ cp apache1/mod_security.c ../apache_1.3.x/src/modules/extra/
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 SSLCERTS=/etc/ssl/certs SSLINCLUDE=/usr/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 \--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-huge.cnf /etc/my.cnf
# echo "/usr/lib/mysql" >> /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
Mhash is a library which provides a uniform interface to a large number of hash algorithms. These algorithms can be used to compute checksums, message digests, and other signatures. It's available at http://mhash.sourceforge.net.
$ ./configure --prefix=/usr $ make $ make check # make install # ldconfig -v
Mcrypt enables add-on support of string encryption and decryption, which is much broader and more efficient than PHP's own cryptographic code. This is mainly used for saving sensitive data to disk that you need to decrypt at a later time. If you only want to encrypt (and not decrypt) strings, or aren't interested in the advanced cryptographic functions this module profides, skip this feature and use the built-in PHP function crypt() instead. Installation of mcrypt requires both mhash and libmcrypt. Libmcrypt is a library that provides uniform interface to access several encryption algorithms, and is used primarily by mcrypt. Both MCrypt and Libmcrypt are available at http://sourceforge.net/projects/mcrypt.
$ ./configure --prefix=/usr $ make $ make check # make install # ldconfig -v
PHP (a recursive acronym for "PHP: Hypertext Preprocessor") is a widely-used Open Source general-purpose scripting language that is especially suited for Web development and can be embedded into HTML. 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.
Note that some of these configuration parameters require some common sense. For example, if you specify "--with-mysql=/usr", then you'd better have already installed MySQL!
$ ./configure --prefix=/usr \
--sysconfdir=/etc \
--with-config-file-path=/etc \
--with-mysql=/usr \
--with-apache=../apache_x.y.z \
--with-openssl \
--with-imap=/usr/include/imap \
--with-imap-ssl \
--with-mhash \
--with-mcrypt \
--enable-memory-limit \
--enable-inline-optimization \
--enable-sysvsem \
--disable-debug \
--enable-track-vars \
--disable-cgi \
--with-gettext \
--enable-ftp \
--enable-safe-mode
$ make
# make install
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 | 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 |
| --with-mhash | Include PHP code for integrating with mhash |
| --with-mcrypt | Include PHP code for integrating with mcrypt. This is much broader and more efficient than PHP's built-in cryptographic code. This is mainly used for saving sensitive data to disk that you need to decrypt at a later time. If you only want to encrypt (and not decrypt) strings, or aren't interested in the advanced cryptographic functions this module profides, skip this feature and use the built-in PHP function crypt() instead. |
| --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 |
| --enable-sysvsem | Enable System V sempahore (specialized file locking to prevent simultaneous access) support. |
| --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 |
The PHP Configuration file is located in /etc/php.ini and is not created by default. To create your initial PHP configuration file, run:
# cp php.ini-recommended /etc/php.ini
Next, make the following adjustments to your /etc/php.ini file:
safe_mode = On
safe_mode_gid = Off
safe_mode_exec_dir = /web/exec
safe_mode_include_dir = /web/include
open_basedir = /web
expose_php = Off
display_errors = Off
log_errors = On
error_log = /web/log/php.log
register_globals = Off
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.
$ SSL_BASE=SYSTEM ./configure --prefix=/usr \
--sysconfdir=/etc/apache \
--sbindir=/usr/sbin \
--logfiledir=/var/log \
--runtimedir=/var/run \
--datadir=/web \
--iconsdir=/web/icons \
--htdocsdir=/web/default \
--disable-module=all \
--enable-module=access \
--enable-module=log_config \
--enable-module=dir \
--enable-module=mime \
--enable-module=auth
--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/sbin/httpd
# mkdir -p /web/secure
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 |
| --sbindir=/usr/sbin | Install Apache's system binaries in /usr/sbin rather than /usr/local/apache/bin or /usr/bin |
| --logfiledir=/var/log/ | Install Apache log files in the /var/log directory rather than /usr/local/apache/log |
| --runtimedir=/var/run | Store Apache's runtime files in /var/run |
| --datadir=/web | Apache's cgi-bin directory will be installed in the /web/cgi-bin directory (no, this is not a typo). |
| --iconsdir=/web/icons | Apache's graphic files will be installed in the /web/icons directory. |
| --htdocsdir=/web/default | Apache's web pages will be located in the /web/default directory. |
| --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 ModSecurity:
AddModule mod_security.c
<IfModule mod_security.c>
SecFilterEngine On
SecFilterCheckURLEncoding On
SecFilterForceByteRange 32 126
SecAuditEngine RelevantOnly
SecAuditLog /web/log/audit.log
SecFilterDebugLog /web/log/audit-debug.log
SecFilterDebugLevel 0
SecFilterDefaultAction "deny,log,status:406"
SecFilter "<( |\n)*script>"
SecFilter "<(.|\n)+>"
SecFilter "\.\./"
</IfModule>
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_mutex
SSLSessionCache 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