# HOWTO: Apache 2 bandwidth limiting

## raoulduke

This is a work-in-progress version on how to limit bandwidth for an Apache 2 webserver. For Apache version 1.3 I recommend using mod_throttle or mod_bandwidth. As these modules are not available for Apache 2, this guide will use the kernel built in packet scheduler. Don't worry, it's not as hard as it sounds.

What are we going to do? We will limit the outgoing total traffic from our Apache 2 webserver to the rest of the world.

So, if you have an internet connection with a low upload speed (e.g. 256 or 192 kbit/s) you will be able to cap your webserver-upload-speed to anything you want so that you can still comfortably browse the web or do other things on-line.

What are the steps to get it working?

- reconfigure the kernel to include QoS and traffic shaping

- emergeing a few small packages we will use

- design and implement a traffic shaping script

- make sure the script is started at boot time

Because we use a built-in kernel packet scheduler called 'htb' we have several advantages over a per-connection based limiter. The biggest advantage is that clients will always have an equal share of limited bandwidth: if there's one client, it gets the full-limited bandwidth. In the case of two clients, they both get half of the full-limited bandwidth.

Get ready because here we go, please buckle your seatbelts! Oh, and don't forget to su as you'll need root privileges for the largest part of this guide.

Step 1 - Kernel configuration

I hope you've got a file containing your current kernel configuration as this will make things a lot easier. Make sure that file is in the /usr/src/linux directory. We are going to start the menu setup of your kernel:

```

#cd /usr/src/linux

#make menuconfig

```

Now, load your configuration file using the option at the bottom of this menu:

```

Load an Alternate Configuration File

```

Make sure that the following option is enabled:

```

Code maturity level options  --->

   [*] Prompt for development and/or incomplete code/drivers

```

We are now going to enable all kernel options required for our basic, and future advanced traffic shaping, so let's go and enable these options. They must be compiled into the kernel, not as a module, hence the *:

```

*       QoS and/or fair queueing

        *       HTB packet scheduler

        *       QoS support

                *       Rate estimator

        *       Packet classifier API

                *       TC index classifier

                *       Routing table based classifier

                *       Firewall based classifier

                *       U32 classifier

        *       Traffic policing

```

Save this configuration, for instance as mykernel-htb. And compile your new kernel using:

```

#make dep ; make clean bzImage modules modules_install

```

Copy the kernel to your favourite location and add it to your bootloader, for instance:

```

#cp arch/i386/boot/bzImage /boot/kernel-htb

#vi /boot/grub/menu.lst

```

The kernel is ready. Reboot with the new -htb kernel.

Step 2 - emerging packages

There's not a lot we're going to need, just iproute, so type:

```

#emerge -p iproute

(check the output for anomalies)

#emerge iproute

```

Check that the package is fully working by issueing the 'tc' command as root:

```

#tc

```

Your output should look like something like this:

```

Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }

where  OBJECT := { qdisc | class | filter }

       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] file }

```

This is good as it means 'tc' is working. Now let's head over to our script creation!

Step 3 - Designing and implementing our script

FIXME: explain what is happening here

For now, just assume I'm right. We're going to build a htb tree with only two leaves and one parent node. One leaf is going to be the traffic limiting node, the other is the rest of the unshaped traffic. You must now decide what upload speed you want Apache to have in kilobytes per second. The tree we will build looks like this:

```

       NIC

      (eth)

        |

        |

        |

        |

       LINK

      X kbps

        /\

       /  \

      /    \

     /      \

    /        \

 HTTP       REST

Y kbps    X-Y kbps

```

Now you must think up the following data:

- the ethernet device, I will use eth0

- the linkspeed, I will use 1024kpbs

- the Apache upload speed, I will use 20kbps (this is 160 kbit/s)

Let's call the ethernet device EDEV, the linkspeed LSPD and the Apache upload speed ASPD. We will have to create the following script using our favourite editor (as long as it's vi(m)):

```

#!/bin/bash

# change these values to suit your needs

EDEV="eth0"

LSPD="1024kbps"

ASPD="20kbps"

# create root node

tc qdisc add dev $EDEV root handle 1: htb default 11

# create LINK class

tc class add dev $EDEV parent 1: classid 1:1 htb rate $LSPD

# create our HTTP shaping class

tc class add dev $EDEV parent 1:1 classid 1:10 htb rate $ASPD

# create our REST class for unutilized bandwidth

tc class add dev $EDEV parent 1:1 classid 1:11 htb rate $LSPD

# create the filter for the HTTP class, we filter on source port 80 (http)

tc filter add dev $EDEV protocol ip parent 1:0 prio 1 u32 match ip sport 80 0xffff flowid 1:10

```

