Posts Tagged ‘apache’

Securing Apaches Header Information

When you install apache with default settings (./configure && make && make install) this is the header that your users are able to get:

[root@hostname] /usr/local/apache2 $ telnet localhost 80
Trying 127.0.0.1…
Connected to localhost.localdomain (127.0.0.1).
Escape character is ‘^]’.
HEAD / HTTP/1.0
HTTP/1.1 200 OK
Date: Tue, 24 Aug 2010 18:17:56 GMT
Server: Apache/2.2.16 (Unix)
Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
ETag: “7001c-2c-3e9564c23b600”
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html

Now what you could do is go and change your ServerTokens to Prod which is short for ProductOnly and would show only Apache. Like this:

[root@hostname] /usr/local/apache2 $ telnet localhost 80
Trying 127.0.0.1…
Connected to localhost.localdomain (127.0.0.1).
Escape character is ‘^]’.
HEAD / HTTP/1.0
HTTP/1.1 200 OK
Date: Tue, 24 Aug 2010 18:23:39 GMT
Server: Apache
Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
ETag: “7001c-2c-3e9564c23b600”
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html

Much better but you are still telling the world that you are using Apache. First thought would be that you can use mod_headers to just remove the Server: part of your headers but unfortunately this is not possible. Apache tags the Server: and Date: information to the header just before this is sent to the client. There is a bug for this issue but it has not been fixed and it has been around for 5 years.

My fix for this is to create a patch that sets the name “Apache” to whatever you would like. Here is a server that has been patched:

[root@hostname] /usr/local/apache2 $ telnet localhost 80
Trying 127.0.0.1…
Connected to localhost.localdomain (127.0.0.1).
Escape character is ‘^]’.
HEAD / HTTP/1.0
HTTP/1.1 200 OK
Date: Tue, 24 Aug 2010 18:23:39 GMT
Server: Freddys Secure HTTP Server
Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
ETag: “7001c-2c-3e9564c23b600”
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/htm

The file you want is Apache_source/include/ap_release.h then look for line 44:

#define AP_SERVER_BASEPRODUCT “Freddys Secure HTTP Server”

If you don’t like messing with the source code here is a patch that you can apply before running the configure… :

diff -rupN httpd-2.2.16/include/ap_release.h httpd-2.2.16_patched/include/ap_release.h
— httpd-2.2.16/include/ap_release.h 2010-07-21 12:26:44.000000000 -0600
+++ httpd-2.2.16_patched/include/ap_release.h 2010-08-24 12:40:09.000000000 -0600
@@ -41,7 +41,7 @@
*/
#define AP_SERVER_BASEVENDOR “Apache Software Foundation”
#define AP_SERVER_BASEPROJECT “Apache HTTP Server”
-#define AP_SERVER_BASEPRODUCT “Apache”
+#define AP_SERVER_BASEPRODUCT “Freddys Secure HTTP Server”

#define AP_SERVER_MAJORVERSION_NUMBER 2
#define AP_SERVER_MINORVERSION_NUMBER 2

Now put this patch in a file called apache_name.patch and run this command:

[root@hostname] ~/httpd-2.2.16 $  $ patch -p1 < ../apache_name.patch
patching file include/ap_release.h

Now like normal run ./configure && make && make install, set your ServerTokens to Prod and the Server: header should say whatever you change the AP_SERVER_BASEPRODUCT too.

Advertisements

How to generate a self-signed OpenSSL certificate for Apache

There are just a few quick and easy steps to generate a certificate without a passphrase for Apache. First you have to generate a key for your host:

[root@heimdull]# openssl genrsa 1024 > host.key

Generating RSA private key, 1024 bit long modulus
..........................................++++++
.........++++++
e is 65537 (0x10001)
Generating RSA private key, 1024 bit long modulus............. .............................++++++.........++++++e is 65537 (0x10001)

Now you have your host key file that you will use in the Apache configuration file and to generate the actual certificate

[root@heimdull]# openssl req -new -x509 -nodes -sha1 -days 365 -key host.key > host.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:GB
State or Province Name (full name) [Berkshire]:Berkshire
Locality Name (eg, city) [Newbury]: Newbury
Organization Name (eg, company) [My Company Ltd]:My Company Ltd
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:www.myserver.com
Email Address []:

Now you have to move these files somewhere that is related to you Apache installation and in your httpd.conf or httpd-ssl.conf file you will need these lines:

