Wednesday, December 23, 2009

Start Apache as service in Linux (Fedora)

The Apache HTTP server is installed by default in all Linux distributions and it is configured to run as service. I usually prefer to install Apache from source instead of using the default one. After installing Apache I want to run that instance as service so that it can be restarted automatically whenever machine is rebooted. This can be achieved easily by modifying /etc/rc.d/init.d/httpd file, which is configured to run the Apache installed with OS.

Comment the following section, though it is not required but I prefer to keep all configuration at one place


if [ -f /etc/sysconfig/httpd ]; then
        . /etc/sysconfig/httpd
fi
Modify the following lines-
apachectl=/usr/sbin/apachectl
httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
to point towards your Apache installation
apachectl=/opt/apps/httpd-2.2.14/bin/apachectl
httpd=${HTTPD-/opt/apps/httpd-2.2.14/bin/httpd}
prog=httpd
pidfile=${PIDFILE-/opt/apps/httpd-2.2.14/logs/httpd.pid}
Now your custom Apache instance will be started by OS instead of the default one.

Monday, August 03, 2009

Getting started with Redmine

For sometime I was looking for a project management software, which can provide an integrated view of most of the project related artifacts/activities. Redmine was the most impressive tool, I came across. It has issue tracking, wiki, forum, documents, integration with third party tools (source repositories, LDAP etc.), plugin to integrate with Hudson and many more features. It has plugin based architecture, so possibilities are almost endless.

Redmine is written in Ruby (Ruby on Rail) and I know nothing about that other than spelling :-) I had to install several packages to get started with it. Redmine stores its data in a database and when it comes to open source DB, PostgreSQL is always my first choice. As a practice I prefer to serve all web applications through Apache and here I found an Apache module called Passenger, which can serve Ruby applications.

Here are my notes, which I took during installing Redmine and supporting applications.

  1. Install PostgreSQL for Linux
          $ ./postgresql-x.x.x-x.bin --mode text

    Follow the installer instructions to complete the installation. Make sure that PostgreSQL accepts connections from other than 'localhost' else you can't connect to DB from any other machine. This can be done by editing 'pg_hba' configuration file.

  2. Install Ruby, Redmine needs ruby 1.8.7-
          $ tar zxvf ruby-1.8.7-p174.zip
          $ cd ruby-1.8.7-p174
          $ ./configure --prefix=/opt/redmine/ruby-1.8.7
          $ make
          $ make install


    Add ruby to your classpath before executing further installation steps.

  3. Install ruby-gems, say rubygems-1.3.4
          $ unzip rubygems-1.3.4.zip
          $ cd rubygems-1.3.4
          $ ruby setup.rb

  4. Install rake
          $ unzip rake-0.8.7.zip
          $ cd rake-0.8.7
          $ ruby install.rb

  5. Install rails (Ruby On Rails) version 2.1.2 (required by Redmine)
          $ gem install rails -v 2.1.2

    The GEM needs internet connectivity to download and install the packages. Though there are ways to install packages locally, after downloading them manually. As I am new to Ruby so preferred the easiest installation method.

  6. Install PostgreSQL adapter for Ruby
    Add PostgreSQL's 'bin' directory in PATH before executing following command-
        $ gem install pg

  7. Install redmine

    • Unzip the downloaded archive
      $ tar zxvf redmine-0.8.4.tar.gz

    • Create 'redmine' database user
      CREATE ROLE redmine LOGIN PASSWORD 'redmine' NOSUPERUSER NOINHERIT CREATEDB NOCREATEROLE;

    • Create 'redmine' database
      CREATE DATABASE redmine WITH ENCODING='UTF8' OWNER=redmine;

    • Define PosgtreSQL DB in '/opt/redmine/redmine-0.8.4/config/database.yml'
             production:
               adapter: postgresql
               database: redmine
               host: localhost
               port: 5432
               username: redmine
               password: "redmine"

    • Create the database structure, by running the following command under the redmine installation directory. It will create tables and an administrator account.
          $ rake db:migrate RAILS_ENV="production"

    • Insert default configuration data in database, by running the following command:
          $ rake redmine:load_default_data RAILS_ENV="production"

  8. Install Passenger module to enable Apache to serve ruby applications
        $ tar zxvf passenger-2.2.4.tar.gz
        $ cd passenger-2.2.4/bin
        $ export APXS2=/opt/redmine/apache-2.2.11/bin/apxs
        $ ./passenger-install-apache2-module

  9. Configure Apache to server redmine or any other ruby application using passenger
    To publish a rubby application under a sub-uri, create a symbolic link to application's public directory under web root directory. Thats the way passenger works, pointing directly to application's public directory will not work here.

        $ ln -s /opt/redmine/redmine-0.8.4/public redmine

    Here is a sample configuration text from Apache's httpd-vhosts.conf file to serve Redmine-

        NameVirtualHost *:80

        LoadModule passenger_module /opt/redmine/passenger-2.2.4/ext/apache2/mod_passenger.so
        PassengerRoot /opt/redmine/passenger-2.2.4
        PassengerRuby /opt/redmine/ruby-1.8.7/bin/ruby

        <VirtualHost *:80>
            ServerAdmin webmaster@mydomain.com
            ServerName redmine

            DocumentRoot "/opt/apache-2.2.11/htdocs"
            RailsEnv production
            RailsBaseURI /redmine

            ErrorLog "logs/error_log"
            CustomLog "logs/access_log" common

            <Directory "/opt/redmine/redmine-0.8.4/public">
                Options FollowSymLinks
                AllowOverride None
                Order deny,allow
                Allow from all
            </Directory>
        </VirtualHost>
