Software 44176 Published by

A new version of the Nginx CGI module, version 0.15, can be easily installed on recent Debian or Ubuntu releases by adding the GetPageSpeed repository keyring and then installing the nginx and nginx-module-cgi packages. To use the module, you need to add a load statement to your configuration file if Nginx was compiled manually or stores modules in a custom location, and enable CGI for specific URI prefixes with the cgi on directive. A minimal shell script that prints a greeting can be created by placing a bash file in the document root's cgi-bin directory and ensuring it has execute permission. After configuring the module, you can test the setup by reloading Nginx and accessing the script through its URL, checking for any errors in the log files if necessary.



NGINX CGI 0.15: How to Hook It Into a Running Server

The new CGI module arrives in version 0.15 and is ready for instant deployment on recent Debian or Ubuntu releases. Within ten minutes an ordinary PC user will learn how to install the binary, enable it for a location, and fire up a shell script that prints a greeting.

Getting the pre‑built package

Adding the GetPageSpeed repository keyring to /etc/apt/keyrings is not a cosmetic nicety; if this directory does not exist, the tee command silently fails, and apt will later complain about an “untrusted signature” when trying to install nginx‑cgi.

sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://extras.getpagespeed.com/deb-archive-keyring.gpg \
  | sudo tee /etc/apt/keyrings/getpagespeed.gpg >/dev/null

# Add the repository (Ubuntu example - replace 'ubuntu' and 'jammy' for your distro)
echo "deb [signed-by=/etc/apt/keyrings/getpagespeed.gpg] https://extras.getpagespeed.com/ubuntu jammy main" \
  | sudo tee /etc/apt/sources.list.d/getpagespeed-extras.list

Once the keyring exists, the next step—appending the repository line for your distribution—to the sources list tells apt where to locate both nginx itself and the new module. After a quick apt‑get update, a single command pulls everything in:

sudo apt-get install nginx nginx-module-cgi

The installation process automatically loads the module, so no manual load_module line is required on vanilla Debian 12 or Ubuntu 24.

Loading the module from a custom location

If nginx was compiled manually or if your system stores modules in /usr/lib/nginx/modules-available, the CGI binary will not be found unless an explicit load statement appears at the top of the configuration.

load_module /some/path/ngx_http_cgi_module.so;

Without that line, any later cgi on directives are ignored and requests to scripts will return “404 Not Found” instead of the intended dynamic content.

Turning CGI on for a specific URI prefix

Once nginx knows about the module, adding cgi on; inside a server or location block tells it to hand every matching request off to an external interpreter. The setting is inherited by nested locations unless a child explicitly turns it off with cgi off.
The cascading behaviour means that if you enable CGI for /cgi-bin, all requests under /cgi-bin/* will spawn the script; only a child location that sets cgi off; will prevent that.

A minimal shell CGI script

For a quick sanity check, place a simple bash file in the document root’s cgi-bin directory. The script must emit a header section followed by an empty line, then the body.
A missing separator is the most common cause of a 500 error; this happened to a user after a bad driver update when an accidental carriage‑return slipped into the output.
The example below shows the bare minimum:

#!/bin/bash
echo "Status: 200 OK"
echo "Content-Type: text/plain"
echo
echo "Welcome to CGI world!"

If the shebang line is omitted, nginx‑cgi will reject the file with a “No interpreter” error unless a global cgi_interpreter setting is in place. The safest bet is to keep the shebang and give the file execute permission.

Ensuring execution rights

Nginx‑cgi insists on the executable bit for any script it runs. A 403 Forbidden is easier to diagnose than an opaque “permission denied” error that a missing execute flag can trigger, even on systems where scripts are sometimes run without chmod +x.
The quick workaround—setting cgi_interpreter—is rarely needed; simply applying

sudo chmod +x /var/www/html/cgi-bin/hello.sh

solves the problem in 99 % of setups.

Testing the configuration

After editing the config, a reload guarantees that all changes take effect:

sudo systemctl restart nginx
curl http://127.0.0.1/cgi-bin/hello.sh

The response should read “Welcome to CGI world!”. If it does not, consult /var/log/nginx/error.log; a 500 here usually points to an illegal header or a missing separator, while a 403 indicates that the execute bit was never set.

Things that can go wrong
  • Invalid HTTP headers – Only Status: <code> <text> and well‑formed key/value pairs are allowed; anything else triggers a 500 unless strict mode is disabled.
  • High‑concurrency workloads – Because CGI spawns a new process per request, it does not scale to high QPS or heavy traffic; for those scenarios a lightweight embedded language like Lua or Nginx’s FastCGI integration is preferable.
  • Missing shebang – Without cgi_interpreter, the absence of a shebang line produces a 500 error, even if the file otherwise looks correct.

With these straightforward steps anyone running a recent Debian, Ubuntu, or Fedora distribution can have CGI up and running fast enough to prototype admin scripts or lightweight dynamic pages. 

Release Nginx CGI v0.15

Allow users to control CGI stderr log level Deprecate REMOTE_USER and AUTH_TYPE vars

Release v0.15 · pjincz/nginx-cgi