SSLEngine on
  SSLCertificateFile /Apache-home/ssl/host.crt
  SSLCertificateKeyFile /Apache-home/ssl/host.key

where does the php.ini file go?

The Problem

I needed to add more memory to php but by default php installed from source (configure && make && make install) does NOT install the php.ini file. So where is waldo?

The Fix

Here is a code snip that shows what configuration file IS loaded when php is executed:

[root@mybox php-5.2.10]# php -r "phpinfo();" | grep Configuration
Configuration File (php.ini) Path => /usr/local/lib
Loaded Configuration File => (none)
Configuration

This shows that the php.ini path is in /usr/local/lib. So I grabbed the php.ini-recommended, copied that file to /usr/local/lib/php.ini and this file has the memory_limit set to 128MB which should be enough for now….

[root@mybox php-5.2.10]# php -r "phpinfo();" | grep Configuration
Configuration File (php.ini) Path => /usr/local/lib
Loaded Configuration File => /usr/local/lib/php.ini
Configuration

Done!

Installing Apache HTTP Server with a quick-start config

The Problem

How to install Apache HTTP Server with a good baseline configuration file starter.

The Fix

When I install a Apache HTTP Server for a client or myself, small or large I follow a “standard” configuration setup which is very easy to build on later. For the most part I use CentOS or Redhat Enterprise edition servers but these steps should work on any Unix system. This might not be true for AIX which requires a little more hand-holding to make sure the compiler is installed correctly.

Content of this article

  • Download the source code from the Apache project website. ( Currently 2.2.11 )
  • Execute the configure, make and make install installation steps. ( With a few custom switches )
  • Setup the httpd.conf and associated files
  • Start your newly built Apache server
  • Done!

Download Apache

First step is to download the Apache source code and not binaries or rpms. I believe that using the source code will give the best performing most flexible installation of Apache. If you follow a few steps the actual “installation” procedure is not difficult and it will give you a good foundation to add/remove features later.

Go to this url http://httpd.apache.org/download.cgi and get the latest tgz or bz2 file, currently 2.2.11.

Compiling/installing the source for apache

I like to keep my source download in ~/Software/ so that I can go back and just re-compile and re-install the binaries if I need to add a module or two.

[root@coco ~]# cd ~/Software/httpd-2.2.11
[root@coco httpd-2.2.11]# “./configure” \
“–enable-ssl” \
“–enable-proxy” \
“–enable-proxy-balancer” \
“–enable-rewrite” \
“–enable-headers” \
“–enable-deflate” \
“–enable-cache” \
“–enable-expires” \
“–enable-mem-cache” \
“–enable-disk-cache” \
“–enable-file-cache” \
“–with-mpm=worker” \
“–disable-cgi –disable-asis” \
“–disable-autoindex” \
“–disable-userdir”

Let me explain

enable-ssl This is so that you can enable a secure port later.

enable-proxy/enable-proxy-balancer This is here to setup a connection to a backend server like Tomcat/Thin/Mongrel

enable-rewrite We are always going to need rewrite rules in the config file.

enable-headers Need this to enable monitoring of the server, and for mod_proxy we need to manipulate the header.

enable-deflate The old gzip module which will allow us to setup some content to be compressed with gzip

enable-cache/expires/mem-cache/disk-cache/file-cache Are all there so that we can enable the expires module.

with-mpm=worker I’m choosing to use the worker MPM as my default since most server I work with do have more than 1 CPU. If you are working on servers that only has one cpu use the prefork MPM.

[root@coco httpd-2.2.11]# make && make install

You will now have the apache server installed in /usr/local/apache2, this is the default install directory and if you would want to change this you need to add the –prefix=/my/directory/apache2 switch to the configure string and make && make install to install apache to the correct directory.

Apache startup script

The easiest and fastest way is to copy /usr/local/apache2/bin/apachectl to /etc/init.d/apache this will allow you todo /etc/init.d/apache start|stop|restart.

If you want a script that has more feedback you can use the following script:

#!/bin/bash
# httpd        Startup script for the Apache HTTP Server
# chkconfig: 2345 85 15
# description: Apache is a World Wide Web server.  It is used to serve \
#              HTML files and CGI.
# processname: httpd
# config: /usr/local/apache2/conf/httpd.conf
# pidfile: /var/run/apache2.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Start httpd in the C locale by default.
HTTPD_LANG=${HTTPD_LANG-"C"}

