Apr
12th

Lighttpd can lighten Apache’s load

Is your Apache Web server slowing down under the weight of streaming media content or database-driven applications? Lighttpd, sometimes pronounced “Lighty,” is a lightweight HTTP server that can help alleviate Apache’s load by serving static content or CGI scripts. Since Lighttpd uses fewer resources per request than Apache alone, it can generally serve most static content faster than Apache. It also benefits from an actively developed FastCGI interface that performs true load balancing, giving you all the performance benefits of compiled into Apache modules such as PHP.

One of the most beautiful things about using Lighttpd is that you can run it behind Apache via Apache’s proxy module. This means you don’t need to add another physical server in order to use it.

Installing Lighttpd

On most distributions, you’re best off installing Lighttpd from source. This means downloading it, configuring and compiling it, then installing it. It’s a fairly straightforward process. Lighttpd compiles cleanly and easily on nearly every platform I’ve tried it on. The essential commands for compiling and installing Lighttpd can be found on the software’s download page.

If you’re running Gentoo or FreeBSD, it’s even easier. Under Gentoo, you can simply type emerge lighttpd to get up and running. FreeBSD has a port of Lighttpd in /usr/ports/www/lighttpd that you can install, as well via the usual ports installation method, detailed in section 4.5.2 in the FreeBSD handbook.

Once Lighttpd is installed, you’ll have to build a configuration file to use it. The Lighttpd tarball comes with a sample in the doc/ folder that will fill most static-content hosting needs. While configuring all of the aspects of Lighttpd is beyond the scope of this article, it is important to pay attention to these configuration items:

# If you don’t change this variable, it will try to serve document from /www/pages, which
# is probably not where your documents are. Point this to the place to serve the content
server.document-root = “/www/pages”

# Server error and access logs – make sure this path exists with a mkdir -p /var/log/lighttpd
server.errorlog = “/var/log/lighttpd/error_log”
accesslog.filename = “/var/log/lighttpd/access_log”

# bind to port (Default: 80)
server.port = 81

# bind to localhost (recommended for proxy behind Apache, otherwise comment this out for all)
server.bind = “localhost”


This is not a full listing of the configuration file, but rather a highlight of the most important parts. Notice that we’ve set the server port to 81. By doing this, we’re making sure it doesn’t clash with Apache listening on port 80. If you wanted to let Lighttpd power your entire site instead of Apache, you can set this to port 80, or comment it out to accept the default.

Setting up Apache’s proxy

To let Apache take the output of Lighttpd on port 81 and map it to your Web site, you’ll need to make sure the Proxy module of Apache is loaded. The following configuration examples assume you’re using the Apache 2 series, but if you’re running Apache 1.3 the configuration is similar in most places. For differences in the proxy module for Apache 1.3, consult the proxy module documentation.

First, make sure that Apache’s proxy module is loaded, by ensuring that something resembling these lines is present in your httpd.conf file:

LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_connect_module libexec/apache2/mod_proxy_connect.so
LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so


If not, add them, or make sure that you’ve got the proxy module installed as per your distribution’s instructions. In most cases, this module will either be there already or commented out. In the latter case, just uncomment it and restart Apache.

If you are using virtual hosting, you will want to use the following code to set up a proxy between the applicable <VirtualHost> directives. If not, putting them at the end of the httpd.conf file should do the trick:

ProxyRequests Off
ProxyPreserveHost On
ProxyPass /images http://0.0.0.0:81/
ProxyPassReverse / http://0.0.0.0:81/


In the above example, Lighttpd will serve up your images folder, leaving Apache to do the rest. You can easily set this to any folder that has static content in it and Lighttpd will serve it, instead of Apache. Another good use of Lighttpd would be to serve up multimedia files, taking the load off of Apache.

The performance boost you’ll gain is dependent on many factors. If you only have Lighttpd serve up your images, it probably won’t help too much. You can put all of your static content, including HTML and PDF files, images, and movies in a folder called /static and then set the ProxyPass variable to that for a slightly better boost.

Dynamic Lighty

