2026年11月14日
2026年11月14日
Limit Concurrent Connections per IP in Apache with mod_limitipconn
This article is a localized edition of the Japanese original. Read the Japanese original
mod_limitipconn is a module that caps the number of simultaneous connections a single IP address can open to Apache. It is well suited to download pages for large files, where download managers may open dozens of parallel connections and tie up bandwidth and worker slots.
It is not a standard module bundled with Apache but a third-party module distributed by David Jao. As of November 2026 the latest version is 0.25, and the download page says it has been tested on Apache 2.4 and 2.2. We could not find a package in the official Debian 13 repositories or in EPEL 9, so this article builds it from source. The steps were tested on Debian 13 (Apache 2.4).
As the author's own documentation states, this module is not designed to prevent DoS attacks. It does nothing against attacks coming from many IP addresses, so if your goal is attack mitigation, also read "Choosing between this and other approaches" later in the article.
How it works and prerequisites
mod_limitipconn looks at Apache's scoreboard (the list of which client each worker is currently serving) and counts the in-progress connections from the same IP address. Requests over the limit receive 503 Service Unavailable.
Because client information has to be recorded in the scoreboard, two things are required:
mod_statusis loadedExtendedStatus Onis in effect (in Apache 2.4, loading mod_status turns it On by default, but writing it in the configuration to make the intent explicit is the safer choice)
On Debian/Ubuntu, mod_status is enabled by default. Check that status_module appears in the output of sudo apache2ctl -M | grep status.
Building and installing
The build needs apxs, which comes with Apache's development package. On Debian/Ubuntu, install it like this:
sudo apt update
sudo apt install apache2-dev build-essential bzip2 curl
On RHEL-family systems, httpd-devel and gcc provide apxs and the compiler.
Download the source from the distribution page, extract it, and build and install it with apxs.
cd /usr/local/src
sudo curl -LO https://dominia.org/djao/limit/mod_limitipconn-0.25.tar.bz2
sudo tar xjf mod_limitipconn-0.25.tar.bz2
cd mod_limitipconn-0.25
sudo apxs -c -i -a -n limitipconn mod_limitipconn.c
-i copies the module into Apache's module directory, and -a adds the configuration that loads it. On Debian/Ubuntu this creates /etc/apache2/mods-available/limitipconn.load and enables it right away. Confirm that it is loaded with:
sudo apache2ctl -M | grep limitipconn
If you see limitipconn_module (shared), you are ready. After upgrading Apache, you may need to rebuild the module using the same steps.
Setting the concurrent connection limit
The module provides three directives:
| Directive | Meaning |
|---|---|
MaxConnPerIP number |
Maximum simultaneous connections from one IP address. 0 means no limit |
NoIPLimit MIME-type… |
Do not count the listed MIME types (e.g. image/*) |
OnlyIPLimit MIME-type… |
Count only the listed MIME types |
On Debian/Ubuntu, create the configuration file in conf-available. The following example limits each IP to 2 simultaneous connections under /downloads only, and does not count images.
sudo nano /etc/apache2/conf-available/limitipconn.conf
ExtendedStatus On
<IfModule mod_limitipconn.c>
<Location /downloads>
MaxConnPerIP 2
NoIPLimit image/*
</Location>
</IfModule>
To limit only video and audio, write something like OnlyIPLimit audio/mpeg video instead of NoIPLimit.
Enable the configuration, check the syntax, then restart.
sudo a2enconf limitipconn
sudo apache2ctl configtest
sudo systemctl restart apache2
Server-wide limits and per-location limits
Writing something like MaxConnPerIP 10 outside <Location> sets a server-wide limit. Note that the server-wide limit and each <Location> limit are calculated separately. For example, if the server-wide limit is 10 and /downloads is 3 with NoIPLimit image/* set for /downloads, the 11th simultaneous image request still hits the server-wide limit. If you want per-location settings to override, put the global limit inside <Location /> and nest the individual <Location> blocks inside it.
Pages that load many images, CSS and JavaScript files make browsers open several connections at once. A small site-wide limit turns normal browsing into 503 errors, so restrict the limit to download paths or exclude static files with NoIPLimit.
Testing that it works
Put a fairly large test file in place and run four bandwidth-limited curl requests at the same time. With a limit of 2, the third and later requests return 503.
sudo mkdir -p /var/www/html/downloads
sudo head -c 5000000 /dev/zero | sudo tee /var/www/html/downloads/big.bin > /dev/null
for i in 1 2 3 4; do
curl -s -o /dev/null --limit-rate 200k -w "req$i %{http_code}\n" http://127.0.0.1/downloads/big.bin &
sleep 0.3
done
wait
Sample output (requests 3 and 4 return 503 immediately; requests 1 and 2 print 200 after their downloads finish in about 25 seconds):
req3 503
req4 503
req1 200
req2 200
Delete the test file when you are done. In production, watch the number of 503s in the access log to make sure the limit isn't too strict.
sudo rm /var/www/html/downloads/big.bin
sudo awk '$9 == 503' /var/log/apache2/access.log | tail
Operational notes
- Logging denied requests: Requests denied by the limit have the environment variable
LIMITIPset to1. Writing something likeCustomLog ${APACHE_LOG_DIR}/access.log combined env=!LIMITIPkeeps the denied requests out of the access log. - Behind a proxy or load balancer: By default, every client is counted as the proxy's IP address, so everyone shares the same limit. Use
mod_remoteip, which ships with Apache 2.4, to restore the original IP fromX-Forwarded-For. List only trusted proxy addresses inRemoteIPTrustedProxy.
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 10.0.0.10
- Users sharing one IP: In offices, schools and on mobile networks, many users share a single IP address. Set the limit too low and legitimate users get 503s.
- No per-IP limits: The same limit applies to every IP address.
- Combining with mod_cache: When used with modules that respond from a quick handler, such as mod_cache, per-location settings such as
<Location>have no effect; only server-wide settings work.
Choosing between this and other approaches
| Goal | Tool |
|---|---|
| Limit simultaneous connections (parallel downloads) from one IP | mod_limitipconn |
| Limit transfer speed per connection | The standard mod_ratelimit (How to limit bandwidth in Apache) |
| Temporarily block IPs that send a burst of requests | mod_evasive (DDoS mitigation with mod_evasive) |
| Control connections and requests in finer detail | mod_qos (How to configure mod_qos) |
Apache modules alone can't absorb attacks coming from many IP addresses. Combine them with a CDN, a WAF or an upstream firewall.
Summary
- mod_limitipconn is a third-party module; build and enable it with
apxs -c -i -a -n limitipconn mod_limitipconn.c - It requires mod_status and
ExtendedStatus On - Set the cap with
MaxConnPerIP, and narrow what is counted by MIME type withNoIPLimit/OnlyIPLimit - Requests over the limit get 503. Behind a proxy, use mod_remoteip so the real client IP is used
- For attack mitigation, combine it with mod_evasive, mod_qos, a CDN or a WAF
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)