How to use CGI scripts with NGINX using Fastcgi
A tutorial on setting up Fastcgi and NGINX
by spitemim, 2021-08-04
After hours of deliberating over NGINX error logs and unhelpful online tutorials, I have finally figured out how to use CGI scripts with Fastcgi and NGINX. In case anyone else is having the same problem I was, here’s the solution.
After following these instructions, you will have Fastcgi and NGINX set up together, and will be able to execute any executable script as a CGI script when placed somewhere within your document root.
Note: these instructions were written around August of 2021, and confirmed working as of July 2022. If you’re reading these months or years into the future, the instructions may be outdated. Read up on the current state of FastCGI online.
Important Notes
To put it simply, when the user requests a .cgi file on your webserver, FastCGI executes this file and pipes its stdout to the user. Typically, we will write these scripts to write HTML to stdout. This makes it easy to write dynamic parts of an otherwise simple/static webpage without leveraging a big language like PHP. CGI was the big way to write dynamic web applications in the ‘90s, and honestly I still like it today.
What we will be doing is setting up NGINX and FastCGI so that, when accessed by the user, .cgi files will be executed and their outputs sent to the user’s browser.
Instructions
For simplicity, we will be using a shell script as an example, but you can use any interpreted language as long as it has the correct shebang.
You can even run C programs as CGI scripts if your compiler supports running C programs. See TCC.
These instructions are meant for Debian/Ubuntu systems, and they assume some familiarity with NGINX and the command line.
Make sure you have NGINX and fcgiwrap installed.
sudo apt-get install fcgiwrap nginx
Enable NGINX and fcgiwrap.
sudo systemctl enable --now nginx fcgiwrap fcgiwrap.socket
If the file
/etc/nginx/fastcgi.conf
doesn’t exist, create it with these contents:#fastcgi.conf fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;
Add the following to the
server
block of the NGINX site file you want to enable CGI scripts for. This file is located in/etc/nginx/sites-available
and, if it is enabled, should have a symlink in/etc/nginx/sites-enabled
.location ~ (\.cgi)$ { gzip off; fastcgi_pass unix:/var/run/fcgiwrap.socket; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi.conf ; }
Create a test CGI script. This example script is writtten in
sh
and should display memory usage details. Create a file called test.cgi somewhere in your document root (e.g:/var/www/html/test.cgi
) and add these contents:#!/bin/sh echo "Content-type: text/html" echo "" cat << EOF <html> <head> <meta http=equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Example CGI script</title> </head> <body> <h1>CGI scripts work!!!</h1> <pre> EOF free cat << EOF </pre> </body> </html> EOF exit 0
Make sure the script is executable and readable by the webserver.
sudo chmod a+rx test.cgi
Test that the script worked by trying to access it from your browser. If you saved it at
/var/www/html/test.cgi
and nginx is running on https://example.com, you should go to https://example.com/test.cgi in your browser. If everything went smoothly, you should see something similar to this:
If the above steps didn’t work, this page is probably outdated or maybe I’m retarded. Try a more up-to-date guide or ask your local guru.