The performance boosts you’ve gained so far with Lighttpd aren’t phenomenal, but they can help in some heavy load situations. If you have some heavy-duty PHP scripts or a Ruby on Rails application, you might be better off letting Lighttpd handle it, as its FastCGI load-balancing is superior to Apache’s. Running a Ruby on Rails application with Lighttpd’s FastCGI support can yield huge performance gains.

To enable PHP behind Lighttpd, make sure that you’ve compiled PHP with FastCGI support. You can do this with the –enable-fastcgi configure switch. The Lighttpd documentation on PHP is quite helpful.

For Ruby on Rails, this Lighttpd configuration snippet will run your Rails application quickly and also dramatically reduce Apache’s load and memory usage:

# replace path_to_app with the path to your actual Website files and Rails app
# replace rails_app_name with the folder containing the Rails app

fastcgi.server = (
“.fcgi” =>
( “localhost” =>
( “socket” => “/home/path_to_app/var/lighttpd-fcgi.socket”,
“bin-path” => “/home/path_to_app/rails_sites/rails_app_name/public/dispatch.fcgi”,
“bin-environment” => ( “RAILS_ENV” => “production” ),
“min-procs” => 1,
“max-procs” => 1,
“idle-timeout” => 60,
“allow-x-send-file” => “enable” ) ) )


Lower server loads, happier visitors

By shifting some of the load from Apache to Lighttpd, you’ll increase your Web site’s performance, reduce the load on your server, and keep your visitors happier. For heavier load situations, you can put another server on the local network and have it running nothing but Lighttpd on port 80. Using Apache’s proxy module, you can redirect Lighttpd’s output from the local server to the front-end server with Apache by changing the ProxyPass and ProxyReverse variables to listen on the local IP.

I’ve found Lighttpd to be very helpful in reducing load and increasing performance, especially in serving PHP and Rails applications, and I’m confident that you will too.

Apr
11th

Configure a low-cost load-balanced LAMP Cluster

The ubiquitous Linux, Apache, MySQL and PHP/Perl/Python (LAMP) combination powers many interactive web sites and projects. When demand exceeds the capabilities of a single server, the database is typically moved to a different server to spread the workload. When demand exceeds a two-server solution, it’s time to think cluster.

LAMP cluster defined

Before getting into the details, it helps to distinguish what is meant by cluster in the context of this article. This is not the Beowulf kind of cluster that uses specialized message passing software to tackle a compute-intensive task. Also, it does not cover high-availability features such as automatic fail over. Rather, it is a load-sharing cluster that distributes web requests among multiple web and database servers while appearing to be a single application.
Everything required to implement this cluster is done with software that ships with most Linux distributions, making it easy and (relatively) inexpensive to implement. We’ll construct a cluster using seven computers for a fictitious company, foo.com. Two servers will run DNS (primary and backup) to distribute web requests among three web servers that read and write data from two MySQL database servers.

Any number of different designs can be built, with more or fewer of each kind of server, but this model will serve as a good illustration of what can be done.

Load balancing

The first part of the cluster handles load balancing by using the round robin feature of the popular DNS software Berkeley Internet Name Daemon (BIND). To use round robin, each web server must have its own public IP address. A common scenario is to use network address translation and port forwarding at the firewall to assign each web server a public IP address while internally using a private address. In the DNS example, I show private IP addresses, but public IPs are required for the web servers so DNS can work its magic.

This snippet from the DNS zone definition for foo.com assigns the same name to each of the three web servers, but uses different IP addresses for each:

;
; Domain database for foo.com
;
foo.com.                 IN SOA ns1.foo.com. hostmaster.foo.com. (
2006032801 ; serial
10800 ; refresh
3600 ; retry
86400 ; expire
86400 ; default_ttl
)
;
; Name servers
;
foo.com. IN NS ns1.foo.com.
foo.com. IN NS ns2.foo.com.
;
; Web servers
; (private IPs shown, but public IPs are required)
;
www IN A 10.1.1.11
www IN A 10.1.1.12
www IN A 10.1.1.13

When DNS gets a request to resolve the name www.foo.com, it will return one IP address, then a different address for the next request and so on. Theoretically, each web server will get one-third of the web traffic. Due to DNS caching and because some requests may use more resources that others, the load will not be shared equally. However, over time it will come close.

Hardware load balancers

