1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
|
=====================
the FastCGI Interface
=====================
-------------------
Module: mod_fastcgi
-------------------
:Author: Jan Kneschke
:Date: $Date: 2004/11/03 22:26:05 $
:Revision: $Revision: 1.3 $
:abstract:
The FastCGI interface is the fastest and most secure way
to interface external process-handlers like Perl, PHP and
your self-written applications.
.. meta::
:keywords: lighttpd, FastCGI
.. contents:: Table of Contents
Description
===========
lighttpd provides an interface to a external programs that
support the FastCGI interface. The FastCGI Interface is
defined by http://www.fastcgi.com/ and is a
platform-independent and server independent interface between
a web-application and a webserver.
This means that FastCGI programs that run with the Apache
Webserver will run seamlessly with lighttpd and vice versa.
FastCGI
-------
FastCGI is removes a lot of the limitations of CGI programs.
CGI programs have the problem that they have to be restarted
by the webserver for every request which leads to really bad
performance values.
FastCGI removes this limitation by keeping the process running
and handling the requests by this always running process. This
removes the time used for the fork() and the overall startup
and cleanup time which is necessary to create and destroy a
process.
While CGI programs communicate to the server over pipes,
FastCGI processes use Unix-Domain-Sockets or TCP/IP to talk
with the webserver. This gives you the second advantage over
simple CGI programs: FastCGI don't have to run on the Webserver
itself but everywhere in the network.
lighttpd takes it a little bit further by providing a internal
FastCGI load-balancer which can be used to balance the load
over multiple FastCGI Servers. In contrast to other solutions
only the FastCGI process has to be on the cluster and not the
whole webserver. That gives the FastCGI process more resources
than a e.g. load-balancer+apache+mod_php solution.
If you compare FastCGI against a apache+mod_php solution you
should note that FastCGI provides additional security as the
FastCGI process can be run under different permissions that
the webserver and can also live a chroot which might be
different than the one the webserver is running in.
Options
=======
lighttpd provides the FastCGI support via the fastcgi-module
(mod_fastcgi) which provides 2 options in the config-file:
fastcgi.debug
a value between 0 and 65535 to set the debug-level in the
FastCGI module. Currently only 0 and 1 are used. Use 1 to
enable some debug output, 0 to disable it.
fastcgi.map-extensions
map multiple extensions to the same fastcgi server
Example: ::
fastcgi.map-extensions = ( ".php3" => ".php" )
fastcgi.server
tell the module where to send FastCGI requests to. Every
file-extension can have it own handler. Load-Balancing is
done by specifying multiple handles for the same extension.
structure of fastcgi.server section: ::
( <extension> =>
(
( "host" => <string> ,
"port" => <integer> ,
"socket" => <string>, # either socket
# or host+port
"bin-path" => <string>, # OPTIONAL
"bin-environment" => <array>, # OPTIONAL
"bin-copy-environment" => <array>, # OPTIONAL
"mode" => <string>, # OPTIONAL
"docroot" => <string> , # OPTIONAL if "mode"
# is not "authorizer"
"check-local" => <string>, # OPTIONAL
"max-procs" => <integer>, # OPTIONAL
"broken-scriptfilename" => <boolean>, # OPTIONAL
"disable-time" => <integer>, # optional
"allow-x-send-file" => <boolean>, # optional
"kill-signal" => <integer>, # OPTIONAL
"fix-root-scriptname" => <boolean>,
# OPTIONAL
( "host" => ...
)
)
)
:<extension>: is the file-extension or prefix
(if started with "/")
:"host": is hostname/ip of the FastCGI process
:"port": is tcp-port on the "host" used by the FastCGI
process
:"bin-path": path to the local FastCGI binary which should be
started if no local FastCGI is running
:"socket": path to the unix-domain socket
:"mode": is the FastCGI protocol mode.
Default is "responder", also "authorizer"
mode is implemented.
:"docroot": is optional and is the docroot on the remote
host for default "responder" mode. For
"authorizer" mode it is MANDATORY and it points
to docroot for authorized requests. For security
reasons it is recommended to keep this docroot
outside of server.document-root tree.
:"check-local": is optional and may be "enable" (default) or
"disable". If enabled the server first check
for a file in local server.document-root tree
and return 404 (Not Found) if no such file.
If disabled, the server forward request to
FastCGI interface without this check.
:"broken-scriptfilename": breaks SCRIPT_FILENAME in a wat that
PHP can extract PATH_INFO from it (default: disabled)
:"disable-time": time to wait before a disabled backend is checked
again
:"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
are allowed
:"fix-root-scriptname": fix broken path-info split for "/" extension ("prefix")
If bin-path is set:
:"max-procs": the upper limit of the processess to start
:"bin-environment": put an entry into the environment of
the started process
:"bin-copy-environement": clean up the environment and copy
only the specified entries into the fresh
environment of the spawn process
:"kill-signal": signal to terminate the FastCGI process with,
defauls to SIGTERM
Examples
--------
Multiple extensions for the same host ::
fastcgi.server = ( ".php" =>
(( "host" => "127.0.0.1",
"port" => 1026,
"bin-path" => "/usr/local/bin/php"
)),
".php4" =>
(( "host" => "127.0.0.1",
"port" => 1026
))
)
Example with prefix: ::
fastcgi.server = ( "/remote_scripts/" =>
(( "host" => "192.168.0.3",
"port" => 9000,
"check-local" => "disable",
"docroot" => "/" # remote server may use
# it's own docroot
))
)
The request `http://my.host.com/remote_scripts/test.cgi` will
be forwarded to fastcgi server at 192.168.0.3 and the value
"/remote_scripts/test.cgi" will be used for the SCRIPT_NAME
variable. Remote server may prepend it with its own
document root. The handling of index files is also the
resposibility of remote server for this case.
In the case that the prefix is not terminated with a slash
the prefix will be handled as file and /test.cgi would become
a PATH_INFO instead of part of SCRIPT_NAME.
Example for "authorizer" mode: ::
fastcgi.server = ( "/remote_scripts/" =>
(( "host" => "10.0.0.2",
"port" => 9000,
"docroot" => "/path_to_private_docs",
"mode" => "authorizer"
))
)
Note that if "docroot" is specified then its value will be
used in DOCUMENT_ROOT and SCRIPT_FILENAME variables passed
to FastCGI server.
Load-Balancing
==============
The FastCGI plugin provides automaticly a load-balancing between
multiple FastCGI servers. ::
fastcgi.server = ( ".php" =>
(( "host" => "10.0.0.2", "port" => 1030 ),
( "host" => "10.0.0.3", "port" => 1030 ))
)
To understand how the load-balancing works you can enable the
fastcgi.debug option and will get a similar output as here: ::
proc: 127.0.0.1 1031 1 1 1 31454
proc: 127.0.0.1 1028 1 1 1 31442
proc: 127.0.0.1 1030 1 1 1 31449
proc: 127.0.0.1 1029 1 1 2 31447
proc: 127.0.0.1 1026 1 1 2 31438
got proc: 34 31454
release proc: 40 31438
proc: 127.0.0.1 1026 1 1 1 31438
proc: 127.0.0.1 1028 1 1 1 31442
proc: 127.0.0.1 1030 1 1 1 31449
proc: 127.0.0.1 1031 1 1 2 31454
proc: 127.0.0.1 1029 1 1 2 31447
Even if this for multiple FastCGI children on the local machine
the following explaination is valid for remote connections too.
The output shows:
- IP, port, unix-socket (is empty here)
- is-local, state (0 - unset, 1 - running, ... )
- active connections (load)
- PID
As you can see the list is always sorted by the load field.
Whenever a new connection is requested, the first entry (the one
with the lowest load) is selected, the load is increased (got proc: ...)
and the list is sorted again.
If a FastCGI request is done or the connection is dropped, the load on the
FastCGI proc decreases and the list is sorted again (release proc: ...)
This behaviour is very light-weight in code and still very efficient
as it keeps the fastcgi-servers equally loaded even if they have different
CPUs.
Adaptive Process Spawning
=========================
.. note:: This feature is disabled in 1.3.14 again. min-procs is
ignored in that release
Starting with 1.3.8 lighttpd can spawn processes on demand if
a bin-path is specified and the FastCGI process runs locally.
If you want to have a least one FastCGI process running and
more of the number of requests increases you can use min-procs
and max-procs.
A new process is spawned as soon as the average number of
requests waiting to be handle by a single process increases the
max-load-per-proc setting.
The idle-timeout specifies how long a fastcgi-process should wait
for a new request before it kills itself.
Example
-------
::
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php.socket",
"bin-path" => "/usr/local/bin/php",
"min-procs" => 1,
"max-procs" => 32,
"max-load-per-proc" => 4,
"idle-timeout" => 20
))
)
Disabling Adaptive Spawning
---------------------------
Adaptive Spawning is a quite new feature and it might misbehave
for your setup. There are several ways to control how the spawing
is done:
1. ``"max-load-per-proc" => 1``
if that works for you, great.
2. If not set ``min-procs == max-procs``.
3. For PHP you can also use: ::
$ PHP_FCGI_CHILDREN=384 ./lighttpd -f ./lighttpd.conf
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php.socket",
"bin-path" => "/usr/local/bin/php",
"min-procs" => 1,
"max-procs" => 1,
"max-load-per-proc" => 4,
"idle-timeout" => 20
))
)
It will create one socket and let's PHP create the 384 processes itself.
4. If you don't want lighttpd to manage the fastcgi processes, remove the
bin-path and use spawn-fcgi to spawn them itself.
FastCGI and Programming Languages
=================================
Preparing PHP as a FastCGI program
----------------------------------
One of the most important application that has a FastCGI
interface is php which can be downloaded from
http://www.php.net/ . You have to recompile the php from
source to enable the FastCGI interface as it is normally
not enabled by default in the distributions.
If you already have a working installation of PHP on a
webserver execute a small script which just contains ::
<?php phpinfo(); ?>
and search for the line in that contains the configure call.
You can use it as the base for the compilation.
You have to remove all occurences of `--with-apxs`, `--with-apxs2`
and the like which would build PHP with Apache support. Add the
next three switches to compile PHP with FastCGI support::
$ ./configure \
--enable-fastcgi \
--enable-force-cgi-redirect \
...
After compilation and installation check that your PHP
binary contains FastCGI support by calling: ::
$ php -v
PHP 4.3.3RC2-dev (cgi-fcgi) (built: Oct 19 2003 23:19:17)
The important part is the (cgi-fcgi).
Starting a FastCGI-PHP
----------------------
Starting with version 1.3.6 lighttpd can spawn the FastCGI
processes locally itself if necessary: ::
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/local/bin/php"
))
)
PHP provides 2 special environment variables which control the number of
spawned workes under the control of a single watching process
(PHP_FCGI_CHILDREN) and the number of requests what a single worker
handles before it kills itself. ::
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/local/bin/php",
"bin-environment" => (
"PHP_FCGI_CHILDREN" => "16",
"PHP_FCGI_MAX_REQUESTS" => "10000"
)
))
)
To increase the security of the started process you should only pass
the necessary environment variables to the FastCGI process. ::
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/local/bin/php",
"bin-environment" => (
"PHP_FCGI_CHILDREN" => "16",
"PHP_FCGI_MAX_REQUESTS" => "10000" ),
"bin-copy-environment" => (
"PATH", "SHELL", "USER" )
))
)
Configuring PHP
---------------
If you want to use PATH_INFO and PHP_SELF in you PHP scripts you have to
configure php and lighttpd. The php.ini needs the option: ::
cgi.fix_pathinfo = 1
and the option ``broken-scriptfilename`` in your fastcgi.server config: ::
fastcgi.server = ( ".php" =>
(( "socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/local/bin/php",
"bin-environment" => (
"PHP_FCGI_CHILDREN" => "16",
"PHP_FCGI_MAX_REQUESTS" => "10000" ),
"bin-copy-environment" => (
"PATH", "SHELL", "USER" ),
"broken-scriptfilename" => "enable"
))
)
Why this ? the ``cgi.fix_pathinfo = 0`` would give you a working ``PATH_INFO``
but no ``PHP_SELF``. If you enable it, it turns around. To fix the
``PATH_INFO`` `--enable-discard-path` needs a SCRIPT_FILENAME which is against the CGI spec, a
broken-scriptfilename. With ``cgi.fix_pathinfo = 1`` in php.ini and
``broken-scriptfilename => "enable"`` you get both.
External Spawning
-----------------
Spawning FastCGI processes directly in the webserver has some
disadvantages like
- FastCGI process can only run locally
- has the same permissions as the webserver
- has the same base-dir as the webserver
As soon as you are using a seperate FastCGI Server to
take off some load from the webserver you have to control
the FastCGI process by a external program like spawn-fcgi.
spawn-fcgi is used to start a FastCGI process in its own
environment and set the user-id, group-id and change to
another root-directory (chroot).
For convenience a wrapper script should be used which takes
care of all the necessary option. Such a script in included
in the lighttpd distribution and is call spawn-php.sh.
The script has a set of config variables you should take
a look at: ::
## ABSOLUTE path to the spawn-fcgi binary
SPAWNFCGI="/usr/local/sbin/spawn-fcgi"
## ABSOLUTE path to the PHP binary
FCGIPROGRAM="/usr/local/bin/php"
## bind to tcp-port on localhost
FCGIPORT="1026"
## bind to unix domain socket
# FCGISOCKET="/tmp/php.sock"
## number of PHP childs to spawn
PHP_FCGI_CHILDREN=10
## number of request server by a single php-process until
## is will be restarted
PHP_FCGI_MAX_REQUESTS=1000
## IP adresses where PHP should access server connections
## from
FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.0.1"
# allowed environment variables sperated by spaces
ALLOWED_ENV="ORACLE_HOME PATH USER"
## if this script is run as root switch to the following user
USERID=wwwrun
GROUPID=wwwrun
If you have set the variables to values that fit to your
setup you can start it by calling: ::
$ spawn-php.sh
spawn-fcgi.c.136: child spawned successfully: PID: 6925
If you get "child spawned successfully: PID:" the php
processes could be started successfully. You should see them
in your processlist: ::
$ ps ax | grep php
6925 ? S 0:00 /usr/local/bin/php
6928 ? S 0:00 /usr/local/bin/php
...
The number of processes should be PHP_FCGI_CHILDREN + 1.
Here the process 6925 is the master of the slaves which
handle the work in parallel. Number of parallel workers can
be set by PHP_FCGI_CHILDREN. A worker dies automaticly of
handling PHP_FCGI_MAX_REQUESTS requests as PHP might have
memory leaks.
If you start the script as user root php processes will be
running as the user USERID and group GROUPID to drop the
root permissions. Otherwise the php processes will run as
the user you started script as.
As the script might be started from a unknown stage or even
directly from the command-line it cleans the environment
before starting the processes. ALLOWED_ENV contains all
the external environement variables that should be available
to the php-process.
Perl
----
For Perl you have to install the FCGI module from CPAN.
Skeleton for remote authorizer
==============================
The basic functionality of authorizer is as follows (see
http://www.fastcgi.com/devkit/doc/fcgi-spec.html, 6.3 for
details). ::
#include <fcgi_stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main () {
char* p;
while (FCGI_Accept() >= 0) {
/* wait for fastcgi authorizer request */
printf("Content-type: text/html\r\n");
if ((p = getenv("QUERY_STRING")) == NULL) ||
<QUERY_STRING is unauthorized>)
printf("Status: 403 Forbidden\r\n\r\n");
else printf("\r\n");
/* default Status is 200 - allow access */
}
return 0;
}
It is possible to use any other variables provided by
FastCGI interface for authorization check. Here is only an
example.
Troubleshooting
===============
fastcgi.debug should be enabled for troubleshooting.
If you get: ::
(fcgi.c.274) connect delayed: 8
(fcgi.c.289) connect succeeded: 8
(fcgi.c.745) unexpected end-of-file (perhaps the fastcgi
process died): 8
the fastcgi process accepted the connection but closed it
right away. This happens if FCGI_WEB_SERVER_ADDRS doesn't
include the host where you are connection from.
If you get ::
(fcgi.c.274) connect delayed: 7
(fcgi.c.1107) error: unexpected close of fastcgi connection
for /peterp/seite1.php (no fastcgi process on host/port ?)
(fcgi.c.1015) emergency exit: fastcgi: connection-fd: 5
fcgi-fd: 7
the fastcgi process is not running on the host/port you are
connection to. Check your configuration.
If you get ::
(fcgi.c.274) connect delayed: 7
(fcgi.c.289) connect succeeded: 7
everything is fine. The connect() call just was delayed a
little bit and is completly normal.
|