# This will prevent initlog from swallowing up a pass-phrase prompt if
# mod_ssl needs a pass-phrase from the user.
INITLOG_ARGS=""

# Path to the apachectl script, server binary, and short-form for messages.
apachectl=/usr/local/apache2/bin/apachectl
httpd=${HTTPD-/usr/local/apache2/bin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/apache2.pid}
lockfile=${LOCKFILE-/var/lock/subsys/apache2}
RETVAL=0

start() {
 echo -n $"Starting $prog: "
 LANG=$HTTPD_LANG daemon $httpd $OPTIONS
 RETVAL=$?
 echo
 [ $RETVAL = 0 ] && touch ${lockfile}
 return $RETVAL
}
stop() {
 echo -n $"Stopping $prog: "
 killproc $httpd
 RETVAL=$?
 echo
 [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}
reload() {
 echo -n $"Reloading $prog: "
 if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then
 RETVAL=$?
 echo $"not reloading due to configuration syntax error"
 failure $"not reloading $httpd due to configuration syntax error"
 else
 killproc $httpd -HUP
 RETVAL=$?
 fi
 echo
}

# See how we were called.
case "$1" in
 start)
 start
 ;;
 stop)
 stop
 ;;
 status)
 status $httpd
 RETVAL=$?
 ;;
 restart)
 stop
 start
 ;;
 condrestart)
 if [ -f ${pidfile} ] ; then
 stop
 start
 fi
 ;;
 reload)
 reload
 ;;
 graceful|help|configtest|fullstatus)
 $apachectl $@
 RETVAL=$?
 ;;
 *)
 echo $"Usage: $prog {start|stop|restart|condrestart|reload|status|fullstatus|graceful|help|configtest}"
 exit 1
esac

exit $RETVAL

Apache configuration file

I will step through the different sections of the main configuration file that I use as the template for my Apache servers.

# =================================================
# Basic settings
# =================================================
ServerName %{SERVER_NAME}
ServerRoot "/usr/local/apache2"
PidFile "/var/run/apache2.pid"
# =================================================
# Performance settings
# =================================================
Timeout 30
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 2
<IfModule mpm_prefork_module>
 StartServers            1
 MinSpareServers         1
 MaxSpareServers         10
 MaxClients              25
 MaxRequestsPerChild     1000
</IfModule>
<IfModule mpm_worker_module>
 ServerLimit             16
 StartServers             2
 MaxClients              40
 MinSpareThreads          5
 MaxSpareThreads         20
 ThreadsPerChild         20
 MaxRequestsPerChild   5000
</IfModule>

The Basic section is just there for Apaches Root directory. Next we have a Timeout of 30 seconds which is enough for most setups the default of 300 is way too long. We enable keepalive BUT the keepalive timeout is only 2 seconds which allows each user to get their own connection but the connection will close as soon as they download the page they requested ( You can play with this timeout and have it set somewhere in the 1-5 sec range ). Then I setup perfork and worker depending on the number of cpus that are installed on the Apache server.

# =================================================
# General settings
# =================================================
Listen 80
# Listen 443
User www
Group www
ServerAdmin webmaster@openlogic.com
UseCanonicalName Off
ServerTokens Prod
ServerSignature Off
HostnameLookups Off
ExtendedStatus On
# =================================================
# Modules
# =================================================
#LoadModule dummy_module /usr/lib/apache2/modules/mod_dummy.so

Next sections we listen to port 80 but also have 443 if we want.( I will show you later how to setup a https/SSL/Secure virtualhost ) User and Group is the www user which is a system user. ( On Redhat you create a system user with the -r switch. adduser -r www ). We dont want the server to lookup hostname or show a signature to our users. The ExtendedStatus is on for monitoring reasons.The dummy module is there if we want to install php later down the road.

# =================================================
# Access control
# =================================================
<Directory />
 Options FollowSymLinks
 AllowOverride None
 Order deny,allow
 Deny from all
</Directory>
<DirectoryMatch "^/.*/\.svn/">
 ErrorDocument 403 /404.html
 Order allow,deny
 Deny from all
 Satisfy All
</DirectoryMatch>
<FilesMatch "^\.ht">
 Order allow,deny
 Deny from all
 Satisfy All