Now Redmine is available for action. Next steps could be configuring to integrate with LDAP and few more things or installing some plugins to enhance the functionality. Next I am looking for ways to migrate issue tracker from Bugzilla to Redmine, to have everything under one roof.

Saturday, June 06, 2009

Spell checking with FCKeditor

FCKeditor is an excellent tool for providing rich text editing experience on web. Best part is that it works almost out of the box, there is very little to configure. Spelling checking is an exception here. Though spell checking also works out of the box, but with Internet Explorer only, which is not the only browser out there. Recently I used FCKeditor in a Java web application and had to integrate the spell check functionality as well. The spellar pages + aspell + PHP combination works pretty well for this task. FCKeditor comes with perl, PHP and Cold Fusion scripts for spell checking, I used PHP. In this post I will try to outline the steps required to make spell check working in FCKeditor.

1. Install PHP
PHP installation (I did it on Fedora) is pretty simple, just download the source and execute following command sequence-

tar –xvzf php-5.2.9.tar.gz
cd php-5.2.9
./configure --prefix=/path_to_install \
         --with-apxs2=/apache_install_dir/bin/apxs \
         --disable-cli \
         --disable-cgi
make
make install
For more details about PHP installation see PHP documentation.

2. Integrate PHP with Apache
Apache needs to be instructed to invoke PHP interpreter for all requests for PHP files ('.php' extension). First we need to include PHP module by adding following line in /apache_install_dir/conf/httpd.conf-
LoadModule php5_module modules/libphp5.so
In same configuration file add PHP handler-
<Directory "/apache_install_dir/htdocs">
     . . . .
     . . . .
     <FilesMatch \.php$ >
          SetHandler application/x-httpd-php
     </FilesMatch>
</Directory>
3. Install aspell and dictionaries
Aspell provides dictionaries for all major world languages. Installation of aspell and its dictionaries is fairly straightforward. After downloading aspell and dictionaries execute following command sequence for each of the downloaded archive-
tar –xvzf archive_name.tar.gz
cd archive_name
./configure
make
make install
4. FCKeditor Configuration
By default FCKeditor is configured to use 'ieSpell', change it to use 'SpellarPages' instead. Also make sure it uses PHP and does spell checking in FireFox. Following properties needs to be changed in 'fckconfig.js'-
FCKConfig.SpellChecker = 'SpellerPages' ;
FCKConfig.SpellerPagesServerScript = 'server-scripts/spellchecker.php' ;
FCKConfig.FirefoxSpellChecker = true ;
Now configure the language and 'aspell' path in 'spellchecker.php'-
$aspell_prog = 'aspell';
$lang = 'en_US';

