Skip to content
User65k edited this page Oct 6, 2023 · 6 revisions

Is done using https://github.com/User65k/async-fcgi.

Config

Specify the key fcgi in a mount path. You can also add the entries to serve static files.

fcgi subkey meaning
sock Socket to connect to, e.g. 127.0.0.1:9000 or /var/run/php/php7.4-fpm.sock
exec Optional Array of file types to send to the FCGI App, e.g. ["php"]. This also enables checking if the file does even exist.
set_script_filename Optional if true sets SCRIPT_FILENAME that is needed by PHP, but not part of the FCGI Spec
set_request_uri Optional if true sets REQUEST_URI to the path of the clients request (not part of the FCGI Spec)
timeout Optional max. seconds to wait for an answer. Defaults to 20. 0 means no timeout
params Optional Table of additional (F)CGI Params to set
allow_multiline_header Optional if true forwards requests with line breaks in a header
multiple_header Optional Change which HTTP headers are forwarded to the Application. If not set only the First occurrence is. Can be one of Last or Combine
buffer_request Optional Size in Bytes used to buffer chunked requests. If not set LENGTH REQUIRED is returned to the client upon receiving a chunked request
bin Optional Start the FCGI Application, see below
fcgi.bin subkey meaning
path Path of binary to start
wdir Optional directory to change the working directory to
environment Optional Map of variables to set
copy_environment Optional Array of variable to keep

Examples

PHP on the local Filesystem

Serve static files and run php files with php-cgi7.4

["example.com".php] # /php/* will go to php-cgi via FastCGI
dir = "/opt/php/"
index = ["index.php"]
fcgi.sock = "127.0.0.1:9000" # TCP
fcgi.exec = ["php"] # check that the file exists and ends in .php
# Optional: If we don't want so serve everything else,
# we can limit what will be served to:
serve = ["css", "js", "png", "jpeg", "jpg"]
# PHP does not follow the CGI/1.1 spec, it needs SCRIPT_FILENAME set
# to do so:
fcgi.set_script_filename = true
# Optional: Start the FCGI App from here
fcgi.bin.path = "/usr/bin/php-cgi7.4"
fcgi.bin.environment = {PHP_FCGI_CHILDREN = "4", PHP_FCGI_MAX_REQUESTS = "10000"}
fcgi.bin.copy_environment = ["PATH"]
$ bat -P index.php
───────┬──────────────────────────────────────────────────────────────────────
       │ File: index.php
───────┼──────────────────────────────────────────────────────────────────────
   1   │ <?php
   2   │ echo 'POST: ';
   3   │ print_r($_POST);
   4   │ echo 'GET: ';
   5   │ print_r($_GET);
   6   │ echo 'SERVER: ';
   7   │ print_r($_SERVER);
   8   │ ?>
───────┴──────────────────────────────────────────────────────────────────────
$ curl -d test=123 http://example.com/php/?oh=realy
POST: Array
(
    [test] => 123
)
GET: Array
(
    [oh] => realy
)
SERVER: Array
(
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [PHP_FCGI_CHILDREN] => 4
    [PHP_FCGI_MAX_REQUESTS] => 10000
    [HTTP_ACCEPT] => */*
    [HTTP_USER_AGENT] => curl/7.76.1
    [HTTP_HOST] => example.com
    [REQUEST_METHOD] => POST
    [QUERY_STRING] => oh=realy
    [SERVER_PORT] => 80
    [SCRIPT_FILENAME] => /opt/php/index.php
    [GATEWAY_INTERFACE] => CGI/1.1
    [CONTENT_LENGTH] => 8
    [SCRIPT_NAME] => /php/index.php
    [REMOTE_ADDR] => ::ffff:10.168.255.201
    [SERVER_PROTOCOL] => HTTP/1.1
    [CONTENT_TYPE] => application/x-www-form-urlencoded
    [SERVER_SOFTWARE] => frws
    [SERVER_NAME] => example.com
    [FCGI_ROLE] => RESPONDER
    [PHP_SELF] => /php/index.php
    [REQUEST_TIME_FLOAT] => 1630415187.9611
    [REQUEST_TIME] => 1630415187
)

Flup with PATH_INFO

Serve a flup/python app with its own internal routing (not present on the file system)

["example.com".flup] # /flup/* will go to python via FastCGI
fcgi.sock = "/tmp/fastcgi2.python.sock"
fcgi.bin.path = "/var/www/py_apps/flup_test.py"
# by not specifieing fcgi.exec we allow flup to do the routing
$ bat -P flup_test.py
───────┬──────────────────────────────────────────────────────────────────────
       │ File: flup_test.py
───────┼──────────────────────────────────────────────────────────────────────
   1   │ #!/usr/bin/python3
   2   │ from flup.server.fcgi import WSGIServer
   3   │ from flask import Flask, request, render_template
   4   │ from json import dumps
   5   │ 
   6   │ app = Flask(__name__)
   7   │ 
   8   │ @app.route('/status', methods=['GET', 'POST'])
   9   │ def status():
  10   │     data = {
  11   │       'post': request.form,
  12   │       'get': request.args,
  13   │       'env': {k: v for k, v in request.environ.items() if k[0]!='w'},
  14   │     }
  15   │     ret = dumps(data, indent=4)
  16   │     response = app.response_class(
  17   │             response=ret,
  18   │             status=200,
  19   │             mimetype='application/json'
  20   │     )
  21   │     return response
  22   │ 
  23   │ if __name__ == '__main__':
  24   │     WSGIServer(app).run()
───────┴──────────────────────────────────────────────────────────────────────
$ curl -d test=123 http://example.com/flup/status?oh=realy
{
    "post": {
        "test": "123"
    },
    "get": {
        "oh": "realy"
    },
    "env": {
        "SERVER_SOFTWARE": "frws",
        "SERVER_PORT": "80",
        "REMOTE_ADDR": "::ffff:10.168.255.201",
        "SERVER_NAME": "example.com",
        "SERVER_PROTOCOL": "HTTP/1.1",
        "PATH_INFO": "/status",
        "SCRIPT_NAME": "/flup",
        "GATEWAY_INTERFACE": "CGI/1.1",
        "QUERY_STRING": "oh=realy",
        "REQUEST_METHOD": "POST",
        "CONTENT_TYPE": "application/x-www-form-urlencoded",
        "CONTENT_LENGTH": "8",
        "HTTP_HOST": "example.com",
        "HTTP_USER_AGENT": "curl/7.76.1",
        "HTTP_ACCEPT": "*/*"
    }
}

Clone this wiki locally