If round robin DNS is too crude and you have the money, hardware load balancers offer better performance. Some take into account the actual load on each web server to maximize cluster performance instead of just delegating incoming requests evenly. They may also have features to solve the cookie problem discussed below. Cisco and Citrix are popular choices of companies who sell hardware load balancers. You can even use round robin DNS in front of the hardware load balancers.

Web servers

Configuring the web servers is largely the same as configuring a single Apache web server, with one exception. The content on each web server has to be identical to maintain the illusion that visitors are using one web site and not three. That requires some mechanisms to keep the content synchronized.

The most elegant solution would be to use some kind of global shared file system. NFS won’t work very well due to locking and performance issues. Red Hat’s Global File System might work, or Intermezzo, but they are beyond the scope of this work.

For file synchronization, my tool of choice is rsync. First, designate one server, web1 for example, as the primary web server and the other two as secondaries. We make content changes only on the primary web server and let rsync and cron update the others every minute. Due to the advanced algorithms in rsync, content updates happen quickly.

I recommend creating a special user account on each web server, called “syncer” or something similar. The syncer account needs to have write permissions to the web content directory on each server. Then, generate a pair of secure shell (SSH) keys for the syncer account using ssh-keygen on the primary web server and distribute the public keys to the /home/syncer/.ssh directory on the other two web servers. This allows the use of password-less SSH along with rsync to keep the content updated.

Here is a shell script that uses rsync to update the web content.

#!/bin/bash
rsync -r -a -v -e “ssh -l syncer” –delete /var/www/ web2:/var/www/
rsync -r -a -v -e “ssh -l syncer” –delete /var/www/ web3:/var/www/

This script should be set up in cron to run every minute and push updates out to web2 and web3.

The cookie conundrum and application design

Cookies can be a tricky issue when LAMP applications use this kind of cluster. By default, Apache stores its cookies in the /tmp directory on the server where it is running. If a visitor starts a session on one web server but future HTTP requests are handled by a different web server in the cluster, the cookie won’t be there and things won’t work as expected.

Because the IP of a web server is cached locally, this doesn’t happen often, but it is something that must be accounted for and may require some application programming changes. One solution to the cookie problem is to use a shared cookie directory for all web servers. Be particularly aware of this issue when using pre-built LAMP applications.

Aside from the cookie issue, the only other requirement for the application is that all database writes are sent to the database master, while reads should be distributed between the master and slave(s). In our example cluster, I would configure the master web server to read from the master database server, while the other two web servers would read from the slave database server. All web servers write to the master database server.
Database servers

MySQL has a replication feature to keep databases on different servers synchronized. It uses what is known as log replay, meaning that a transaction log is created on the master server which is then read by a slave server and applied to the database. As with the web servers, we designate one database server as the master, call it db1 to match the naming convention we used earlier, and the other one, db2, is the slave.

To set up the master, the first thing to do is create a replication account. This is a user ID defined in MySQL, not a system account, which is used by the slaves to authenticate to the master in order to read the logs. For simplicity, I’ll create a MySQL user called “copy” with a password of “copypass”. You will need a better password for a production system. This MySQL command creates the copy user and gives it the necessary privileges:

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
TO copy@”10.1.0.0/255.255.0.0″
IDENTIFIED BY ‘copypass’;
Next, edit the MySQL configuration file, /etc/my.cnf, and add these entries in the [mysqld] section:
# Replication Master Server (default)
# binary logging is required for replication
log-bin

# required unique id
server-id = 1

The log-bin entry enables the binary log file required for replication, and the server-id of 1 identifies this server as the master. Then, restart MySQL. You should see the new binary log file in the MySQL directory with the default name of $HOSTNAME-bin.001. MySQL will create new log files as needed.
To set up the slave, edit the /etc/my.cnf file and add these entries in the [mysqld] section:

# required unique id
server-id = 2
#
# The replication master for this slave – required
# (replace with the actual IP of the master database server)
master-host = 10.1.1.21
#
# The username the slave will use for authentication when
# connecting to the master – required
master-user = copy

# The password the slave will authenticate with when connecting to
# the master – required
master-password = copypass

# How often to retry lost connections to the master
master-connect-retry = 15
# binary logging – not required for slaves, but recommended
log-bin

