Ahrens Insights

installcgi

📅 October 28, 2026📖 Verified Publication
Installing CGI Binaries on Linux: A Comprehensive Guide to /var/www/cgi-bin

Key Takeaways: Installing CGI programs requires more than simple file placement. The three critical factors for successful deployment are: 1) Correct file system permissions (executable bit + write protection), 2) Web server configuration to explicitly allow execution in the target directory, and 3) Operating at non-root privileges with `suExec` or `mod_suexec` enabled for security. A common failure point is missing the `` directive in Apache or the `try_files` fallback in Nginx.

Understanding the CGI Execution Path

Common Gateway Interface (CGI) scripts are external programs that communicate with a web server using a standard protocol. The "install" process differs fundamentally from static content deployment. Unlike an `.html` file, the server must spawn a new process, set environment variables (`REQUEST_METHOD`, `QUERY_STRING`), and pipe `stdin`/`stdout` to the binary or script. This architectural overhead dictates a specific installation structure.

Standard Directory Conventions

While the physical location is configurable, standard convention places executables in /var/www/cgi-bin (Apache) or /usr/lib/cgi-bin (system-wide). The web server's document root must be configured to map the URL alias /cgi-bin/ to this directory. If your web root is /var/www/html, creating /var/www/html/cgi-bin is often the simplest path for user-generated or application-specific scripts.

Installation Method Comparison: Apache vs. Nginx

The implementation strategy varies significantly between pre-fork/worker model servers and event-driven asynchronous servers. The following table compares the installation and execution mechanisms for the two dominant web servers.

Feature Apache (mod_cgi) Nginx (Fcgi-Wrapper or Proxy)
Native Support Yes, first-class module (mod_cgi / mod_cgid) No native CGI. Requires external handler (fcgiwrap) or reverse proxying to FastCGI
Execution Model Spawns a child process per request (MPM dependent) Spawns fcgiwrap process which speaks FastCGI to the binary
Configuration Location httpd.conf or 000-defaults.conf nginx.conf or site-specific .conf file in conf.d/
Script Handler ScriptAlias /cgi-bin/ /var/www/cgi-bin/ fastcgi_pass unix:/run/fcgiwrap.sock;
Performance Impact High overhead for high concurrency due to process forking Low overhead, reuses worker connections; better for static+dynamic mixed sites
Best Use Case Simplicity, compatibility with legacy `.cgi`/`.sh`/`.pl` files High-traffic sites, containerized environments, modern FastCGI apps

Step-by-Step Installation & Configuration

Prerequisites and Permissions

Before placing any file in the CGI directory, verify the operating system user account. The web server typically runs as www-data (Debian/Ubuntu) or apache (RHEL/CentOS). The CGI binary must not be owned by www-data to prevent the web server from rewriting its own source code, a common attack vector.

  • Owner: The application developer or root.
  • Group: www-data (optional, for shared access).
  • Permissions: 755 (rwxr-xr-x) for executables. The file must be readable by the web server but not writable by it.

# Example: Securing a Perl script
chown root:www-data /var/www/cgi-bin/hello.cgi
chmod 755 /var/www/cgi-bin/hello.cgi

Apache Configuration

Edit your Apache virtual host configuration (e.g., /etc/apache2/sites-available/000-default.conf). You must map the URL to the physical directory and explicitly declare which file extensions are treated as scripts.

<Directory /var/www/cgi-bin>
    Options +ExecCGI
    AllowOverride None
    Require all granted
</Directory>

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

# Explicitly declare allowed extensions
<FilesMatch "\.(cgi|pl|sh)$">
    SetHandler cgi-script
</FilesMatch>

Reload Apache with sudo systemctl reload apache2.

Nginx Configuration with FCGI Wrapper

Native CGI support in Nginx was deprecated and removed. The standard installation method now involves installing fcgiwrap from your package manager and configuring Nginx to proxy CGI requests through it.

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    location /cgi-bin/ {
        root /var/www/html;
        fastcgi_pass unix:/run/fcgiwrap.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Security Hardening Checklist

Installing CGI is a significant privilege boundary. The following checklist is mandatory for production environments to mitigate local file inclusion and privilege escalation risks.

  • [ ] Disable PathInfo if not required: Ensure AcceptPathInfo is set to Off in Apache unless explicitly needed for specific frameworks.
  • [ ] Principle of Least Privilege: Run the web server as a non-root user. The CGI process should inherit this restricted context.
  • [ ] Output Sanitization: Verify that your CGI script does not inject user input directly into HTML or shell commands without escaping. Use parameterized queries for database interactions.
  • [ ] Chroot Jails: For high-security requirements, consider placing the CGI binary in a chroot jail (e.g., using mod_security or dedicated containers) to limit filesystem access.
  • [ ] Logging: Enable verbose logging for the CGI handler to monitor for unusual QUERY_STRING lengths or malformed POST bodies.

FAQ

Why does my CGI script return a 500 Internal Server Error in Apache?

A 500 error in CGI is almost exclusively caused by permission issues or a missing interpreter. The two primary causes are: 1) The script lacks the executable bit (chmod +x), or 2) The shebang line (e.g., #!/usr/bin/perl) points to an interpreter path that does not exist on the server. Check the Apache error log (/var/log/apache2/error.log) to distinguish between a "Permission denied" (chmod) and a "No such file or directory" (missing shebang path).

Can I install CGI binaries that require root access?

No. Modern web servers and operating systems strictly enforce that CGI processes must run as the unprivileged web server user (www-data). If a binary requires root privileges to function, it cannot be deployed via standard CGI. Instead, you must refactor the application to use a FastCGI pool running under systemd with specific capabilities (Capability directives) or split the application into a user-facing part and a privileged backend service communicating over localhost sockets.

What is the difference between CGI and FastCGI installation?

Traditional CGI spawns a new process for every single HTTP request, which is resource-intensive. FastCGI requires the installation of a persistent process manager (like spawn-fcgi or a systemd unit) that keeps the application in memory. Installing a FastCGI application involves configuring the