reverse proxy FastCGI (fcgi) with uWSGI

People are still using FastCGI, and it's hard. I used uWSGI to convert FCGI traffic to regular http/1.0 so I can keep my existing http service running without apache mod_fcgi shit.

CGI environ variables

This is some ancient knowledge, better keep them noted

KEY description
AUTH_TYPE ignore this
REMOTE_IDENT The user making the request.
REMOTE_USER The authenticated name of the user making the query.
CONTENT_LENGTH byte length of body
CONTENT_TYPE MIME such as text/html, without the charset shit
DOCUMENT_ROOT NEW. The directory from which web documents are served.
REQUEST_URI NEW. confusing shit similar with PATH_INFO
HTTP_* HTTP headers
PATH_INFO like /a/b/c
PATH_TRANSLATED not really used
QUERY_STRING the part after ? in an URL
REMOTE_ADDR client IP
REMOTE_HOST client host name by lookup ip
REQUEST_METHOD GET/POST
SCRIPT_NAME The virtual path (e.g., /cgi-bin/program.pl) of the script being executed.
SCRIPT_FILENAME confusing shit similar with SCRIPT_NAME
SERVER_NAME The server's hostname or IP address.
SERVER_PORT The port number of the host on which the server is running.
SERVER_PROTOCOL The name and revision number of the server protocol.

reverse proxy FastCGI with uWSGI

slap this into my_conf.ini

  [uwsgi]
  my_port = 9000  # can be set otherwise
  route-run = addvar:SERVER_NAME=%h
  route-run = addvar:SERVER_PORT=%(my_port)
  route-if  = empty:${REQUEST_METHOD} addvar:REQUEST_METHOD=GET
  route-if  = empty:${HTTP_HOST} addvar:HTTP_HOST=%h:%(my_port)
  route-run = seturi:/fcgi-proxy${PATH_INFO}
  route-run = http:127.0.0.1:9527
  fastcgi-socket = 0.0.0.0:%(my_port)
  http-socket = 0.0.0.0:8000  # for testing purpose.

Install uWSGI, install the binary from pypi wheels instead of compiling uwsgi.c shit

  pip install pyuwsgi

Run it

  uwsgi --ini my_conf.ini

Now you can run your regular http service behind 127.0.0.1:9527, while serving fcgi on 127.0.0.1:9000

Requests like fcgi://127.0.0.1:9000/hello will be fowwarded to http://127.0.0.1:9527/fcgi-proxy/hello

You may ask why adding a /fcgi-proxy in path? Because there's a gotcha.

fuckedup FastCGI requests

Learned this from some php-fpm tutorial, first install the standard fcgi client tool because curl doesn't speak fcgi.

  apt-get install libfcgi0ldbl
  yum --enablerepo=epel install fcgi
  SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000

You can observe from uWSGI logs that cgi-fcgi command sends flawed requests, the PATH_INFO was unset.

After hours wasted, I came up with a clever hack to force uWSGI's internal router to force seturi with a path prefix

ToDo

There are further problems that can be improved, for example, my http service is running uvicorn, it can not guess the client ip:port infor from its stupid get_remote_addr

what's worse, the uWSGI addheader directive are for responses, so I can't add request headers like x-forwared-for.

Also the reverse proxy is HTTP/1.0 only. to make the Connection: Keep-alive happen needs some further investigation.

Q&A

Thanks for reading my shitpost. Questions?

Comments