While not required for a slave, it is good planning to create the MySQL replication user (”copy” in our example) on each slave in case it needs to take over for the master in an emergency.

Restart MySQL on the slave and it will attempt to connect to the master and begin replicating transactions. When replication is started for the first time (even unsuccessfully), the slave will create a master.info file with all the replication settings in the default database directory, usually /var/lib/mysql.

To recap the database configuration steps,

  1. create a MySQL replication user on the master (and optionally on the slave)
  2. grant privileges to the replication user
  3. edit /etc/my.cnf on master and restart mysql
  4. edit /etc/my.cnf on the slave(s) and restart mysql

How to tell if replication is working

On the master, login to the mysql monitor and use “show master status”:

mysql> show master status \G;
************************ 1. row ************************
File: master-bin.006
Position: 73
Binlog_do_db:
Binlog_ignore_db:
1 row in set (0.00 sec)
On the slave, login to the mysql monitor and use “show slave status”:
mysql> show slave status \G;
************************ 1. row ************************
Master_Host: master.foo.com
Master_User: copy
Master_Port: 3306
Connect_retry: 15
Master_Log_File: intranet-bin.006
[snip]
Slave_IO_Running: Yes
Slave_MySQL_Running: Yes

The most important fields are Slave_IO_Running and Slave_MySQL_Running. They should both have values of Yes. Of course, the real test is to execute a write query to a database on the master and see if the results appear on the slave. When replication is working, slave updates usually appear within milliseconds.

Recovering from a database error

If the slave database server loses power or network connection, it will no longer be able to stay synchronized with the master. If the outage is short, replication should pick up where it left off. However, if a serious error occurs on the slave, the safest way to get replication working again is to:

  • stop mysql on the master and slave
  • dump the master database
  • reload the database on the slave
  • start mysql on the master
  • start mysql on the slave

Depending on the nature of the problem, a full reload on the slave may not be necessary, but this procedure should always work.
If the problem is with the master database server and it will be down for a while, the slave can be reconfigured as the master by updating its IP address and /etc/my.cnf file. All web servers have to be changed to read from the new master. When the old master is repaired, it can be brought up as the slave server and the web servers changed to read from the slave again.

Going large

Clusters make it possible to scale a web application to handle a tremendous number of requests. As traffic builds, network bandwidth also becomes an issue. Top tier hosting providers can supply the redundancy and bandwidth required for scaling. The number of possible cluster configurations is only limited by your imagination. MySQL 5 introduced a special storage engine designed for distributed databases called NDB that provides another option. For more in-depth information on MySQL clustering, see the MySQL web site or High Performance MySQL by Jeremy Zawodny and Derek Balling.

Apr
1st

Installing Ruby on Rails on Linux and on Windows

Ruby has been the latest buzz in the web hosting community for quite some time now. Ruby is a pure object-oriented programming language with clean syntax which facilitates quick and easy programming.

It originated in Japan in 1993 and was written by Yukihiro Matsumoto, a.k.a. “Matz”. Rails are an open source Ruby framework used to develop web applications with database backend.

The combination of Ruby on Rails is believed to lead to development of applications 10-times faster than other object-oriented languages.

Pros of Ruby on Rails

  • Easy setup and deployment of an application – excellent for RAD (Rapid Application Development) since fewer lines of code and configuration are needed
  • A lot of internal API (Application Programmers Interface) which can be extended
  • More flexibility during runtime
  • Completely Object Oriented
  • Supports database like PostgreSQL and MySQL

The major drawback of Ruby on Rails, for the time being, is the lack of documentation. Someone new to programming might have difficulty in picking up Ruby on Rails.

In this article we will cover installation procedures for Ruby on Rails in Windows and Linux platforms. Let us start with Linux installation first. Text in green indicates commands you need to issue on SSH.

Installing Ruby On Rails on Linux

You just need to follow some basic steps to create a working Ruby environment. A web server daemon is needed for Ruby applications to run. Apache is normally used on Linux so we will consider Apache as our web server in this example. All these installation steps are normally done as the ‘root’ user or a superuser on the system.

1. Installing Ruby

Installing Ruby is the first step involved. The following are the commands you need to issue on SSH to install Ruby from source.

