CGI#

The module adds support for CGI.

It is important to note that CGI is not suitable for:

  • high QPS;

  • heavy traffic;

  • high concurrency.

Installation#

To install the module, use one of the following packages:

  • Angie: angie-module-cgi

  • Angie PRO: angie-pro-module-cgi

Loading the Module#

To load the module in the main{} context:

load_module modules/ngx_http_cgi_module.so;

Configuration Example#

server {
    listen 80;

    root /usr/share/angie/html;
    index index.html index.htm;

    location /cgi {
        alias /usr/share/angie/cgi-bin;
        cgi on;
    }
}

A location block can also run the same script for every request it handles, regardless of the request URI:

location /hook {
    cgi_set_var HOOK_CLIENT $remote_addr;
    cgi_set_var HOOK_HOST $host;
    cgi_pass /usr/share/angie/cgi-bin/hook.sh;
}

Here cgi_pass runs the named script on its own; cgi on is not needed in this location. Each cgi_set_var directive adds one variable to the script's environment, with a value that may be built from Angie variables. A literal value written directly in cgi_set_var does not reach the script unchanged, so pass such a value through a variable of your own: set $hook_mode test; and then cgi_set_var HOOK_MODE $hook_mode;. Apart from the standard CGI variables, the script receives nothing from the environment of the Angie worker processes: values set with the env directive do not reach it, so everything it needs from the configuration comes through cgi_set_var. The script's standard error goes to the Angie error log at the warn level, so these messages appear only when the log level is warn or less severe. A Status: header in the script's output sets the response code; without such a header the response code is 200. The ACME guide's CGI and octoDNS example builds a DNS-01 hook the same way, in the named location that acme_hook requires, passing the ACME variables to the script that updates the DNS record.

Test Script#

An example test executable script test.sh:

#!/bin/sh
echo "Content-Type: text/plain" # Add header to the response
echo "" # Separator between headers and body of the response

# Environment variables
echo "query string: $QUERY_STRING"
echo "server addr: $SERVER_ADDR"
echo "server port: $SERVER_PORT"

# Request headers via environment variables
echo "http host: $HTTP_HOST"
echo "http accept: $HTTP_ACCEPT"
echo "http Some-Field: $HTTP_SOME_FIELD"

body=$(cat) # Reads the request body into a variable
echo "Request body: $body"

Placing the Script#

According to the configuration, the script must be placed in the /usr/share/angie/cgi-bin/ directory. Installing the module does not create this directory, so create it first:

$ sudo install -d /usr/share/angie/cgi-bin

The file must have read and execute permissions.

Example of Request Execution#

$ curl  -H 'Some-Field:some text' -d '{"key1":"value1", "key2":"value2"}' -i \
  'http://127.0.0.1/cgi/hello.sh?a=valueA&b=valueB'

HTTP/1.1 200 OK
Server: Angie/1.12.2
Date: Thu, 17 Sep 2026 19:15:35 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Content-Type: text/plain

query string: a=valueA&b=valueB
server addr: 127.0.0.1
server port: 80
http host: 127.0.0.1
http accept: */*
http Some-Field: some text
Request body: {"key1":"value1", "key2":"value2"}

Additional Information#

Version: v0.15

Detailed documentation and source code are available at: pjincz/nginx-cgi