Now we are ready to test the application and see spell check in action. All software versions being used for this post are outlined below-
  • Apache 2.2.11
  • PHP 5.2.9
  • FCKeditor 2.6.4 (with bundled Spellar Pages)
  • Aspell 0.60.6
  • Tomcat 6.0.18
  • Java 6 update 13
  • Fedora 9
To know more about using Apache to serve Java application see Apache in from of Tomcat and JBoss.

Saturday, April 11, 2009

Redirect HTTP to HTTPS on Apache

At times we need to run a website over HTTPS only and to retain the traffic coming to the website over HTTP, that needs to be redirected towards HTTPS. Though there are many ways to do so but this method looks easiest to me-

<VirtualHost *:80>
    ServerName mydomain.com

    RedirectPermanent / https://mydomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName mydomain.com

    # other SSL configuration goes here
</VirtualHost>


If only parts of the website (say /secure) needs to be HTTPS enabled then redirection can be done something like-

        RedirectPermanent /secure https://mydomain.com/secure

Sunday, January 25, 2009

Apache in front of Tomcat and JBoss

Recently I have to deploy two Java web applications on a single server (one IP address). Where static content was to be served by Apache Http web server instead of Java application servers. When we have multiple applications deployed on an instance of Tomcat or JBoss we have their URLs something like http://server:port/appA, http://server:port/appB etc. This kind of URLs does not look good when we publish it to external world. So instead of 'http://domainA.tld/appA' we wanted to have URL as 'http://domainA.tld/'. This can be achieved by running applications on different instances of Tomcat / JBoss and fronting them with Apache using virtual hosts.

Running multiple instances of JBoss on a machine with single IP address is a nightmare, while it is much easier to run several Tomcat instances, as one has to change just four ports (8005, 8080, 8443, 8009). An application can be run at root context in Tomcat by adding a line like below, inside <host> element in $TOMCATHOME/conf/server.xml-

    <context path="" docbase="appA.war" unpackWAR="false" />

There are pretty decent documentation available on Apache, Tomcat and JBoss' website about their installation and configuration. So I will leave that discussion here itself. Though there is lots of documentation available for Apache virtual hosting also but it takes lots of effort for a newbie to do the configuration and put it in front of application servers. Here I am assuming that Apache Tomcat Connector (mod_jk) is also installed along with Apache web server.

To establish communication between Apache and application server, first we need to define connector workers as shown below-

    worker.list=appA,appB

    # Define appA
    worker.appA.port=9009
    worker.appA.host=localhost
    worker.appA.type=ajp13
    worker.appA.lbfactor=1

    # Define appB
    worker.appB.port=8009
    worker.appB.host=localhost
    worker.appB.type=ajp13
    worker.appB.lbfactor=1