$ cd /usr/local/src
$ wget
http://ftp.ruby-lang.org/pub/ruby/ruby-1.8.4.tar.gz
$ tar -zxvf ruby-1.8.4.tar.gz
$ cd ruby-1.8.4
$ ./configure && make && make install

2. Installing Ruby Gems

Ruby Gems manages third-party Ruby libraries.

$ cd /usr/local/src
$ wget rubyforge.org/frs/download.php/3700/rubygems-0.8.11.tgz
$ tar -zxvf rubygems-0.8.11.tgz
$ cd rubygems-0.8.11
$ ruby setup.rb

3. Installing Rails

Once Gems are installed we can install Rails. The following is the command you need to use.

$ gem install rails

You need to make sure you answer yes (Y) to all the asked dependencies.

You are done with the Ruby install part. You need to get it working with Apache now. FastCGI is normally used with Apache for Ruby development. We will check the procedure for installing FastCGI first.

$ cd /usr/local/src
$ wget fastcgi.com/dist/fcgi-2.4.0.tar.gz
$ tar -zxvf fcgi-2.4.0.tar.gz
$ cd fcgi-2.4.0
$ ./configure && make && make install

You now need to install Mod_fastcgi for FastCGI support on Apache. For Apache 1.3 you can use the following commands:

$ cd /usr/local/src
$ wget fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
$ tar -zxvf mod_fastcgi-2.4.2.tar.gz
$ cd mod_fastcgi-2.4.2
$ /usr/local/apache/bin/apxs -iac mod_fastcgi.c

For Apache 2, you can use the following:

$ cd /usr/local/src
$ wget fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
$ tar -zxvf mod_fastcgi-2.4.2.tar.gz
$ cd mod_fastcgi-2.4.2
$ cp Makefile.AP2 Makefile
$ make
$ make install

Add an entry to httpd.conf like this:

LoadModule fastcgi_module modules/mod_fastcgi.so

You need to install the Ruby fcgi module now. The command is:

$ gem install fcgi

The next part is adding handlers in Apache. Please make sure you have added LoadModule fastcgi_module libexec/mod_fastcgi.so in your httpd.conf. If it is added you need to further add the following to your httpd.conf:

<IfModule mod_fastcgi.c>
FastCgiIpcDir /tmp/fcgi_ipc/
AddHandler fastcgi-script .fcgi
</IfModule>

Make sure you have correct permissions on /tmp/fcgi_ipc

$ mkdir -p /tmp/fcgi_ipc
$ chown $apacheuser.$apacheuser /tmp/fcgi_ipc -R
$ chmod 755 /tmp/fcgi_ipc -R

Restart Apache to complete the installation.

Installing Ruby On Rails on Windows

Windows-based installation of Ruby on Rails is relatively simple. There is a wizard-based Windows installer available for installing various Ruby components on Windows. It is called RubyInstaller and can be downloaded form http://rubyinstaller.rubyforge.org/ You need to have the following components for a full, working development environment.

  • Ruby language
  • Gems
  • Scite or FreeIDE
  • MySQL server
  • Rails
  • MySQL Front or any admin tool for managing dbs

You need to run the Windows installer for Ruby and install the components like Ruby, Gems and FreeIDE, as needed. It is an automated installer and does a hassle-free install. Then, you can install MySQL server and start it as a service. Once mysql is started, the next step is to install Rails. Go to the Ruby bin directory on command prompt and issue the command:

gem install rails –include-dependencies

It is now time to test your Ruby installation. Go to Crubytestprojtect and issue the command:

rails testproject

Then, in the testproject dir, you need to issue:

ruby script/server

Open a browser window now and try to access http://127.0.0.1:3000 You should see a welcome screen from Ruby. You are now ready to start developing your Ruby applications.

I hope you find this article helpful and enjoy Ruby programming. To get started with programming Ruby on Rails, download and watch the 15 minute introduction video on Rails . It will give you a very good overview of the language. You should then read and follow the ONLamp.com tutorial “Rolling with Ruby on Rails” which shows how to create a ‘Hello World!’ application and some of the basics of database connection.

Feb
11th

How to Use Gmail as a Smart Host