</FilesMatch>
# =================================================
# MIME encoding
# =================================================
DefaultType text/plain
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl

First things first, Deny from all. This makes sure we have to allow access to any directory that is used in the Apache configuration. Then we make sure that users don’t have access to .svn directories or .ht files. We also have a minimal mimetype setup. ( for the deflate and ssl modules. )

# =================================================
# Logs
# =================================================
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
ErrorLog /usr/local/apache2/logs/error_log
# Mark requests for the robots.txt file
SetEnvIf Request_URI "^/robots\.txt$" dontlog
SetEnvIf Request_URI "^\/monit\/token$" dontlog
# =================================================
# SSL Configuration
# =================================================
SSLPassPhraseDialog  builtin
SSLSessionCache        shmcb:/usr/local/apache2/logs/ssl_scache(512000)
SSLSessionCacheTimeout  300
SSLMutex  file:/usr/local/apache2/logs/ssl_mutex
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin

Now we setup the logformat for use in our virtualhosts and the server error log file. We also mark two dontlog Env which removes the robot.txt and monit/token hits from the log. When we created the virtualhost I will show how this is used. We also setup a default ssl configuration for the server.

# =================================================
# Mod status for monitoring
# =================================================
<VirtualHost 127.0.0.1:80>
 <Location /server-status>
 SetHandler server-status
 Order Deny,Allow
 Deny from all
 Allow from localhost
 Allow from 127.0.0.1
 </Location>
</VirtualHost>
# =================================================
# Include extra configs
# =================================================
Include conf/extra/httpd-myblog.com.conf

Now the server monitoring setup. We allow only access from localhost and it will only listen to the 127.0.0.1 ip. This is a good setup for tools like Groundworks and Hyperic. The last line includes a virtualhost configuration file. Now lets have a look at the virtualhost

Virtualhosts using a namebased setup

I like to have my httpd.conf with server-wide settings and free of actual content hosting elements or mod_proxy/mod_jk configurations. In this example I have a blog that’s running on a Ruby on Rails backend with three thin ( Thin is one RoR application server ) servers listening to ports 8000- 8002.

# --------------------------------------------------------
# Always keep the host header
# --------------------------------------------------------
ProxyPreserveHost On
# --------------------------------------------------------
# Rails Cluster
# --------------------------------------------------------
<Proxy balancer://rails-cluster>
  BalancerMember http://127.0.0.1:8000
  BalancerMember http://127.0.0.1:8001
  BalancerMember http://127.0.0.1:8002
</Proxy>

This setup has three servers in a proxy_balancer cluster that you can access using balancer://rails-cluster/ just as it was one server.

# --------------------------------------------------------
# name-based virtual hosting.
# --------------------------------------------------------
NameVirtualHost *:80

<VirtualHost *:80>
 DocumentRoot "/var/www/myblog.com/current/public"
 ServerName www.myblog.com
 ServerAlias myblog.com

 # -------------------------------------------------
 # Rewrite rules
 # -------------------------------------------------
 RewriteEngine on

 # Force www.myblog.com and make sure we use a 301 HTTP code for the redirect. This is a SEO must.
 RewriteCond %{HTTP_HOST}   !^www\.myblog\.com [NC]
 RewriteCond %{HTTP_HOST}   !^$
 RewriteRule ^/(.*)         http://www.myblog.com/$1 [L,R=301]

 # --------------------------------------------------------
 # List of urls not to proxy
 # --------------------------------------------------------
 ProxyPass /system !
 ProxyPass /images !
 ProxyPass /stylesheets !
 ProxyPass /javascripts !
 ProxyPass /monit/token !
 # Send everything else to the proxy_balancer cluster of rails servers
 ProxyPass / balancer://rails-cluster/
 ProxyPassReverse / balancer://rails-cluster/

 <Directory "/var/www/myblog.com/current/public">
  Options FollowSymLinks
  AllowOverride None
  Order allow,deny
  Allow from all
 </Directory>
 # Before you restart the server you need to create the logs/myblog.com directory.
 # We are also adding the dontlog environment variable here to stop logging the set entries. (This is configured in your httpd.conf)
 ErrorLog  "logs/myblog.com/error_log"
 CustomLog "logs/myblog.com/access_log" combined env=!dontlog

 # --------------------------------------------------------
 # Deflate Module Configuration
 # --------------------------------------------------------
 <IfModule deflate_module>
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/atom_xml
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/x-httpd-php
  AddOutputFilterByType DEFLATE application/x-httpd-fastphp
  AddOutputFilterByType DEFLATE application/x-httpd-eruby
  AddOutputFilterByType DEFLATE text/html
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4.0[678] no-gzip
 </IfModule>
 # =============================================
 # Configure expires Module
 # =============================================
 <IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType text/html "access plus 1 seconds"
  ExpiresByType image/gif "access plus 1 week"
  ExpiresByType image/jpeg "access plus 1 week"
  ExpiresByType image/png "access plus 1 week"
  ExpiresByType text/css "access plus 1 week"
  ExpiresByType text/javascript "access plus 1 week"
  ExpiresByType application/x-javascript "access plus 1 week"
  ExpiresByType text/xml "access plus 1 seconds"
 </IfModule>