Save this script somewhere you can remember, for instance /etc/htb-script.sh.

Step 4 - making the script startup at boot

We must now create a script to stop our traffic shaping activities, so create a file with your editor containing:

```

#!/bin/bash

EDEV="eth0"

tc qdisc del dev $EDEV root

```

Save the file, for instance as /etc/htb-stop.sh.

We must make sure we can execute our scripts later on, so chmod them:

```

#chmod +x /etc/htb-script.sh

#chmod +x /etc/htb-stop.sh

```

We will now create a script that is going to be placed in /etc/init.d, so fire up your editor again and create this:

```

#!/sbin/runscript

depend() {

        use logger

        need net

}

start() {

        ebegin "Starting htb"

        /etc/htb-script.sh

        eend $?

}

stop() {

        ebegin "Stopping htb"

        /etc/htb-stop.sh

        eend $?

}

```

Save the script as /etc/init.d/htb. And chmod it as well:

```

#chmod +x /etc/init.d/htb

```

We want to run this script at boot time, so we will add it to the default runlevel using:

```

#rc-update add htb default

```

Everything is now in place. To start our script without rebooting type:

```

#/etc/init.d/htb start

```

That should do it!

Questions / comments

Help with the FIXME's is appreciated. They will disappear within the next few days / weeks.

I wish you luck!

----------

## benca1

Can't wait to try this. Thanks an awful lot of writing this.

----------

## apyh

could i get a bit more explanation of how that last tc command works?

```

# create the filter for the HTTP class, we filter on source port 80 (http) 

tc filter add dev $EDEV protocol ip parent 1:0 prio 1 u32 match ip sport 80 0xffff flowid 1:10 

```

I've got several ideas in mind, for one, adding more branches to this tree, one for http (restricted), bittorrent (restricted), and the rest (unrestricted).

However, for bt, i'll need to restrict based on a range of ports.  So a better explanation of the last command would be great.

From the man page, i get the general syntax, but i'm thrown off between the arguments you use between priority and flow:

```

u32 match ip sport 80 0xffff

```

u32 is the filtertype, but where do i find documentation on the rest of the arguments for this filter (like sport and that mask)?

On a side note, why is the parent node referenced as 1:0 instead of just 1: which was used in the root creation in the first tc command?

----------

## sn4ip3r

When I needed to limit the bandwidth apache2 used I wrote a version of 'cat' which took as a parameter the needed bandwidth and then used mod_filter_ext to pipe all traffic through the program.

Something like this:

```

ExtFilterDefine ksec16 mode=output cmd="/usr/local/bin/throttle_cat 16384" preservescontentlength

<Location /~sn4ip3r/packages>

    # 16KB/s

    SetOutputFilter ksec16

</Location>

```

----------

## sn4ip3r

I described another method of limiting apache bandwidth in my previous reply to this post, an accurate name would be "Poor mans apache2 bandwidth limiting" :Razz: .

Here is a little bit more accurate howto for that.

1. Download a customized version of cat (writte by me) from here.

2. Compile it

```

g++ throttle_cat.cpp -o throttle_cat

```

(although the program is called cat, it is not a full implementation, it only relays data sent to its standard input and it does not accept any other parameters besides data rate which btw. is bytes per second, so to test it you could "cat filename|throttle_cat 10" to see data flow 10 bytes at a time with intervals of 1 second)

3. Put it in a safe place where you keep your binaries which are not installed by portage (or make an ebuild if you really want to)

4. Edit /etc/apache2/conf/commonapache.conf

```

# Following is an example, customize it to your needs

# define a 16KB/s filter

ExtFilterDefine ksec16 mode=output cmd="/usr/local/bin/throttle_cat 16384" preservescontentlength

# apply the filter to /~sn4ip3r/packages

<Location /~sn4ip3r/packages>

       # 16KB/s

      SetOutputFilter ksec16

</Location>

```

And thats it. One thing you should know, this method creates a per-client limit, not a per-location or overall limit, so if you need an overall limit you have to limit the number of connections allowed.

Hope this is of use to someone

[edit] updated URLLast edited by sn4ip3r on Fri Jul 08, 2005 9:56 am; edited 1 time in total

----------

## MooktaKiNG

is it possible to give different limits on different interfaces.

For example my server connects to the internet through eth0, and NAT is eth1. I want full speed, unlimited, on eth1. but i want to limit speed for eth0.

Is this possible?

----------