I like to send mail direct from my home network for various reasons, not least being that I used to work on my current ISP’s mail servers and I know that they are in and out of blackholes these days like Hawking radiation. By sending mail directly from my dynamic block, the results are at least somewhat consistent.

Some may suggest changing ISP, but I am happy with every other aspect of their service, and there is no guarantee that any other ISP won’t run in to the same problems at any point in the future. Exim makes it easy for me to maintain a list of domains that do require me to use my ISP’s smart host, and even has the decency to read it dynamically, so it’s little hardship for me to: echo painintheass.net >> /usr/local/etc/exim/smarthost.domains for those domains that do need it.

Occasionally, however, I run into problems whereby the recipient that I am trying to mail won’t accept mail from me or the upstream smart host at the ISP. In the past, that has meant that I’ve been stuffed, which would normally be the would-be recipient’s problem, but every so often I really, really want to send them the message.

This just happened twice in the space of ten minutes, so I worked out how to get exim to relay mail via smtp.gmail.com:

  • First, enable POP for your gmail account. You do that in the “Forwarding and POP” section of the settings. Strangely enough.
  • Next, add a domain list to your exim configuration:

    domainlist use_gmail_domains = /usr/local/etc/exim/gmail.domains

    This domain list will hold the list of domains to send via gmail, one domain per line. If you don’t have any to add now, create the file empty with touch(1) so that you don’t forget later. Exim won’t complain either way.

  • Create an authenticator. Note that although we’re using the plaintext mechanism here, we’ll force TLS in the transport so your details will not get transferred in the clear:
    gmail_login:
      driver = plaintext
      public_name = LOGIN
      client_send = : YourGmailUsername@gmail.com : YourGmailPassword

    Note that in a default exim configuration there are usually no authenticators, so don’t forget the begin authenticators statement if this is your first one.

  • Add a router:
    send_via_gmail:
      driver = manualroute
      domains = +use_gmail_domains
      transport = gmail_smtp
      route_list = "* smtp.gmail.com byname"
  • Add a transport, forcing it to use AUTH and TLS:
    gmail_smtp:
      driver = smtp
      hosts = smtp.gmail.com
      hosts_require_auth = smtp.gmail.com
      hosts_require_tls = smtp.gmail.com

That’s all it requires. You may now need to lock down the permissions on your configuration file to stop anyone reading your username and password from it. Advanced exim users can work out how to put this information in a separate file easily enough.

Feb
11th

Audio Websites — Web Developers: Make Money Now

Are you a website developer looking to establish a long-term relationship with a web content provider that could make money over the long-term for both of you? Have you considered becoming an expert in the providing of website audio content — in webcasting and podcasting? Knowing how to present web audio and how to manage such a site can be your key to making money over the web.

It is hard to pick up a periodical about the web these days without coming upon an article about the ever increasing use of substantive audio content in websites. Webcasting and podcasting are the rage. These websites can make money through banner ads, click-throughs, and charging for downloads of audio content.

An audio-based website can include, for instance real-time streaming of a radio talk show or an interview. It can also contain archived materials, such as past shows, the equivalent of books-on-tape, and the like.

A web site developer can team up with the audio content provider, using cost and revenue sharing in order to make the enterprise beneficial to both.

The success of such a venture can be heightened by the use of low-cost audio. For instance, the audio could consist largely of streaming or recorded conversation about hot topics in international affairs, national politics, the economy, and trends and issues in our ever-changing culture, philosophy, and religious expression.

The likelihood of success can also be heightened if the format involves the same basic co-hosts, with the occasional invited guest, where the co-hosts are knowledgeable, clear-speaking, with a sense of humor; but who also often find themselves on opposite sides of the issue under discussion. The spark of life attracts the visitor.

And believe me, there are audio content providers with in-demand audio ready to team up with the right web developer. I know, because I am co-host of the US Virgin Islands-based and currently broadcast-based talk radio program known as Island Insight, with my co-host Randall Scott Johns. We are ready to move on to the web with live, streaming conversation, as well as archived shows. There must be others out there as well, ready to provide you with the content you need.

So, get ready for the future, for the future is now. Get the word out that you know how to do it and you are ready to design a high-quality product. Be a part of the future, and have fun doing it.