Table of Contents#
- Understanding the Components
- Installing FcgiWrap on Gentoo
- Configuring the Service
- Configuring Nginx
- Testing the Setup with Scripts
- Security Considerations
- Troubleshooting Common Issues
- Conclusion
- References
1. Understanding the Components#
Before we dive in, let's clarify the workflow:
- A user's browser requests a resource like
http://yourdomain.com/test.pl. - Nginx receives the request.
- Based on its configuration, Nginx recognizes the
.plextension and forwards the request to the FcgiWrap process via a FastCGI socket. - FcgiWrap receives the request, starts a new process for the Perl interpreter, and executes the
test.plscript. - The script's output (HTML, text, etc.) is sent back through FcgiWrap to Nginx.
- Nginx finally delivers the response to the user's browser.
This process is similar for Ruby (.rb) and Bash (.sh/.cgi) scripts.
2. Installing FcgiWrap on Gentoo#
Gentoo's package manager, Portage, makes installation straightforward. We will also install the necessary interpreters.
-
Update your system: It's always good practice to start with an updated system.
sudo emerge --sync sudo emerge -avuDN @world -
Install the required packages: We need
fcgiwrapand the language interpreters. If you already have some of these, Portage will skip them.sudo emerge -av www-servers/fcgiwrap dev-lang/perl dev-lang/ruby app-shells/bashwww-servers/fcgiwrap: The main FcgiWrap package.dev-lang/perl: The Perl interpreter.dev-lang/ruby: The Ruby interpreter.app-shells/bash: The Bash shell (almost certainly already installed).
Accept the proposed list of packages to install.
3. Configuring the Service#
FcgiWrap needs to run as a service so it's always available for Nginx. The configuration differs slightly depending on your init system.
3.1. OpenRC (Traditional Init)#
-
Create the service configuration directory and file:
sudo mkdir -p /etc/init.d sudo nano /etc/init.d/fcgiwrap -
Add the following content to the file. This script defines how to start, stop, and manage the
fcgiwrapdaemon. We'll configure it to use a Unix socket for communication.#!/sbin/openrc-run description="fcgiwrap - simple FastCGI wrapper for CGI scripts" command="/usr/sbin/fcgiwrap" command_args="-c 2 -s unix:/var/run/fcgiwrap/fcgiwrap.sock" command_user="nginx:nginx" command_background=true pidfile="/var/run/${RC_SVCNAME}.pid" depend() { need net nginx use mysql } start_pre() { checkpath --directory --owner nginx:nginx --mode 0755 /var/run/fcgiwrap }command_args:-c 2spawns 2 processes to handle requests. You can adjust this number based on your expected load.-s unix:/var/run/fcgiwrap/fcgiwrap.sockdefines the socket file location.command_user: It's crucial to run the service as the same user and group as your Nginx worker processes (commonlynginx:nginx). Check yournginx.conffile for theuserdirective.start_pre: Ensures the runtime directory exists with the correct permissions before starting the service.
-
Make the script executable and add it to the default runlevel:
sudo chmod +x /etc/init.d/fcgiwrap sudo rc-update add fcgiwrap default -
Start the service:
sudo /etc/init.d/fcgiwrap startYou can verify it's running with
sudo rc-statusor by checking if the socket file exists:ls -l /var/run/fcgiwrap/fcgiwrap.sock.
3.2. systemd#
-
Create a systemd service file:
sudo nano /etc/systemd/system/fcgiwrap.service -
Add the following content:
[Unit] Description=fcgiwrap - simple FastCGI wrapper for CGI scripts After=nginx.service [Service] Type=forking ExecStart=/usr/sbin/fcgiwrap -c 2 -s unix:/var/run/fcgiwrap/fcgiwrap.sock User=nginx Group=nginx RuntimeDirectory=fcgiwrap PIDFile=/var/run/fcgiwrap/fcgiwrap.pid [Install] WantedBy=multi-user.targetThe
RuntimeDirectorydirective will automatically create/var/run/fcgiwrapwith the correct permissions. -
Reload systemd, enable, and start the service:
sudo systemctl daemon-reload sudo systemctl enable fcgiwrap.service sudo systemctl start fcgiwrap.serviceVerify with
sudo systemctl status fcgiwrap.service.
4. Configuring Nginx#
Now we need to tell Nginx to pass requests for specific file extensions to the FcgiWrap socket.
4.1. Creating a FastCGI Parameter File#
It's efficient to create a common file for FastCGI parameters that can be included in multiple server blocks.
-
Create or edit the parameter file (a common location is
/etc/nginx/fastcgi_paramsor a new one like/etc/nginx/fcgiwrap_params).sudo nano /etc/nginx/fcgiwrap_params -
Add the standard FastCGI parameters:
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_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 REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 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; # PHP only, required if PHP was built with --enable-force-cgi-redirect # fastcgi_param REDIRECT_STATUS 200;
4.2. Setting Up a Virtual Host#
Within your Nginx server block configuration (e.g., /etc/nginx/sites-available/example.com), you need to add a location block for each language you want to support.
Here is an example configuration for a server block:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/yourdomain.com/public_html;
index index.html index.htm;
# Location block for Perl scripts (.pl, .cgi)
location ~ \.(pl|cgi)$ {
try_files $uri =404; # Ensure the script file exists
include /etc/nginx/fcgiwrap_params; # Include parameters
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock; # Socket from service
fastcgi_index index.pl;
}
# Location block for Ruby scripts (.rb)
location ~ \.rb$ {
try_files $uri =404;
include /etc/nginx/fcgiwrap_params;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
}
# Location block for Bash/CGI scripts (.sh, .cgi)
location ~ \.(sh|cgi)$ {
try_files $uri =404;
include /etc/nginx/fcgiwrap_params;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
}
}Important: After making changes to your Nginx configuration, always test it and then reload:
sudo nginx -t # Tests configuration for syntax errors
sudo nginx -s reload # OR, depending on your setup: sudo rc-service nginx reload5. Testing the Setup with Scripts#
Let's create simple test scripts to verify everything works. Ensure all scripts are executable by the Nginx user.
- Create a test directory and script:
sudo mkdir -p /var/www/yourdomain.com/public_html cd /var/www/yourdomain.com/public_html
5.1. Perl Script Test#
- Create
test.pl:sudo nano test.pl - Add this content:
#!/usr/bin/env perl print "Content-type: text/html\n\n"; print "<html><body>\n"; print "<h1>Hello from Perl!</h1>\n"; print "<p>This is a dynamic page generated by a Perl script.</p>\n"; print "</body></html>\n"; - Make it executable:
sudo chmod +x test.pl sudo chown nginx:nginx test.pl - Access it via your browser:
http://yourdomain.com/test.pl
5.2. Ruby Script Test#
- Create
test.rb:sudo nano test.rb - Add this content:
#!/usr/bin/env ruby puts "Content-type: text/html\n\n" puts "<html><body>" puts "<h1>Hello from Ruby!</h1>" puts "<p>This is a dynamic page generated by a Ruby script.</p>" puts "</body></html>" - Make it executable:
sudo chmod +x test.rb sudo chown nginx:nginx test.rb - Access it via your browser:
http://yourdomain.com/test.rb
5.3. Bash Script Test#
- Create
test.sh(ortest.cgi):sudo nano test.sh - Add this content:
#!/bin/bash echo "Content-type: text/html" echo "" echo "<html><body>" echo "<h1>Hello from Bash!</h1>" echo "<p>This is a dynamic page generated by a Bash script.</p>" echo "<p>The current date is: $(date)</p>" echo "</body></html>" - Make it executable:
sudo chmod +x test.sh sudo chown nginx:nginx test.sh - Access it via your browser:
http://yourdomain.com/test.sh
If you see the "Hello from ..." messages, congratulations! FcgiWrap is successfully installed and configured.
6. Security Considerations#
- File Permissions: Scripts must be owned and executable by the Nginx user, but should not be writable by it. This prevents code injection attacks.
- Script Validation: FcgiWrap will execute any script with the configured extension. Be extremely careful with user-uploaded content. It's better to have upload directories handled by a dedicated application (like PHP) rather than allowing direct execution.
- Limit Scope: Use the Nginx
locationblocks carefully. Don't use a broad regex like~ \.cgi$on a directory where users have write access unless you fully trust them. - SELinux/AppArmor: If you are using mandatory access control systems, you may need to create policies to allow Nginx to communicate with the FcgiWrap socket and for FcgiWrap to execute the interpreters.
7. Troubleshooting Common Issues#
- 502 Bad Gateway: This usually means Nginx cannot communicate with FcgiWrap.
- Is the
fcgiwrapservice running? Check its status. - Does the socket file (
/var/run/fcgiwrap/fcgiwrap.sock) exist and have correct permissions? The Nginx user must have read/write access. - Check the Nginx error log:
tail -f /var/log/nginx/error.log.
- Is the
- 403 Forbidden: This is a permission issue on the script file or one of the parent directories.
- Ensure the script is executable (
chmod +x). - Ensure the Nginx user has read (
r) and execute (x) permissions on the script and all parent directories leading up to it.
- Ensure the script is executable (
- Script Outputs Plain Text: The script is being executed, but the "Content-type" header is missing or incorrect. The browser is interpreting the output as plain text. Double-check that your script prints the header correctly (e.g.,
Content-type: text/html\n\n).
8. Conclusion#
You have successfully extended your Gentoo LEMP server beyond PHP. By installing and configuring FcgiWrap, you can now run dynamic web applications written in Perl, Ruby, and Bash. This setup provides a flexible and performant way to leverage the strengths of these languages within the robust Nginx environment. Remember to always prioritize security by carefully managing file permissions and being cautious about where and how you allow script execution.
9. References#
- FcgiWrap Official Repository: https://github.com/gnosek/fcgiwrap
- Nginx Documentation: https://nginx.org/en/docs/
- Gentoo Wiki (Nginx): https://wiki.gentoo.org/wiki/Nginx
- FastCGI Specification: https://fastcgi-archives.github.io/