lighttpd 1.4.x
https://www.lighttpd.net/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
13 KiB
269 lines
13 KiB
================== |
|
Performance Tuning |
|
================== |
|
|
|
[[ Note: latest version is found at https://wiki.lighttpd.net/Docs_Performance ]] |
|
[[ Note: see version with links at https://wiki.lighttpd.net/Docs_Performance ]] |
|
|
|
important performance tuning rules |
|
|
|
* Prefer lighttpd defaults unless you have a reason to change a setting, |
|
and unless you test that changing the setting is beneficial to you. |
|
* Proper functionality is more important than marginal increases in performance; |
|
a web server that does not function as intended is not useful. |
|
Do not sacrifice security or desired operational functioning for marginal |
|
performance improvements. |
|
* Performance tuning is not magic. The recommended approach is that one change |
|
be made at a time, that the change be tested and benchmarked, and that if the |
|
change does not have a measurable and positive impact in real-world scenarios, |
|
that the change be reverted. |
|
|
|
lighttpd is generally pretty snappy. |
|
Most of the following are micro-optimizations. |
|
No changes are required unless you have a specific performance issue that you |
|
must address. |
|
|
|
|
|
lighttpd configuration performance tuning (technical guidelines) |
|
----------------------------------------- |
|
|
|
* less is more (and is often simpler, too) |
|
- rely on defaults where possible to reduce unnecessary (duplicative) config |
|
processing (at runtime) to process configuration directives which were |
|
already set to the default values |
|
- set config options in the global scope rather than repeating in sub-scopes. |
|
lighttpd optimizes configuration settings in the global scope and makes |
|
those settings the defaults |
|
- TLS configuration can be set in the global scope and inherited by multiple |
|
$SERVER["socket"] |
|
ssl.pemfile = "..." |
|
ssl.privkey = "..." |
|
$SERVER["socket"] == ":443" { ssl.engine = "enable" } |
|
$SERVER["socket"] == "[::]:443" { ssl.engine = "enable" } |
|
- list only the modules actually used and enabled in server.modules; |
|
comment out the others |
|
- each loaded module registers itself into lighttpd hooks and gets a chance |
|
to handle each request, which is is unnecessary if a module is loaded but |
|
not otherwise configured to be used |
|
- server.compat-module-load = "disable" skips loading the default modules |
|
(mod_indexfile, mod_dirlisting, mod_staticfile), and you can then |
|
explicitly add one or more to server.modules to use them |
|
- tweaks to remove optional functionality |
|
- server.tag = "" skips sending "Server: lighttpd/1.4.xx" in responses; |
|
alternatively, use: server.tag = "lighttpd" to hide the lighttpd version |
|
- server.range-requests = "disable" can be used if all server responses are |
|
small files, but otherwise it is recommended to be left enabled |
|
- review the default lighttpd config provided by your distro |
|
- configs provided by distros aim to be newbie friendly but can introduce |
|
complexity of yet another config framework |
|
- configs provided by distros are often out-dated and then kept for historic |
|
compatibility, rather than current best practices |
|
- example: ~20 years ago some widely used versions of Adobe Acrobat reader |
|
plugin PDF clients misbehaved with range requests. Unfortunately, the |
|
config setting to disable range requests for PDFs has been cargo-culted |
|
into configs since then. Prefer to comment out or remove: |
|
$HTTP["url"] =~ "\.pdf$" { server.range-requests = "disable" } |
|
- server.max-connections limits the maximum number of simultaneous connections |
|
to handle and also affects memory usage for the connection cache |
|
- default is (about) 1365 which is oversized for all but the largest |
|
systems. Embedded systems might set server.max-connections = 16 or lower |
|
- server.max-worker = 0 should generally be left unset (or "0"), as |
|
CPU bottlenecks are usually elsewhere |
|
- server.follow-symlink = "enable" (default) should be left enabled. If such |
|
restrictions are required, prefer to run a separate lighttp instance under a |
|
separate user account, and enforce more restrictive file access permissions. |
|
- ssl.read-ahead = "disable" (default) is strongly recommended for slower, |
|
embedded systems which process TLS packets more slowly than network |
|
wire-speed. For faster systems, test if ssl.read-ahead = "enable" improves |
|
performance (or not) |
|
- prefer to configure mod_extforward extforward.hap-PROXY for lighttpd |
|
instances behind HAProxy or load balancers supporting the HAProxy PROXY |
|
protocol |
|
* minimize conditional processing (but not at the cost of proper functionality) |
|
- more conditions means more config processing at runtime |
|
- more conditions means more memory used by config per request |
|
- avoid repeating conditions and its opposite by joining them into if/else |
|
<condition> { ... } else { ... } |
|
<condition> { ... } else <condition> { ... } else { ... } |
|
- sometimes it may take fewer config lines to set a config option once in the |
|
global scope and then, where necessary, to unset the option in a small |
|
number of conditions rather than leaving the default in the global scope |
|
and enabling the config option in many more conditions |
|
- having no config conditions will be among the fastest configs to be |
|
processed, but config processing at runtime is fast and is not typically |
|
a bottleneck |
|
* dynamic backends (mod_proxy, mod_fastcgi, mod_scgi, mod_ajp13, ...) |
|
- prefer to use unix domain sockets (instead of TCP sockets) for connections |
|
from lighttpd to backends running on the same host |
|
- lighttpd can listen on a unix domain socket |
|
(server.bind = "/path/to/lighttpd.sock") |
|
and lighttpd mod_proxy can act as a reverse-proxy to a backend lighttpd |
|
server. Use with mod_extforward to preserve client remote address for the |
|
backend. |
|
* mod_fastcgi |
|
- Recommended: use PHP-FPM (FastCGI Process Manager), |
|
which is available as a package in many OS distros |
|
- If not using PHP-FPM, then see Docs_PerformanceFastCGI |
|
- lighttpd provides mechanisms for lighttpd to start up PHP backends, and |
|
that works well, but PHP-FPM is the modern and recommended mechanism to |
|
manage PHP backends |
|
* mod_rewrite and mod_redirect: short-circuiting |
|
(when using a sequence of regexes) |
|
- consider putting static file matches (passed through unmodified) first, |
|
and using a blank target to indicate no modification |
|
- consider using a blank match as a catch-all, rather than "^(.*)", |
|
which will still match all, but without the regex |
|
url.rewrite-once = ( |
|
"^/static/|\.(?:css|jpg)$" => "", |
|
"" => "/index.php${url.path}${qsa}" |
|
) |
|
* mod_indexfile: reduce the number of entries in index-file.names, |
|
if mod_indexfile is enabled |
|
- index-file.names = ("index.html") as a list of one or two entries rather |
|
than a list of, say, 10 differenent file extensions |
|
* cache tuning |
|
- stat_cache: default server.stat_cache-engine = "simple" works well for |
|
typical usage and caches stat() results for 1-2 seconds. Test with |
|
server.stat-cache-engine = "inotify" or server.stat-cache-engine = "kqueue" |
|
for stat() results to be cached longer (16 seconds) |
|
- mod_auth: set auth.cache = ("max-age" => "600") to cache passwords (default |
|
disabled), but acknowledge changes to your security posture if enabling the |
|
cache. (since lighttpd 1.4.56) |
|
- mod_deflate: set deflate.cache-dir to cache (and reuse) compressed static |
|
assets based on ETag (since lighttpd 1.4.56) |
|
- mod_dirlisting: set dir-listing.cache = ( ... ) to configure caching of |
|
generated directory listings (since lighttpd 1.4.60) |
|
* do not sacrifice security to save a few CPU cycles |
|
- server.http-parseopts* option defaults are recommended, and are very fast |
|
- disabling server.http-parseopts* might save a few CPU cycles, but is an |
|
anti-pattern for secure configurations |
|
- server.http-parseopts* options should be modified only when the |
|
functionality needs to be tuned for proper site operation |
|
- ETag response headers are used in HTTP/1.1 conditional caching. |
|
ETag response headers are also required for mod_deflate and strongly |
|
recommended with mod_webdav. While lighttpd ETag generation for |
|
static content can be disabled for micro-benchmarking purposes, |
|
ETag generation (default enabled) is recommended for production use |
|
(etag.use-inode, etag.use-mtime, etag.use-size) |
|
* compile lighttpd with mmap support (./configure --enable-mmap) to improve |
|
mod_deflate performance |
|
|
|
|
|
lighttpd configuration for use of operating system (OS) features |
|
---------------------------------------------------------------- |
|
|
|
lighttpd generally chooses optimal defaults for the OS on which it is running. |
|
Prefer lighttpd defaults unless something is not functioning correctly. |
|
(Please report bugs and include your platform information if the lighttpd OS |
|
defaults are not working correctly.) |
|
|
|
* server.event-handler (e.g. epoll, kqueue, event ports, devpoll, poll, ...) |
|
* server.network-backend (e.g. sendfile, writev, write) |
|
|
|
|
|
lighttpd configuration tuning for high-traffic sites with a large number of connections |
|
--------------------------------------------------------------------------------------- |
|
|
|
* test with server.max-fds = 16384 (or higher) and OS system and/or per-user |
|
ulimit -Hn might need to be adjusted to allow this or higher values. |
|
For each 4k increase in server.max-fds, lighttpd uses an additional ~100 kb |
|
of memory for internal structures, not including memory used by each active |
|
connection. (In other words, there is a marginal cost for using very high |
|
values when there are not nearly so many simultaneous open connections). |
|
server.max-connections is calculated to be 1/3 of server.max-fds if |
|
server.max-connections is not configured. |
|
|
|
|
|
lighttpd configuration tuning for low-memory systems |
|
---------------------------------------------------- |
|
|
|
* test with server.max-fds = 128 (or lower) |
|
* test with server.max-connections = 16 (or lower) |
|
* test with server.listen-backlog = 16 (or lower) |
|
* (default) server.stat_cache-engine = "simple" |
|
* (default) ssl.read-ahead = "disable" |
|
* support for the HTTP/2 protocol (enabled by default in lighttpd 1.4.59) uses |
|
more memory than HTTP/1.1; low-memory systems might choose to disable HTTP/2 |
|
protocol support: server.feature-flags += ("server.h2proto" => "disable") |
|
|
|
|
|
lighttpd configuration tuning for traffic shapping (download rate-limiting) |
|
-------------------------------------------------- |
|
|
|
connection.kbytes-per-second |
|
server.kbytes-per-second |
|
|
|
|
|
lighttpd configuration tuning for timeouts |
|
------------------------------------------ |
|
|
|
To free up connections more quickly, tune down the idle timeouts for how long |
|
lighttpd waits to read or write to the client (when lighttpd is trying to read |
|
or write), or how long lighttpd waits for the next keep-alive request, and for |
|
how many keep-alive requests, before lighttpd closes the connection. A value |
|
of 0 disables an idle timeout and is not recommended. |
|
* server.max-read-idle = 60 |
|
* server.max-write-idle = 360 |
|
* server.max-keep-alive-idle = 5 |
|
* server.max-keep-alive-requests = 100 |
|
Generally, server.max-keep-alive-requests should not be set to 0 since setting |
|
up a new TCP connection takes more resources than keeping an open idle fd, |
|
especially if the connection is over TLS. |
|
|
|
|
|
Platform-Specific Notes |
|
======================= |
|
|
|
Note: The following is old and possibly out-dated. |
|
Please consider only as a starting point for further testing. |
|
|
|
Linux |
|
----- |
|
|
|
For Linux 2.4.x you should think about compiling lighttpd with the option |
|
``--disable-lfs`` to disable the support for files larger than 2GB. lighttpd will |
|
fall back to the ``writev() + mmap()`` network calls which is ok, but not as |
|
fast as possible but support files larger than 2GB. |
|
|
|
Disabling the TCP options reduces the overhead of each TCP packet and might |
|
help to get the last few percent of performance out of the server. Be aware that |
|
disabling these options most likely decreases performance for high-latency and lossy |
|
links. |
|
|
|
- net.ipv4.tcp_sack = 0 |
|
- net.ipv4.tcp_timestamps = 0 |
|
|
|
Increasing the TCP send and receive buffers will increase the performance a |
|
lot if (and only if) you have a lot of large files to send. |
|
|
|
- net.ipv4.tcp_wmem = 4096 65536 524288 |
|
- net.core.wmem_max = 1048576 |
|
|
|
If you have a lot of large file uploads, increasing the receive buffers will help. |
|
|
|
- net.ipv4.tcp_rmem = 4096 87380 524288 |
|
- net.core.rmem_max = 1048576 |
|
|
|
Keep in mind that every TCP connection uses the configured amount of memory for socket |
|
buffers. If you've got many connections this can quickly drain the available memory. |
|
|
|
See http://www.acc.umu.se/~maswan/linux-netperf.txt for more information on these parameters. |
|
|
|
FreeBSD |
|
------- |
|
|
|
On FreeBSD you might gain some performance by enabling accept filters. Just |
|
compile your kernel with: :: |
|
|
|
options ACCEPT_FILTER_HTTP |
|
|
|
For more ideas about tuning FreeBSD read: tuning(7) |
|
|
|
Reducing the recvspace should always be ok if the server only handles HTTP |
|
requests without large uploads. Increasing the sendspace would reduce the |
|
system load if you have a lot of large files to be sent, but keep in mind that |
|
you have to provide the memory in the kernel for each connection. 1024 * 64KB |
|
would mean 64MB of kernel RAM. Keep this in mind. |
|
|
|
- net.inet.tcp.recvspace = 4096 |
|
|
|
|