</VirtualHost>

Here there is alot of information lets try to take it step by step. First we setup a server with the name http://www.myblog.com that also listens to myblog.com but by using mod_rewrite we force everyone to http://www.myblog.com with a 301 redirect. Then we setup all of the static content that we want apache to server from the local filesystem using ProxyPass with a ! to say “do not proxypass” these directories and then we send everything else to the balancer cluster. We setup the access rights to the static directory where our content is stored ( images, javascript, uploaded files and other things like css. ) Now we setup the virtualhosts log file in its own directory inside the logs directory. The mod_deflate and mod_expires configurations work for most setups BUT this piece needs to be monitored and tuned to your setup. I have seen the mod_expires setup give me problems using rails and authentication.

Now of to a secure.myblog.com virtualhost

<VirtualHost _default_:443>
 DocumentRoot "/var/www/myblog.com/current/public"
 ServerName secure.myblog.com
 ServerAlias www.myblog.com myblog.com
 RewriteCond %{HTTP_HOST}   !^secure\.myblog\.com [NC]
 RewriteCond %{HTTP_HOST}   !^$
 RewriteRule ^/(.*)         https://secure.myblog.com/$1 [L,R=301]
 # --------------------------------------------------------
 # List of urls not to proxy
 # --------------------------------------------------------
 ProxyPass /system !
 ProxyPass /images !
 ProxyPass /stylesheets !
 ProxyPass /javascripts !
 ProxyPass / balancer://rails-cluster/
 ProxyPassReverse / balancer://rails-cluster/

 ErrorLog  "logs/myblog.com/error_log"
 CustomLog "logs/myblog.com/access_log" combined env=!donlog

 # --------------------------------------------------------
 # SSL Certificates
 # --------------------------------------------------------
 SSLEngine on
 SSLCertificateFile    /usr/local/apache2/ssl/secure.myblog.com.crt
 SSLCertificateKeyFile /usr/local/apache2/ssl/secure.myblog.com.key
 # --------------------------------------------------------
 # Deflate Module Configuration
 # --------------------------------------------------------
 <IfModule deflate_module>
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/atom_xml
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/x-httpd-php
  AddOutputFilterByType DEFLATE application/x-httpd-fastphp
  AddOutputFilterByType DEFLATE application/x-httpd-eruby
  AddOutputFilterByType DEFLATE text/html
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4.0[678] no-gzip
 </IfModule>
 # =============================================
 # Configure expires Module
 # =============================================
 <IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType text/html "access plus 1 seconds"
  ExpiresByType image/gif "access plus 1 week"
  ExpiresByType image/jpeg "access plus 1 week"
  ExpiresByType image/png "access plus 1 week"
  ExpiresByType text/css "access plus 1 week"
  ExpiresByType text/javascript "access plus 1 week"
  ExpiresByType application/x-javascript "access plus 1 week"
  ExpiresByType text/xml "access plus 1 seconds"
 </IfModule>
 # --------------------------------------------------------
 # Document root /
 # --------------------------------------------------------
 <Directory "/var/www/myblog.com/current/public">
  Options FollowSymLinks
  AllowOverride None
  Order allow,deny
  Allow from all
 </Directory>
 # -------------------------------------------------
 # Fixing yet abother IE 6 bug
 # -------------------------------------------------
 BrowserMatch ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
 # -------------------------------------------------
 # Add this to the request header so that
 # rails puts the correct redirect in place
 # -------------------------------------------------
 RequestHeader set X_FORWARDED_PROTO 'https'