In the above configuration appA's server's connector is listening on port 9009 and appB's on 8009. This connector port is different from http port (8080 by default for Tomcat). Now define the virtual hosts, this can be done either in Apache's httpd.conf or in a separate file and include that in httpd.conf.

   NameVirtualHost *:80

   LoadModule jk_module modules/mod_jk.so

   # Where to find workers defined above
   JkWorkersFile conf/extra/worker.properties

   <virtualhost *:80>
       ServerAdmin someone@domainA.tld
       DocumentRoot "/path/to/the/content"
       ServerName domainA.tld
       ErrorLog "logs/domainA-error.log"
       CustomLog "logs/domainA-access.log" common

       JkMount / appA
       JkMount /* appA
       JkUnMount /static|/* appA

       JkLogFile logs/mod_jk_appA.log
       JkLogLevel info
       JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
       JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories
       JkRequestLogFormat "%w %V %T"
   </virtualhost>

   <virtualhost *:80>
       ServerAdmin someone@domainB.tld
       DocumentRoot "/path/to/the/content"
       ServerName domainB.tld
       ErrorLog "logs/domainB-error.log"
       CustomLog "logs/domainB-access.log" common

       JkMount / appB
       JkMount /* appB
       JkUnMount /static|/* appB

       JkLogFile logs/mod_jk_appB.log
       JkLogLevel info
       JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
       JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories
       JkRequestLogFormat "%w %V %T"
   </virtualhost>


With above configuration all requests to domainA.tld are served by worker appA and domainB.tld is served by worker appB. The 'JkUnMount /static|/* appA' causes any URL like http://domainA.tld/static/* to be served by Apache instead of the application server. As Apache performs far better while serving the static content like images, html, css, java script etc. so it is good to unmount their URLs from the mod_jk worker. Most of the Jk* properties can be defined out of the <virtualhost> element at global level, that will avoid duplicate entries. Though defining them inside <virtualhost> element gives flexibility to have different values for each virtual host. Detailed information about Jk* is available here.

I have tested above configuration with following environment-

  • Java: 1.6.0_10
  • Tomcat: 6.0.18
  • JBoss: 5.0.0.GA
  • Apache: 2.2.11
  • OS: Fedora 9, Red Hat Enterprise Linux 5 and Windows Vista
Hope this will be useful to others and save their time.

Tuesday, July 29, 2008

SVN with Apache + LDAP

We have been using CVS at work for long, though personally I am a big fan of SVN. Lately we thought to catch up with the SVN buzz and I was asked to have a Proof Of Concept before we officially move to SVN. Installation of SVN with Apache was pretty straightforward. Though LDAP integration was also simpler but at times it failed without any obvious reasons. Here are the steps for the entire process on Windows XP-

1. Install Apache 2.2.
2. Install SVN 1.5 by unzipping the distribution.
3. Add SVN\bin folder to PATH.
4. Copy mod_dav_svn.so to modules directory of Apache.
5. Add following line in Apache conf file-
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so

# Following are required for LDAP authentication
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule ldap_module modules/mod_ldap.so

6. Download [svnindex.css and svnindex.xsl] from http://svn.collab.net/repos/svn/trunk/tools/xslt/
and put them in 'htdocs' folder of Apache. This will do nice listing of SVN contents.

7. Add the repository location in http conf file, this will have LDAP auth as well

#Location of repository
<Location>
DAV svn

SVNParentPath C:\svn
SVNListParentPath on
SVNIndexXSLT "/svnindex.xsl"

AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative off
AuthName "My SVN Setup"
AuthLDAPURL ldap://host:3268/dc=X,dc=Y?sAMAccountName?sub?(objectClass=user) NONE
AuthLDAPBindDN myUserID
AuthLDAPBindPassword myPassword
Require valid-user
</Location>

7. Run 'httpd' command from Apache

VOILA! YOU ARE DONE

I gave it a try on Fedora 4 as well, which comes with Apache 2.2 and SVN 1.4 pre-installed. Only thing that was missing was there 'mod_dav_svn'. Getting that to with YUM is pretty simple, just do-
yum install mod_dav_svn

Here we were using Active Directory as our LDAP server. Initially I used the port 389 in the AUthLDAPURL shown above and it worked fine for first 2 weeks but after that it failed without any obvious reasons with this error message in Apache log files-
[ldap_search_ext_s() for user failed][Operations Error]

It made it to work for brief periods by re-starting the Apache. Re-starting is not an option in production. After googling for some time I found suggestions to use port 3268 instead of 389. More than 2 weeks has been passed since I switched to port 3268 and it is working fine till date :-)

My next step will be to convert some CVS repositories to SVN. Will update soon about the results of this conversion.