Close Menu

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    How to turn a USB flash drive into a portable games console

    Don’t buy a PCIe 5.0 SSD unless you say ‘Yes’ to these 3 questions

    Windows Recall is too risky for your PC. I can’t recommend it

    Facebook X (Twitter) Instagram
    • Artificial Intelligence
    • Business Technology
    • Cryptocurrency
    • Gadgets
    • Gaming
    • Health
    • Software and Apps
    • Technology
    Facebook X (Twitter) Instagram Pinterest Vimeo
    Tech AI Verse
    • Home
    • Artificial Intelligence

      Blue-collar jobs are gaining popularity as AI threatens office work

      August 17, 2025

      Man who asked ChatGPT about cutting out salt from his diet was hospitalized with hallucinations

      August 15, 2025

      What happens when chatbots shape your reality? Concerns are growing online

      August 14, 2025

      Scientists want to prevent AI from going rogue by teaching it to be bad first

      August 8, 2025

      AI models may be accidentally (and secretly) learning each other’s bad behaviors

      July 30, 2025
    • Business

      Why Certified VMware Pros Are Driving the Future of IT

      August 24, 2025

      Murky Panda hackers exploit cloud trust to hack downstream customers

      August 23, 2025

      The rise of sovereign clouds: no data portability, no party

      August 20, 2025

      Israel is reportedly storing millions of Palestinian phone calls on Microsoft servers

      August 6, 2025

      AI site Perplexity uses “stealth tactics” to flout no-crawl edicts, Cloudflare says

      August 5, 2025
    • Crypto

      Chainlink (LINK) Price Uptrend Likely To Reverse as Charts Hint at Exhaustion

      August 31, 2025

      What to Expect From Solana in September

      August 31, 2025

      Bitcoin Risks Deeper Drop Toward $100,000 Amid Whale Rotation Into Ethereum

      August 31, 2025

      3 Altcoins Smart Money Are Buying During Market Pullback

      August 31, 2025

      Solana ETFs Move Closer to Approval as SEC Reviews Amended Filings

      August 31, 2025
    • Technology

      How to turn a USB flash drive into a portable games console

      August 31, 2025

      Don’t buy a PCIe 5.0 SSD unless you say ‘Yes’ to these 3 questions

      August 31, 2025

      Windows Recall is too risky for your PC. I can’t recommend it

      August 31, 2025

      Alienware’s 1440p ultrawide OLED gaming monitor is a huge 50% off

      August 31, 2025

      Clearance! This Asus OLED laptop with 16GB RAM is only $570

      August 31, 2025
    • Others
      • Gadgets
      • Gaming
      • Health
      • Software and Apps
    Check BMI
    Tech AI Verse
    You are at:Home»Technology»Nginx-CGI brings support for CGI to Nginx and angie
    Technology

    Nginx-CGI brings support for CGI to Nginx and angie

    TechAiVerseBy TechAiVerseAugust 30, 2025No Comments19 Mins Read0 Views
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Nginx-CGI brings support for CGI to Nginx and angie
    Share
    Facebook Twitter LinkedIn Pinterest WhatsApp Email

    BMI Calculator – Check your Body Mass Index for free!

    Nginx-CGI brings support for CGI to Nginx and angie

    nginx-cgi plugin

    Brings CGI support to Nginx and
    Angie webserver.

    OS Tested with Nginx Angie
    Linux AlmaLinux 9, Debian 12 and Ubuntu 24.04/20.04 okay okay
    Darwin MacOS 15.1 okay okay
    BSD FreeBSD 14.2 and OpenBSD 7.6 okay okay
    Solaris OmniOS r1510521 okay okay
    Windows No plan, nginx barely supports Windows

    Before everything

    CGI is neither a demon nor an angel. It is simply a tool. Just like a chef’s
    knife in the hands of a cook or a sword in the hands of a warrior, you won’t use
    a sword for cooking, nor you take a chef’s knife to the battlefield. The same
    goes for CGI, it has its appropriate scenarios, and it should not be misused or
    demonized.

    CGI is good for:

    • Low frequency applications, such as system management
    • Resource limited systems, such as embeding system
    • Low budget projects, such as personal websites
    • Prototyping, for fast iterate

    CGI is bad for:

    • High QPS
    • High traffic
    • High concurrency

    I created a discord channel. If:

    • You are also a fun of CGI
    • If you have any problem with nginx-cgi
    • If you want to get update of nginx-cgi
    • If you want to know more friends

    Please join us: https://discord.gg/EJSfqHHmaR.

    Quick start (with Debian 12+, Ubuntu 24.04+)

    Build and install:

    # checkout source code
    git clone https://github.com/pjincz/nginx-cgi
    cd nginx-cgi
    
    # build deb package
    ./build-deb-package.sh
    
    # install built package
    dpkg -i ../libnginx-mod-http-cgi_*_amd64.deb 

    Then enable cgi in nginx. If you have a newly installed nginx, you can find a
    default site at /etc/nginx/sites-enabled/default. The default one looks like
    this:

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
    
        root /var/www/html;
    
        index index.html index.htm index.nginx-debian.html;
    
        server_name _;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    

    The default root points to /var/www/html, keep it as it as, and add
    following section after location / section.

        location /cgi-bin {
            cgi on;
        }
    

    The newly added section means, for all request under /cgi-bin, turns on cgi
    support. Now restart nginx:

    Save following content to /var/www/html/cgi-bin/hello.sh

    #!/bin/bash
    
    echo "Content-Type: text/plain"
    echo
    
    echo Hello CGI

    Add x perm to cgi script:

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

    Now, try it:

    curl http://127.0.0.1/cgi-bin/hello.sh

    If you nothing wrong, you will get an output of Hello CGI.

    Build

    If you are using latest deb based system, such as Debian and Ubuntu, and not
    willing to debug the plugin, you can just following the Quick start to get a
    usable deb package.

    If you are using Angie, the cgi plugin has already in Angie’s official repo.
    Please have a look here:
    https://en.angie.software/angie/docs/installation/oss_packages/#install-thirdpartymodules-oss

    Manual build guide:

    1. Checkout nginx and this plugin

      Generate Makefile in nginx dir

      cd nginx
      ./auto/configure --add-dynamic-module=$PWD/../nginx-cgi [...other option...]

      If you want to debug the plugin, you may also want --with-debug.

      If you want to build a module compatible with system’s nginx, you need run
      nginx -V to checkout system nginx’s build options first.

    2. Make the binary

    If everything is good, then you will find ngx_http_cgi_module.so under objs
    directory.

    Usage

    Loading plugin

    If this plugin is installed to nginx’s default module path (such as
    /usr/lib/nginx/modules), the plugin will be loaded automatically.
    Otherwise, you need to manually load the plugin by load_module.

    Add following statement to nginx’s top level context to load the plugin:

    load_module /ngx_http_cgi_module.so;

    Enable cgi

    After loading the plugin, you can add cgi on to location contexts to enable
    cgi. Example:

    location /cgi-bin {
        cgi on;
    }
    

    Once cgi turned on on a location, all nested locations will also have cgi turned
    on. If you want to disable cgi for a child location, just use cgi off.

    When the location is accessed, nginx-cgi will find the script under the document
    root (it’s specified by root statement). For example, if you have specify the
    document root as /var/www/html, then when you access /cgi-bin/hello.sh,
    /var/www/html/cgi-bin/hello.sh will be executed.

    Nginx-cgi also support alias, it like root statement in nginx, the only
    difference is the location prefix will be removed from uri. For example, if you
    want /cgi/hello.sh also reference to the same script, you can do this:

    location /cgi {
        alias /var/www/html/cgi-bin;
        cgi on;
    }
    

    Hello script

    A cgi script can be wrotten by any language. Here’s an exmaple with shell. You
    can save it to /var/www/html/cgi-bin/hello.sh for testing (if you didn’t
    change the default document root):

    #!/bin/sh
    
    echo "Status: 200 OK"
    echo "Content-Type: text/plain"
    echo
    
    echo "Hello world"

    The first line of the script is a shebang. If you clearly set cgi_interpreter,
    it’s okay to remove this line, otherwise missing of shebang will causes a 500
    error. Some shell allows script be executable even without shebang, but it’s not
    allowed here. If a script runable by shell, but return 500 error, check the
    shebang.

    The output of cgi script contains 2 sections: the header section and body
    section. The first 2 echo statements output the header section, and the last
    echo statement outputs the body section. The echo statement in middle
    outputs the separator. Both header section and body section can be empty, but
    the separator is mandatory. Missing of separator will causes an 500 error.

    All lines in header section will be parsed as normal http response header line.
    And then passed to the client side. There’s one special header Status, it will
    be passed in response status line. If cgi_strict is on, nginx-cgi will check
    all cgi output headers, and 500 error will be responsed if invalid header found.
    Otherwise, invalid headers will be forwarded to client side too. It’s fully
    recommanded to keep cgi_strict on.

    After separator, all output will be sent to client as body as it is.

    x permission

    After all, you need to add the x permission to the file:

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

    Normally, you need x-permission to make script runable. Missing of x-permission
    can cause 403 error. If can’t do this for any reason, cgi_interpreter can
    help.

    Request header

    Request headers will be parsed and then translated to environment variables and
    then passed to cgi script.

    For example, you can find the query string in QUERY_STRING environment var.
    And access Http-Accept by HTTP_ACCPET.

    Here’s an example:

    #!/bin/sh
    echo ""
    
    echo "query string: $QUERY_STRING"
    echo "http accept: $HTTP_ACCEPT"

    For full list of environment variables, see environment section.

    Request body

    The request body will be passed via stdin. Here’s an example to read all request
    body and echo it:

    #!/bin/sh
    echo ""
    
    body=$(cat)
    
    echo "request body: $body"

    Streaming

    Nginx-cgi has streaming support for both request and response body. For example,
    we can implement a simplest online caculator by bc:

    &1″>

    #!/bin/sh
    echo ""
    
    bc 2>&1

    Then we can test our caculator by curl:

    curl 127.0.0.1/cgi-bin/bc.sh --no-progress-meter -T .

    The nginx-cgi plugin is smart enough to choose the correct way to return the
    request body. If it got all output soon enough, it will output the body in once.
    If the output is delayed, it will output the body chunkly(HTTP 1.1) or
    streamingly (HTTP 1.0).

    Hop-by-hop http headers

    Hop-by-hop http headers are not allowed in cgi script output. If it appears
    in response here, a 500 error will response to the client.

    For more information:
    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#hop-by-hop_headers

    Tricks && FAQ

    I want to list all environment variables

    Put following script to your cgi directory, and curl it form your terminal:

    #!/bin/sh
    
    echo 'Content-Type: text/plain'
    echo
    
    printenv

    I want root permission

    Put a sudo file to /etc/sudoers.d and run sudo in your script or set
    cgi_interpreter as /usr/bin/sudo.

    Here’s an example of sudo config file:

    # allow wwww-data run /var/www/bin/my-danger-script with root account
    www-data ALL=(root) NOPASSWD: /var/www/bin/my-danger-script
    
    # allow all CGI script be launched with sudo by nginx-cgi directly
    www-data ALL=(root) NOPASSWD: SETENV: /var/www/html/cgi-bin/*
    

    How can I run CGI scripts with chroot

    It’s highly not recommanded to run CGI script with chroot. Because chroot is not
    designed for security purpose. It still shared a lot of kernel spaces with host
    system. For example, run ps -ef in chrooted process, all processes in host
    system will return. That sould not too aweful? No, that’s really terrible,
    because you can also do kill in chrooted script for the same reason. And
    people normally run programs with root permission in chrooted environment.
    That’s terribly bad. It causes system on high risk than just run script with
    www-data.

    If you want a sandbox environment, lxc, docker and jails are much better
    for this purpose.

    If you still want chroot, okay let me show you how to do it.

    In this example, I assume you’re using /var/www/html as the document root.

    Prepare a CGI script first:

    mkdir -p /var/www/html/cgi-bin
    cat > /var/www/html/cgi-bin/ls.sh <<EOF
    #!/bin/sh
    echo "Status: 200"
    echo "Content-Type: text-plain"
    echo
    echo "files under /:"
    ls /
    EOF
    chmod +x /var/www/html/cgi-bin/ls.sh
    
    # try it
    /var/www/html/cgi-bin/ls.sh

    Step 1: prepare a chroot directory.

    That’re a lot of ways to do this step. debootstrap is a popular way on debian
    based system. busybox is the most light way. docker is a modern way.

    Let’s make a lightest directory with busybox here:

    # In this example, I put everything to /var/www/chroot
    # Be careful, I download x86_64 busybox version here, you may need to change it
    # You need root permission to run all following commands, I'm too lazy to
    # prepend sudo to every commands here.
    
    root_dir=/var/www/chroot
    
    mkdir -p "$root_dir/bin" && cd "$root_dir/bin"
    wget https://www.busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox
    chmod +x busybox
    
    cd "$root_dir"
    mkdir -p $(dirname $(./bin/busybox --list-full) | sort -u)
    ./bin/busybox --list-full | while read line; do ln -sf /bin/busybox $line; done
    
    # try it
    chroot "$root_dir" ls

    Step 2: mount document root into chroot dir

    mkdir -p /var/www/chroot/var/www/html
    mount --bind /var/www/html /var/www/chroot/var/www/html
    
    # try it
    ls /var/www/chroot/var/www/html

    Notice:

    • I use a trick here, after chroot, the document root is still the same. By this
      we can same some time to do path mapping.

    • The mounting will not persist after a reboot. You may need to add an entry to
      /etc/fstab. Or move /var/www/html into chroot, and make a symbolic link
      outside.

    Step 3: allow www-data to run chroot with root permission.

    cat >/etc/sudoers.d/www-run-with-chroot <<EOF
    # allow and only allow www-data run chroot with /var/www/chroot
    www-data ALL=(root) NOPASSWD: /usr/sbin/chroot /var/www/chroot *
    EOF

    Now everything is ready, add following section to your nginx/angie:

    location /cgi-bin {
        cgi on;
        cgi_interpreter /usr/bin/sudo /usr/sbin/chroot /var/www/chroot;
    }
    

    try it:

    curl 127.0.0.1/cgi-bin/ls.sh

    How can I run CGI scripts with docker

    In this example, I assume you’re using /var/www/html as the document root.

    Prepare a CGI script first:

    mkdir -p /var/www/html/cgi-bin
    cat > /var/www/html/cgi-bin/ls.sh <<EOF
    #!/bin/sh
    echo "Status: 200"
    echo "Content-Type: text-plain"
    echo
    echo "files under /:"
    ls /
    EOF
    chmod +x /var/www/html/cgi-bin/ls.sh
    
    # try it
    /var/www/html/cgi-bin/ls.sh

    Create a container and keep running in the background:

    # Change -v if necessary
    # -d: runs background
    # -i -t: keep a terminal
    # --restart always: keep container alive
    docker run -dit --restart always --name my_cgi_docker -v /var/www:/var/www busybox sh
    
    # try it
    docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh

    Allow www-data to run docker commands:

    sudo usermod -aG docker www-data
    
    # try it
    sudo -u www-data docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh

    Now everything is ready, add following section to your nginx/angie:

    location /cgi-bin {
        cgi on;
        cgi_interpreter /usr/bin/docker exec my_cgi_docker;
    }
    

    How can I run CGI scripts with jails

    Okay, you’re a fan of FreeBSD? Me too.

    It’s really similar to running scripts with chroot.

    Here I assume you’re using /var/www/html as the document root too.

    Prepare a CGI script first:

    mkdir -p /var/www/html/cgi-bin
    cat > /var/www/html/cgi-bin/ls.sh <<EOF
    #!/bin/sh
    echo "Status: 200"
    echo "Content-Type: text-plain"
    echo
    echo "files under /:"
    ls /
    EOF
    chmod +x /var/www/html/cgi-bin/ls.sh
    
    # try it
    /var/www/html/cgi-bin/ls.sh

    Step 1: create a jail

    Let’s put the jail to /var/www/jail.

    mkdir -p /var/www/jail && cd /var/www/jail
    fetch https://download.freebsd.org/ftp/releases/$(uname -m)/$(uname -m)/$(uname -r)/base.txz
    tar -xvf base.txz -C .
    
    # create mount points
    mkdir -p /var/www/jail/var/www/html
    touch /var/www/jail/etc/resolv.conf

    Put following config to /etc/jail.conf:

    /var/www/jail/var/www/html
    exec.prestart += “mount_nullfs /var/www/html /var/www/jail/var/www/html || true”;
    mount.devfs;

    # uncomment following lines, if you want to allow network access in jail
    # ip4 = inherit;
    # ip6 = inherit;
    # exec.prestart += “mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true”;

    # uncomment fowlling lines, if you also want `ping` available in jail
    # allow.raw_sockets = 1;

    persist; # keep jail if no process runs
    }”>

    www-jail {
        path = "/var/www/jail";
        host.hostname = "www-jail.local";
    
        exec.clean;
        exec.start = "/bin/sh /etc/rc";
        exec.stop = "/bin/sh /etc/rc.shutdown";
    
        # mount /var/www/html => /var/www/jail/var/www/html
        exec.prestart += "mount_nullfs /var/www/html /var/www/jail/var/www/html || true";
        mount.devfs;
    
        # uncomment following lines, if you want to allow network access in jail
        # ip4 = inherit;
        # ip6 = inherit;
        # exec.prestart += "mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true";
    
        # uncomment fowlling lines, if you also want `ping` available in jail
        # allow.raw_sockets = 1;
    
        persist; # keep jail if no process runs
    }
    

    And ensure that following line appears in /etc/rc.conf:

    And start the jail:

    service jail start www-jail
    
    # try it
    jexec www-jail ls /
    jexec www-jail /var/www/html/cgi-bin/ls.sh

    Step 2: allow www to run jexec with root permission.

    I uses sudo here. I’m not familiar with doas, if you prefer doas you can
    try it yourself. Anyhow, neither sudo nor doas preloaded with FreeBSD. You
    need to manually install one of them.

    cat >/usr/local/etc/sudoers.d/www-jexec <<EOF
    # allow and only allow `www` run `jexec` with `www-jail`
    www ALL=(root) NOPASSWD: /usr/sbin/jexec www-jail *
    EOF
    
    # try it
    sudo -u www sudo jexec www-jail /var/www/html/cgi-bin/ls.sh

    Now everything is ready, add following section to your nginx/angie:

    location /cgi-bin {
        cgi on;
        cgi_interpreter /usr/local/bin/sudo /usr/sbin/jexec www-jail;
    }
    

    try it:

    curl 127.0.0.1/cgi-bin/ls.sh

    I want create a long-run background process

    Just make sure not to inherit stdout when creating the process (ideally, avoid
    inheriting stdin and stderr as well). Here’s an example write in shell.

    “$logfile” 2>&1 &”>

    taskid=1234
    logfile="/var/lib/my-project/$taskid"
    ./long-run-task.sh "$taskid" </dev/null >"$logfile" 2>&1 &

    Or if you are familiar with pipe operation, just close stdout (also, it’s
    better to close stdin and stderr as well), http request will finished
    immediently. And you can use the process as background process.

    My http request hangs

    As you see abvoing. In CGI world, http request’s lifecycle depends on pipe’s
    (stdout’s) lifecycle.

    Each child process might inherit the CGI process’s pipe. If any process that
    inherited stdout remains alive, the HTTP request will never finish.

    This may causes confiusing, when you want a long run background or killing
    CGI process.

    For creating long-run process, see aboving topic.

    For killing CGI process, kill the whole process group rather than CGI process
    itself.

    cgi_pid=...
    
    # don't do this
    # kill "$cgi_pid"
    
    # do this
    kill -- "-$cgi_pid"

    I want to kill my cgi script

    See aboving topic.

    I want to generate content dynamicaly

    Traditionally, people use rewriting to archive this. But it’s much easier here.
    You can do it with cgi pass. Here’s an example to render markdone dynamically:

    {
        location ~ ^.*.md$ {
            cgi_pass /var/www/bin/cgi/render-markdown.sh;
        }
    }
    
    ”
    markdown “${DOCUMENT_ROOT}${PATH_INFO}”
    echo ““”>

    #!/bin/sh
    
    set -e
    
    if [ ! -f "${DOCUMENT_ROOT}${PATH_INFO}" ]; then
        echo "Status: 404"
        echo
        exit
    fi
    
    echo "Status: 200"
    echo "Content-Type: text/html"
    echo
    
    echo ""
    markdown "${DOCUMENT_ROOT}${PATH_INFO}"
    echo ""

    I don’t like suffixes in url

    Way 1: Removing CGI script’s suffix

    Way 2: do rewriting

    Way 3: cgi pass

    How can I response status other than 200

    #!/bin/sh
    
    echo "Status: 404"
    echo "Content-Type: text/plain"
    echo
    
    echo "Welcome to the void"

    How can I response a redirection

    #!/bin/sh
    
    echo "Status: 302"
    echo "Location: https://theuselessweb.com"
    echo

    How can I get http request body

    You can read the request body from stdin. If you’re using shell, cat can
    quickly save request body to a file.

    How can send file to the client

    For small files, you can write file to stdout directly.

    For large files, it’s much better to send a 302 response. Because CGI response
    is streaming, protocol cannot easily handle caching, chunked downloads, or
    resume support.

    I want to write CGI with python, ruby, perl, C, C++…

    Go for it. Nginx-cgi don’t care what language you use. Just grabs information
    from environment var, and read request body from stdin, and write output to
    stdout.

    Manual

    Options

    cgi or cgi pass [script_args...]

    Enable or disable cgi module on giving location block.

    If you specify on here, the plugin will work in traditional mode. It parses
    the request uri first, and then locate the script under document root directory
    with request uri. After all it splits request uri to SCRIPT_NAME and
    PATH_INFO. This is good if you have an old CGI project or you want to strictly
    follow rfc3875.

    I also provided a nginx style syntax here. If you specify cgi pass here, the
    plugin will skip the step to locate the CGI script. It uses the the value you
    provided directly. You can references nginx variables in the second argument,
    eg: cgi pass $document_root$uri. The aboving example do something similar to
    rfc3875, but not equal. In this form, request uri will be assigned to
    PATH_INFO directly. And SCRIPT_NAME will be empty. This form is really good
    for dynamic content generating. It gets around the complex and unnecessary uri
    re-writing.

    Additionally, the second form also provides you the ability to pass additional
    args to script, eg: cgi pass my_script.sh $uri. With this, you can totally
    avoid confusing rfc3875 environment variables.

    If you specify off here, the plugin will be disabled.

    Default: off

    cgi_pass

    Alias of cgi pass .

    cgi_interpreter [interpreter] [args...]

    Set interpreter and interpreter args for cgi script.

    When this option is not empty, cgi script will be run with giving interpreter.
    Otherwise, script will be executed directly.

    This option can contains nginx variables, see
    https://nginx.org/en/docs/varindex.html for more details.

    This option is extremely useful in a lot of senarios, for example:

    • run CGI scripts missing x-perm
    • do sudo before executing CGI script
    • wrap general binary as CGI script
    • filter CGI script output
    • …

    Default: empty

    cgi_working_dir

    Set the working directory of CGI script.

    If this value is set to empty, CGI scripts will inherit nginx’ working
    directory.

    If this value is set to an non-empty string, the CGI script will be launched
    with giving working directory.

    The action of changing working directory may failed. For example, giving
    directory doesn’t exist, no perm or name too long. In this case, script will
    failed to execute.

    This option doesn’t change the way to find interpreter or script (if they are
    specified with related path, they are always related to nginx’ working
    directory).

    This option can contain nginx variable. Althrough I don’t know what use this is.
    Maybe you can setup different working dir for different server_name by this.

    Default: empty

    cgi_body_only

    A standard CGI script should output two parts: header and body. And an empty
    line to split those two parts.

    If you want to simply run a normal program as CGI program. You can turn this on.

    Once this option is enabled, all outout will be treated as response body, and be
    sent to the client.

    Default: off

    cgi_path

    Change cgi script PATH environment variable.

    Default: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

    cgi_strict

    Enable or disable strict mode.

    When strict mode turns on, bad cgi header will cause 500 error. When strict mode
    turns off, bad cgi header be forward as it is.

    Default: on

    cgi_set_var

    Add and pass extra environment variables to CGI script. The first argument of
    this command is the name of environment variable. It should contains only
    alphabets, numbers and underscore, and doesn’t start with number. The second
    argument of this command is the value express of the var. It can contains nginx
    variables, see
    https://nginx.org/en/docs/varindex.html for more details.

    This option can appears more than 1 time to set multiple variables. If more than
    one option set the same var, then the last one works. These directives are
    inherited from the previous configuration level if and only if there’s no
    cgi_set_var directives defined on the current level.

    This option can also be used to override standard CGI vars. This may be useful
    in some case, for example hacking old CGI script or simulate standard vars that
    are not supported by this plugin now (Such as PATH_TRANSLATED,
    REMOTE_IDENT). But it’s not recommanded, it may introduce confusing issues to
    your system.

    cgi_stderr

    Redirect cgi stderr to giving file.

    By default, nginx-cgi grab cgi script’s stderr output and dump it to nginx log.
    But this action is somewhat expensive, because it need to create an extra
    connection to listen stderr output. If you want to avoid this, you can use this
    option to redirect cgi script’s stderr output to a file. Or you can even discard
    all stderr output by redirect to /dev/null. Also you can use this to redirect
    all stderr output to nginx’s stderr by set it as /dev/stderr.

    cgi_rdns [required]

    Enable or disable reverse dns.

    off: disable rdns feature.

    on: Do reverse dns before launching cgi script, and pass rdns result to cgi
    script via REMOTE_HOST environment variable.

    double: After reverse dns, do a forward dns again to check the rdns result. if
    result matches, pass result as REMOTE_HOST.

    required: If rdns failed, 403, 503 or 500 returns to the client. Depends on
    the failure reason of rdns.

    If you turns this option on, you need to setup a resolver in nginx too.
    Otherwise you will get an error of no resolver defined to resolve.

    author notes: do not enable this option, it will makes every request slower.
    this feature can be easily implemented by dig -x or nslookup in script. the
    only reason I implement this is just to make the module fully compliant with the
    rfc3875 standard.

    cgi_timeout [t2]

    Send TERM/KILL signals to the CGI process if it runs too long.

    If both t1 and t2 equal to 0. Timeout feature is disabled.

    If t1 or t2 doesn’t equal to 0. A TERM or KILL signal will be sent to
    the process after timeout.

    If both t1 and t2 not zero. Send TERM at t1 timestamp first. And send
    KILL again at t1+t2 timestamp (if process still alive at that timestamp).

    If t2 doesn’t present, it treated as 0.

    Default: 0 0

    Standard Environment Variables

    Nginx-cgi implemented almost all rfc3875 standard variables. If they cannot
    cover all of your usage, you can add your own variable by cgi_set_var. Also
    those variables can be overrided by cgi_set_var if you really want to.

    • AUTH_TYPE, REMOTE_USER (rfc3875 standard)

    If cgi script is behind an authorization module (such as
    ngx_http_auth_basic_module), and the authorization is succeed, the value is
    set to auth type (such as Basic) and authorized user.

    If no authorization module enabled, no matter client passes autoriazation header
    or not. Those 2 fields are not present.

    Authorization header is not visible in cgi script for security reason. If you
    really want to do authorization in CGI script, try cgi_set_var.

    • CONTENT_LENGTH, CONTENT_TYPE (rfc3875 standard)

    Same to request header’s Content-Length and Content-Type.

    • GATEWAY_INTERFACE (rfc3875 standard)

    Always be CGI/1.1 in this plugin.

    • PATH_INFO (rfc3875 standard)

    Let’s say if you have a script under /cgi-bin/hello.sh, and you access
    http://127.0.0.1/cgi-bin/hello.sh/somewhat.

    Then PATH_INFO contains the string /somewhat.

    Combination with url rewrite or cgi pass, this variable can be used for
    dynamic content generating.

    • PATH_TRANSLATED (rfc3875 standard)

    Note: this option is not implemented strictly compliant with rfc3875.
    Please avoid this, if you are writing new CGI script.

    This is related to PATH_INFO.

    Let’s say if you have a script under /cgi-bin/hello.sh, and you access
    http://127.0.0.1/cgi-bin/hello.sh/somewhat.

    The standard says, the server should try again with http://127.0.0.1/somewhat,
    and found out where the uri should mapped to.

    For technical reason, I just construct this variable by document root and
    PATH_INFO.

    The behaviour may be changed in future version.

    • QUERY_STRING (rfc3875 standard)

    Contains the query string of the request. For example, if you are accessing
    http://127.0.0.1/cgi-bin/hello.sh?a=1&b=2, QUERY_STRING will contains
    a=1&b=2.

    • REMOTE_ADDR, (rfc3875 standard)

    Client ip address.

    • REMOTE_HOST (rfc3875 standard)

    Client host name. Only available if cgi_rdns is turns on.

    If cgi_rdns is on, nginx-cgi will do a reverse DNS, and find a domain matches
    REMOTE_ADDR. If any found, it will be set to REMOTE_HOST.

    If cgi_rdns is double, after the RDNS, nginx-cgi will do a forward DNS again.
    REMOTE_HOST will only be set if the forward DNS result matches the original
    address.

    See cgi_rdns for more information.

    • REMOTE_IDENT (rfc3875 standard)

    Nginx-cgi plugin doesn’t support this for security reason.

    • REQUEST_METHOD (rfc3875 standard)

    Request method of the request, for example: GET, POST…

    • SCRIPT_NAME (rfc3875 standard)

    Path to current script. Normally, you don’t need this. It doesn’t contains the
    full path. See SCRIPT_FILENAME.

    The only reason to use this is construct the URI after rewriting. You can use
    SCRIPT_NAME + PATH_INFO to get the URI after rewriting.

    • SERVER_NAME (rfc3875 standard)

    Server name, normally it equals to Host header without port part. If Host
    header doesn’t appear in the request (HTTP/1.0) or contains invalid value, then
    this value is set to the reflect server ip address. If the ip address is an ipv6
    address, it will be quoted with bracket like [::1].

    • SERVER_PORT (rfc3875 standard)

    Server listening port, such as 80, 443…

    • SERVER_PROTOCOL (rfc3875 standard)

    The protocol used between client and server. Such as HTTP/1.0, HTTP/1.1…

    • SERVER_SOFTWARE (rfc3875 standard)

    Contains a string of nginx and version, such as nginx/1.27.4.

    • X_ (rfc3875 standard)

    All X- prefixed http request header will be convert to X_ variables. For
    example:

    If X-a: 123 appears in header, X_A will be set to 123.

    • HTTP_ (rfc3875 standard)

    All other http request header will be convert to HTTP_ variables, for example:

    If Accept: */* appears in header, HTTP_ACCEPT will be set to */*.

    • DOCUMENT_ROOT (non-standard, impled by apache2)

    Document root of current location block, see root stmt in nginx.

    • REMOTE_PORT (non-standard, impled by apache2)

    Client port number.

    • REQUEST_SCHEME (non-standard, impled by apache2)

    http or https.

    • REQUEST_URI (non-standard, impled by apache2)

    The raw uri before rewriting. If you want the URL after rewriting, try
    SCRIPT_NAME + PATH_INFO.

    Note: this variable doesn’t same to nginx varible $request_uri. You can find
    the document at https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html.

    • SCRIPT_FILENAME (non-standard, impled by apache2)

    The full path to the CGI script.

    • SERVER_ADDR (non-standard, impled by apache2)

    Server ip address. If the server has multiple ip addresses. The value of this
    variable can be different if requests came from different interfaces.

    Known Issues

    PATH_TRANSLATED impl not accurate

    By rfc3875, PATH_TRANSLATED should point to the file that as if $PATH_INFO
    accessed as uri. But that’s really hard to impl on nginx, it need re-trigger
    nginx’s location process. And those functions are private, cannot access by
    plugin directly. The another way to impl it is starting a sub-request, but it’s
    too expensive, and this var is really rearly used. It’s really not worth to do
    it. So I simply construct this var by document root and path_info vars.

    RDNS impl doesn’t access /etc/hosts

    Nginx’s resolver impl doesn’t access /etc/hosts. I don’t want to impl an extra
    resolver in plugin. So I just ignore this problem.

    Reference

    rfc3875

    https://datatracker.ietf.org/doc/html/rfc3875

    nginx

    https://nginx.org/en/docs/dev/development_guide.html
    https://hg.nginx.org/nginx-tests

    Hop-by-hop headers

    https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1

    CGI environments

    https://datatracker.ietf.org/doc/html/rfc3875#section-4.1

    Apache CGI

    https://httpd.apache.org/docs/2.4/howto/cgi.html

    Lighttpd CGI

    https://redmine.lighttpd.net/projects/lighttpd/wiki/Mod_cgi

    License

    2-clause BSD license

    BMI Calculator – Check your Body Mass Index for free!

    Share. Facebook Twitter Pinterest LinkedIn Reddit WhatsApp Telegram Email
    Previous ArticleThe Theoretical Limitations of Embedding-Based Retrieval
    Next Article Why Romania excels in international Olympiads
    TechAiVerse
    • Website

    Jonathan is a tech enthusiast and the mind behind Tech AI Verse. With a passion for artificial intelligence, consumer tech, and emerging innovations, he deliver clear, insightful content to keep readers informed. From cutting-edge gadgets to AI advancements and cryptocurrency trends, Jonathan breaks down complex topics to make technology accessible to all.

    Related Posts

    How to turn a USB flash drive into a portable games console

    August 31, 2025

    Don’t buy a PCIe 5.0 SSD unless you say ‘Yes’ to these 3 questions

    August 31, 2025

    Windows Recall is too risky for your PC. I can’t recommend it

    August 31, 2025
    Leave A Reply Cancel Reply

    Top Posts

    Ping, You’ve Got Whale: AI detection system alerts ships of whales in their path

    April 22, 2025168 Views

    6.7 Cummins Lifter Failure: What Years Are Affected (And Possible Fixes)

    April 14, 202548 Views

    New Akira ransomware decryptor cracks encryptions keys using GPUs

    March 16, 202530 Views

    Is Libby Compatible With Kobo E-Readers?

    March 31, 202528 Views
    Don't Miss
    Technology August 31, 2025

    How to turn a USB flash drive into a portable games console

    How to turn a USB flash drive into a portable games console Image: Chris Hoffman…

    Don’t buy a PCIe 5.0 SSD unless you say ‘Yes’ to these 3 questions

    Windows Recall is too risky for your PC. I can’t recommend it

    Alienware’s 1440p ultrawide OLED gaming monitor is a huge 50% off

    Stay In Touch
    • Facebook
    • Twitter
    • Pinterest
    • Instagram
    • YouTube
    • Vimeo

    Subscribe to Updates

    Get the latest creative news from SmartMag about art & design.

    About Us
    About Us

    Welcome to Tech AI Verse, your go-to destination for everything technology! We bring you the latest news, trends, and insights from the ever-evolving world of tech. Our coverage spans across global technology industry updates, artificial intelligence advancements, machine learning ethics, and automation innovations. Stay connected with us as we explore the limitless possibilities of technology!

    Facebook X (Twitter) Pinterest YouTube WhatsApp
    Our Picks

    How to turn a USB flash drive into a portable games console

    August 31, 20252 Views

    Don’t buy a PCIe 5.0 SSD unless you say ‘Yes’ to these 3 questions

    August 31, 20250 Views

    Windows Recall is too risky for your PC. I can’t recommend it

    August 31, 20252 Views
    Most Popular

    Xiaomi 15 Ultra Officially Launched in China, Malaysia launch to follow after global event

    March 12, 20250 Views

    Apple thinks people won’t use MagSafe on iPhone 16e

    March 12, 20250 Views

    French Apex Legends voice cast refuses contracts over “unacceptable” AI clause

    March 12, 20250 Views
    © 2025 TechAiVerse. Designed by Divya Tech.
    • Home
    • About Us
    • Contact Us
    • Privacy Policy
    • Terms & Conditions

    Type above and press Enter to search. Press Esc to cancel.