Deploying Ring Web Applications to Shared Hosting
Chapter Author: Youssef Saeed
While modern application deployment often involves containers, many hosting environments—especially traditional shared hosting panels like cPanel and Plesk—do not allow running persistent background processes. For these platforms, the classic CGI (Common Gateway Interface) model remains the perfect and most compatible solution.
This tutorial guides you through deploying Ring applications as CGI scripts. We will use a powerful, secure CGI wrapper script that makes the process robust and reliable across different hosting environments.
1. Introduction: The CGI Model
CGI is a standard protocol that allows a web server (like Apache or Nginx) to execute external scripts to generate web pages dynamically.
Docker / Modern Server Model |
Classic CGI Model |
---|---|
Your Ring app is a long-running server using |
Your Ring app is a simple script that runs and exits on each request. |
The web server acts as a Reverse Proxy, forwarding traffic. |
The web server acts as an Executor, running your script directly. |
Requires |
Works on virtually any shared hosting plan with minimal permissions. |
Deployment is typically done via |
Deployment is done by uploading files (e.g., via FTP/SFTP). |
The CGI model is incredibly portable and has been a workhorse of the web for decades, making it ideal for environments with limited control.
2. Prerequisites
Access to a web hosting environment (either a shared hosting panel or a cloud VM with
sudo
access).A way to upload files (e.g., a File Manager in your control panel, or an SFTP client like FileZilla).
A basic understanding of Ring syntax.
Crucially, the Ring language itself must be uploaded to your hosting environment.
3. Creating a CGI-Compatible Ring Script
A CGI script is simpler than a full server application. It does not use httplib
. Instead, it follows a simple contract:
Print a
Content-Type
header (e.g.,Content-Type: text/html
).Print a single blank line.
Print the HTML body content.
Exit.
Create a file named hello.ring
with the following content.
# A minimal CGI script
See "Content-Type: text/html" + nl + nl
See "<html>"
See "<head><title>CGI Test</title></head>"
See "<body>"
See "<h1>Hello from a Ring CGI Script!</h1>"
See "<p>This page was generated by Ring running as a CGI application.</p>"
See "</body>"
See "</html>"
4. The Universal Ring CGI Wrapper
To make our Ring scripts work reliably and securely, we will use a “wrapper.” This is a Bash script that the web server executes. Its job is to correctly prepare the environment and then run our .ring
file.
This wrapper cleverly handles different hosting configurations, sets up necessary library paths, and includes crucial security checks. Create a file named ring.cgi
with the content below.
#!/bin/bash
# ==============================================================================
# Universal Ring CGI Wrapper
#
# A robust CGI front controller for executing .ring files on a web server.
#
# How it works:
# 1. The web server (via .htaccess) calls this script for any .ring file request.
# 2. The script determines the correct Ring installation path and web root.
# 3. It sets the LD_LIBRARY_PATH so Ring's shared libraries can be found.
# 4. It performs security checks to prevent path traversal attacks.
# 5. It executes the requested .ring script using the Ring compiler in CGI mode.
# ==============================================================================
# --- Configuration ----------------------------------------------------
# If the HOME environment variable is not set (common in some CGI environments),
# this script attempts to deduce it from the current working directory (PWD).
if [ -z "$HOME" ]; then
# Guess home directory for various hosting panels.
# Plesk: /var/www/vhosts/domain.com/httpdocs/cgi-bin
# or /home/domain.com/httpdocs/cgi-bin
# cPanel/DirectAdmin: /home/username/public_html/cgi-bin
# KeyHelp: /home/users/username/www/cgi-bin
# ispManager: /var/www/username/data/www/domain/cgi-bin
if [[ "$PWD" == /var/www/vhosts/* ]]; then
HOME_DIR_GUESS="${PWD%/httpdocs*}"
elif [[ "$PWD" == /home/users/* ]]; then
HOME_DIR_GUESS="${PWD%/www*}"
elif [[ "$PWD" == /home/*/public_html* ]]; then
HOME_DIR_GUESS="${PWD%/public_html*}"
elif [[ "$PWD" == /home/*/httpdocs* ]]; then
HOME_DIR_GUESS="${PWD%/httpdocs*}"
elif [[ "$PWD" == /var/www/*/data/* ]]; then
HOME_DIR_GUESS="${PWD%%/data/*}/data"
else
# Fallback to the current directory if no pattern matches.
HOME_DIR_GUESS="$PWD"
fi
RING_DIR="$HOME_DIR_GUESS/ring"
else
RING_DIR="$HOME/ring"
fi
# Full path to the Ring executable.
RING_EXECUTABLE="$RING_DIR/bin/ring"
# WEB_ROOT: Absolute path to your site's document root.
# The script will try to guess this by removing /cgi-bin from the end of the path.
# You can override this by setting a RING_WEB_ROOT environment variable.
WEB_ROOT_GUESS="${PWD%/cgi-bin*}"
export RING_WEB_ROOT="${RING_WEB_ROOT:-$WEB_ROOT_GUESS}"
# Ensure the dynamic linker can find Ring's shared libraries.
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$RING_DIR/lib"
# --- Main Script Logic ------------------------------------------------
# The web server passes the full file path of the requested .ring script
# in the PATH_TRANSLATED environment variable.
TARGET_RING_SCRIPT="$PATH_TRANSLATED"
# Check 1: Ensure the target script exists.
if [ ! -f "$TARGET_RING_SCRIPT" ]; then
echo "Content-Type: text/html"
echo ""
echo "<h1>404 Not Found</h1>"
echo "<p>The requested Ring script could not be found.</p>"
exit 0
fi
# Security Check: Prevent path traversal attacks.
# Ensure the canonical path of the target script is within the web root.
REAL_TARGET_PATH=$(realpath -s "$TARGET_RING_SCRIPT")
if [[ "$REAL_TARGET_PATH" != "$RING_WEB_ROOT"* ]]; then
echo "Content-Type: text/html"
echo ""
echo "<h1>403 Forbidden</h1>"
echo "<p>Access to the requested resource is not allowed.</p>"
exit 0
fi
# Check 2: Ensure the Ring executable is found and has execute permissions.
if [ ! -x "$RING_EXECUTABLE" ]; then
echo "Content-Type: text/html"
echo ""
echo "<h1>500 Server Configuration Error</h1>"
echo "<p>The Ring Compiler/VM could not be found or is not executable. Check that the 'ring' folder was uploaded to your home directory.</p>"
exit 0
fi
# Change to the script's directory so file operations are relative to it.
pushd "$(dirname "$TARGET_RING_SCRIPT")" > /dev/null
# Execute the Ring script in CGI mode.
# The Ring script is responsible for printing all headers and content.
"$RING_EXECUTABLE" -cgi "$TARGET_RING_SCRIPT"
# Return to the original directory.
popd > /dev/null
exit 0
5. Deployment Scenarios
Choose the path that matches your hosting environment.
—
Path A: Shared Hosting with .htaccess
(Apache/LiteSpeed)
This is the most common scenario. It relies on a .htaccess
file to tell the web server how to handle .ring
files.
Step 1: Upload the Ring Language
Download the Ring release for Linux from the official website.
On your local machine, extract the
ring
folder from the archive.Using an SFTP client or your hosting panel’s File Manager, upload the entire
ring
folder to your home directory (e.g.,/home/youruser
). The final structure must be/home/youruser/ring
.
Step 2: Upload and Configure the CGI Wrapper
Using the File Manager, navigate to your web root (usually
public_html
,httpdocs
, orwww
).If it doesn’t exist, create a folder named
cgi-bin
.Upload the
ring.cgi
script you created earlier into thiscgi-bin
folder.Set its permissions to
755
(rwx r-x r-x). This is crucial to make it executable. You can typically do this by right-clicking the file in the File Manager and choosing “Change Permissions.”
Step 3: Create the .htaccess
File
In your web root (
public_html
,httpdocs
, etc.), create a new file named.htaccess
.Add the following content. This tells the web server to use our wrapper script for any file ending in
.ring
.# Allow CGI scripts to be executed from this directory. Options +ExecCGI # Define a custom handler named 'ring-script' for all .ring files. AddHandler ring-script .ring # Specify that our wrapper script should execute files for the 'ring-script' handler. # The path should be relative to the web root. Action ring-script /cgi-bin/ring.cgi
Step 4: Upload and Test Your Ring Application
Upload your
hello.ring
file to your web root.In your browser, navigate to
http://your-domain.com/hello.ring
.
If everything is configured correctly, you should see the “Hello from a Ring CGI Script!” message.
—
Path B: Cloud VM with Nginx & FastCGI
If you have sudo
access on a VM and use Nginx, fcgiwrap
is the standard, high-performance way to run CGI scripts.
Step 1: Install Dependencies
SSH into your VM and install Nginx and the FastCGI wrapper.
sudo apt update
sudo apt install nginx fcgiwrap
Step 2: Enable and Start Services
Ensure both services start on boot and are running now.
sudo systemctl enable --now nginx
sudo systemctl enable --now fcgiwrap
Step 3: Install Ring in a System Location
Upload or move the
ring
folder to/opt/
. The final location must be/opt/ring
.# If already uploaded to your home directory: sudo mv ~/ring /opt/
Give the web server user (
www-data
) ownership and permissions.sudo chown -R www-data:www-data /opt/ring sudo chmod -R 755 /opt/ring
Step 4: Make the Ring Executable System-Wide
This allows scripts to find the ring
command without a full path.
cd /opt/ring/bin
sudo bash install.sh
Step 5: Create a Directly Executable Ring Script
For this method, your script must have a “shebang” line pointing to the system-wide ring
executable. Create or edit hello.ring
to look like this:
#!/usr/bin/ring -cgi
# This script is now directly executable.
See "Content-Type: text/html" + nl + nl
See "<html>"
See "<body>"
See "<h1>Hello from Nginx and FastCGI!</h1>"
See "</body>"
See "</html>"
Step 6: Upload Script and Set Permissions
Upload
hello.ring
to your Nginx web root (typically/var/www/html
).Make the script itself executable.
sudo chmod 755 /var/www/html/hello.ring
Step 7: Configure Nginx
Edit your Nginx site configuration (e.g., /etc/nginx/sites-available/default
) and add a location
block to handle .ring
files.
server {
listen 80;
server_name your-domain.com;
root /var/www/html;
index index.html;
# ... other configurations ...
# Pass .ring scripts to the fcgiwrap socket for execution.
location ~ \.ring$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Step 8: Restart and Test
Reload Nginx to apply the new configuration.
sudo systemctl reload nginx
Navigate to
http://your-domain.com/hello.ring
.
This method is more involved but is the standard, secure way to integrate CGI with Nginx.
6. Platform-Specific Guides for Shared Hosting
For Path A, here are specific tips for popular control panels.
A Crucial Note on Host-Level CGI Support
Before you begin, understand that the .htaccess
method depends on your hosting provider allowing CGI execution. Our .htaccess
file uses Options +ExecCGI
, but some hosts disable this for security.
Troubleshooting Tip: If you follow the steps for Path A and see a “500 Internal Server Error,” the most common cause is a server-level restriction.
Your first step should be to contact your hosting provider’s support team and ask them this specific question:
“Is CGI script execution enabled for my account, and am I allowed to use the
Options +ExecCGI
directive in my.htaccess
file?”
Confirming this first can save you hours of debugging.
—
cPanel
Tested & Confirmed: The
.htaccess
method works flawlessly on cPanel, which typically runs on an Apache or LiteSpeed web server.File Uploads: Use the File Manager tool. Your web root, the folder where website files are publicly accessible, is
public_html
. This folder is located inside your home directory, which has a full path like/home/username/public_html/
.Permissions: In File Manager, right-click on the
ring.cgi
file and select Change Permissions. Enter755
and save to make the script executable. By default, files often have0644
permissions and folders have0755
.Creating
.htaccess
: In File Manager, you can create a new file by clicking the + File button. To view existing.htaccess
files, which are hidden by default, go to the Settings menu in the top right and check the box for Show Hidden Files (dotfiles).CGI Status: CGI is generally enabled on cPanel servers. The server looks for a
cgi-sys/defaultwebpage.cgi
when a domain does not have a configured VirtualHost or is pointed to the wrong IP, indicating CGI is active. Including theOptions +ExecCGI
directive in your.htaccess
file can help ensure that CGI scripts are executed in your specific directory.
—
Plesk
Tested & Confirmed: The
.htaccess
method is effective on Plesk servers running Apache. If the server uses Nginx as a proxy, you must ensure Apache is also enabled and processes requests for.htaccess
to work.File Uploads: Use the Files or File Manager tab. Your web root is typically the
httpdocs
directory.Permissions: In the Files tab, click the three-dot menu next to the
ring.cgi
file and choose Change Permissions. To make the script executable, ensure the Execute permission is checked for the “Owner” and “Group” users..htaccess
Support: For.htaccess
files to work, go to your domain’s Apache & Nginx Settings and ensure that Apache is enabled and that requests are not being handled exclusively by Nginx.CGI Status: To enable CGI script execution, go to the domain’s Hosting Settings and ensure that CGI support is enabled. You may also need to configure the handler in the PHP Settings page by adding an
AddHandler
directive for.cgi
files in the “Additional Apache directives” section.
—
DirectAdmin
Tested & Confirmed: The
.htaccess
method works as expected, often on servers running LiteSpeed or Apache.File Uploads: Use the System Info & Files -> File Manager. Your web root directory is
public_html
.Permissions: In the File Manager, hover over the
ring.cgi
file and select Set Permissions (this may also be found by right-clicking). Set the permission code to755
to make it executable. By default, folders are often755
and files are644
.
—
KeyHelp
Tested & Confirmed: The
.htaccess
method works as described.File Uploads: Use the Files -> File Manager. Your web root is typically
/www
inside your user’s home directory (/home/users/username/www
).Permissions: Within the File Manager, you can change a file’s permissions. Click on the file and adjust the permissions as needed (e.g., from
0644
to0755
to make a script executable).CGI Status: CGI is not enabled by default for users. The server administrator must first enable the “Perl/CGI” permission for the specific user account. Once enabled,
.htaccess
directives can be used to manage CGI script execution. Thering.cgi
wrapper’s logic should function correctly within KeyHelp’s structure, provided the necessary permissions are set.
—
ispManager
Tested & Confirmed: The
.htaccess
method works as expected.File Uploads: Use the File Manager. Your web root is typically located at
/var/www/username/data/www/domain
, whereusername
is your account name anddomain
is your website’s domain name.Permissions: In the File Manager, select the
ring.cgi
file, click Edit, and then choose Attributes. Set the permissions to755
to make it executable. By default, files are often set to644
, which does not allow execution.CGI Status: CGI support is usually enabled by default in ispManager. However, if you encounter issues, check the server settings or contact your hosting provider to ensure that CGI execution is permitted for your account. The
ring.cgi
wrapper should work correctly within ispManager’s environment, provided the necessary permissions are set.
7. Security Considerations
Error Logging: For a production site, prevent detailed error messages from being shown to users. Modify the execution line in
ring.cgi
to redirect errors to a log file:# In ring.cgi, change the execution line to this: "$RING_EXECUTABLE" -cgi "$TARGET_RING_SCRIPT" 2>>/path/to/your/logs/ring_errors.log
Replace the path with a directory that is not inside your public web root.
File Permissions: Never set permissions to
777
. This allows anyone to modify your scripts. The755
permission is correct for executable scripts.Input Validation: Always sanitize and validate any user input (like query strings or form data) within your Ring scripts to prevent security vulnerabilities like SQL injection or Cross-Site Scripting (XSS).
8. Conclusion
You now know how to deploy Ring applications to a wide range of hosting environments using the highly compatible CGI model.
Path A (Shared Hosting) is perfect for getting started quickly on affordable hosting plans where you have limited server control.
Path B (Cloud VM) offers higher performance and a more standard setup for users who manage their own server with Nginx.
By mastering both server and CGI deployment methods, you gain the flexibility to run your Ring applications almost anywhere.