## Lajasha

 *raoulduke wrote:*   

> Step 2 - emerging packages
> 
> There's not a lot we're going to need, just iproute, so type:
> 
> ```
> ...

 

Just thought I would let ya know this should be updated to:

```
emerge -p iproute2
```

----------

## jevidl

Excellent guide! 

Thanks so much for posting the information, for those of us with a bandwidth capped cable modem it's a lifesaver. Now I can share files with friends and not have to worry about not being able to surf or closing out the rest of the people in the house. Thanks again!

----------

## jkolb

Try using tcc (sys-apps/tcng) to generate a tc script.  I found it much easier to define my ruleset using their syntax, and let it generate the ugliness that tc understands.

You can find more information on tcng at http://tcng.sf.net/

Hm.  There seems to be a newer version of tcng that's not in portage.  Anyone up for updating the ebuild?

----------

## roko

Great HOWTO. Thanks.

----------

## lisa

This may help  :Smile: 

```

#!/sbin/runscript

# /etc/init.d/rate_limit_apache

depend() {

        use logger

        need net

}

start() {

        ebegin "Starting Apache Rate Limit on ${EDEV}"

        # create root node 

        ${TC} qdisc add dev $EDEV root handle 1: htb default 11 

        # create LINK class 

        ${TC} class add dev $EDEV parent 1: classid 1:1 htb rate $LSPD 

        # create our HTTP shaping class 

        ${TC} class add dev $EDEV parent 1:1 classid 1:10 htb rate $ASPD 

        # create our REST class for unutilized bandwidth 

        ${TC} class add dev $EDEV parent 1:1 classid 1:11 htb rate $LSPD 

        # create the filter for the HTTP class, we filter on source port 80 (http) 

        ${TC} filter add dev $EDEV protocol ip parent 1:0 prio 1 u32 match ip sport 80 0xffff flowid 1:10

        eend $?

}

stop() {

        ebegin "Stopping Apache Rate Limit on ${EDEV}"

        tc qdisc del dev $EDEV root

        eend $?

}

```

```

#/etc/conf.d/rate_limit_apache

EDEV="eth1"

LSPD="3084kbps"

ASPD="10kbps"

TC="/sbin/tc"

```

----------

## Raniz

Is it possible to create a limit for multiple ports?

I want to have a limit of 250kbps spanning over three or four ports. So if I upload at 100kbps on one port, there's 150 left for the other two.  Or if I upload at 25kbps on one port, 75 kbps on one port and 35 kbps on the third, there's 115kbps left for the fourth port. Get the idea?

----------

## electrofreak

Is it possible to make it not throttle the bandwidth within the network?

Like, when browsing from outside our network (from that world out there!) it would limit the speed, but when from 192.168.0.1-255 it wouldn't limit the speed at all.

Edit: didn't realize how old this topic was. Is this bandwidth limiting stuff still valid? Is it built into apache2 now?

----------

## ARealNoobOne

 *raoulduke wrote:*   

> We are now going to enable all kernel options required for our basic, and future advanced traffic shaping, so let's go and enable these options. They must be compiled into the kernel, not as a module, hence the *:
> 
> ```
> 
> *       QoS and/or fair queueing
> ...

 

Excellent guide.

Could you please explain why traffic shaping options must be builtin rather than modular ("they _must_ be compiled into the kernel") ? I hate having builtin modules that are not critical to boot.

----------

## meulie

Is there also a way to limit the amount of bandwidth consumed per external IP per day?

----------

## dembol

Hi

raoulduke:

 *Quote:*   

> For Apache version 1.3 I recommend using mod_throttle or mod_bandwidth. As these modules are not available for Apache 2

 

meulie:

 *Quote:*   

> Is there also a way to limit the amount of bandwidth consumed per external IP per day?

 

There is mod_cband for the Apache2 server. 

Main features:

- per-user bandwidth limiting

- per-virtualhost bandwidth limiting

- per-destination class bandwidth limiting

- status handler (like in mod_throttle)

homepage of the project: http://cband.linux.pl

the cband-status handler demo: http://dembol.nasa.pl/cband-status, (in XML -> http://dembol.nasa.pl/cband-status?xml)

But, it isn't in the gentoo portage yet  :Crying or Very sad:  You can download the mod_cband sources (http://cband.linux.pl/download/mod_cband-0.9.5.tgz) and compile it for your Apache

Best regards

----------

## electrofreak

Hm. Looks good. Thanks.

----------

## Sakkath

mod_cband is now in portage, it's masked for ~amd64 though  :Sad: .

----------