</VirtualHost>

This is very similar to the port 80 virtualhost of the same name. the biggest difference is the ssl certificates and then the bottom ssl/https settings to fix issues with Mongrel/rails and ie6. You can’t configure mod_expires and mod_deflate in the main configuration file and have the virtuallhost inheret the configuration so the best solution to be dry would be to put these settings in their own mod_deflate.conf and mod_expires.conf and then include the named configuration files in each virtualhosts configuration file like so:

Include conf/mod_deflate.conf
Include conf/mod_expires.conf

Conclusion

Apache with mod_proxy rocks 🙂 What we have here is Apache that is ready to be expanded to a high performance webserver or proxy server, or both. I like to start with this setup and then build from here but if you had to get more concurrent clients and throughput through your Apache server I would look at your available memory and cpu cycles and maybe do something like so:

<IfModule mpm_worker_module>
  ThreadLimit 100
  StartServers 5
  MaxClients 1000
  MinSpareThreads 100
  MaxSpareThreads 1000
  ThreadsPerChild 100
  MaxRequestsPerChild 0
</IfModule>

This is a high threads and low processes setup and to get the number of processes that Apache will use simply divide MaxClients by ThreadPerChild. So this gives us 10 processes each with a maximum of 100 threads, with a maximum of 1000 clients total. Depending on the server and type of content that you are serving you can load test and increase these settings if you need more than 1000 concurrent users.

I’m a very big fan of mod_proxy and I use mod_proxy_ajp inplace of mod_jk every chance I get. ( I also talk my customers into using mod_proxy over mod_jk if they are using Apache 2.2.x )

Using this setup to include the virtualhosts that the server runs I feel it is easy to add/remove new websites to this setup and it also gives me a good overview of what is running on the server.

mod_mem_cache.c:591: undefined reference to `ap_cache_cacheable_hdrs_out’

If you are getting this error, it’s because you’ve included the ‘--enable-mem-cache‘ flag, but not the ‘--enable-cache‘ one. You need both.

enable-disk-cache also needs the same enable-cache switch to work.

Using thin with rails (apache frontend)

prerequisites (running on redhat/centos 5)

ruby 1.8.6+ (download, untar, configure, make, make install [reboot])
rubygems (download, untar, ruby rubygems/setup.rb)
rails (gem install rails)
thin (gem install thin)
apache 2.2 (installs apache to /usr/local/apache2 with mod_proxy/_balancer)

  • download
  • untar
  • ./configure –enable-proxy –enable-proxy-balancer –enable-rewrite –enable-deflate –enable-headers
  • make && make install

Install the thin run script
# thin install

Installing the thin configuration file
# vi /etc/thin/thin_conf.yml

user: daemon
group: daemon
chdir: /var/www/rails_app/current
log: log/mongrel.log
pid: tmp/pids/mongrel.pid
environment: production
port: 8000
address: 127.0.0.1
servers: 3

# /etc/init.d/thin start

Now lets add the proxy configs to apache…

in httpd.conf:

Include conf/extra/*.conf

now add your vhost config in conf/extra/httpd-rails_app.conf …

# vi conf/extra/httpd-rails_app.conf

# Always keep the host header
ProxyPreserveHost On


BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002


ServerName http://www.rails_app.com
ServerAlias rails_app.com
DocumentRoot /var/www/rails_app/current/public


Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all

ProxyPass /images !
ProxyPass /javascripts !
ProxyPass /stylesheets !
ProxyPass /uploads !
ProxyPass /photos !

ProxyPass / balancer://rails_cluster/
ProxyPassReverse / balancer://rails_cluster/

# =============================================
# Configure Deflate Module (gzip)
# =============================================

AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom_xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-httpd-php
AddOutputFilterByType DEFLATE application/x-httpd-fastphp
AddOutputFilterByType DEFLATE application/x-httpd-eruby
AddOutputFilterByType DEFLATE text/html
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip

# =============================================
# Virtualhost logs
# =============================================
# Mark requests for the robots.txt file
SetEnvIf Request_URI “^/robots\.txt$” dontlog

ErrorLog logs/www/error_log
CustomLog logs/www/access_log combined env=!dontlog

# /usr/local/apache2/bin/apachectl start

rails thin apache all working together…. 🙂