The RequestBite Slingshot Proxy is a highly performant REST API written in Go that can proxy HTTP requests for webapps and be used to read files and browse directories on the machine on which it is installed.
It is used as a proxy server by Slingshot as it's almost impossible for webapps to directly make HTTP requests to arbitrary HTTP resources because of CORS restrictions. If installed locally (with necessary config options enabled), Slingshot will also do local file browsing in certain situations (e.g. when importing or updating files).
The RequestBite Slingshot Proxy is hosted at p.requestbite.com but nothing prevents you from running it yourself. Doing so means you won't proxy any requests via our servers (unless you want to) and it means you can access resources normally not reachable over the public Internet, such as those on your machine, on your local network, or on any VPN you might be connected to.
Install the latest release on MacOS or Linux like so:
curl -fsSL https://raw.githubusercontent.com/requestbite/proxy/main/install.sh | bashThe binary will be installed to ~/.local/bin by default.
To install the latest release to a custom directory, do like so:
curl -fsSL https://raw.githubusercontent.com/requestbite/proxy/main/install.sh | bash -s -- --prefix=$HOME/binTo install a specific version (in this example, version 0.3.1), do like so:
curl -fsSL https://raw.githubusercontent.com/requestbite/proxy/main/install.sh | bash -s -- --version=0.3.1Download pre-built binaries from GitHub Releases.
Supported Platforms:
| OS | Architecture | Binary Name |
|---|---|---|
| macOS | Intel (x86-64) | rb-proxy-*-darwin-amd64.tar.gz |
| macOS | Apple Silicon (ARM64) | rb-proxy-*-darwin-arm64.tar.gz |
| Linux | x86-64 | rb-proxy-*-linux-amd64.tar.gz |
| Windows | x86-64 | rb-proxy-*-windows-amd64.zip |
After downloading, extract the archive and move the binary to a directory in your PATH:
# macOS/Linux
tar -xzf rb-proxy-*.tar.gz
mv rb-proxy/rb-proxy ~/.local/bin/
# Make sure ~/.local/bin is in your PATH
export PATH="$HOME/.local/bin:$PATH"To build a Docker image of the RequestBite Slingshot Proxy, run:
docker build -t rb-proxy .This creates an image called rb-proxy:latest. By default this does not support
exposing local files and directories via the /file endpoint. To run the
RequestBite Slingshot Proxy in Docker, run:
docker run -d -p 7331:7331 rb-proxy:latestNow you can check the health of the proxy by running:
curl http://localhost:7331/healthRequires Go 1.19 or later:
# Clone the repository
git clone https://github.com/requestbite/proxy.git rb-proxy
cd rb-proxy
# Build using Makefile
make buildFor active development with hot reload (requires Air):
# Install Air (one-time setup)
go install github.com/air-verse/air@latest
# Run with hot reload (no arguments)
make dev
# Run with CLI arguments
make dev ARGS="--enable-local-files"
# Run with multiple arguments
make dev ARGS="--enable-local-files --port 9090"
# Show help
make dev ARGS="--help"The ARGS variable allows you to pass any CLI arguments to the proxy when using
make dev, making it easy to test different configurations during development.
# Start on default port 7331
rb-proxy
# Start on custom port
rb-proxy --port 8081
# Show version
rb-proxy --version
# Show help
rb-proxy --helpThe full API is documented in OpenAPI 3.1 format in
openapi.yaml and can be imported into Slingshot by clicking
this
link
(note however, that Slingshot itself uses the proxy - so it's essentially using
the proxy to call the proxy which is mostly prohibited - so it's easiest to
interact with the proxy from e.g. cURL).
Executes HTTP requests from JSON payload.
Request Body:
{
"method": "GET",
"url": "https://example.com/api",
"headers": [
"Content-Type: application/json",
"Authorization: Bearer token"
],
"body": "request body content",
"timeout": 30,
"followRedirects": true,
"path_params": {
":id": "123",
":category": "users"
}
}Response:
{
"success": true,
"response_status": 200,
"response_headers": {
"content-type": "application/json"
},
"response_data": "response body",
"response_size": "1.2 KB",
"response_time": "156.78 ms",
"content_type": "application/json",
"is_binary": false,
"cancelled": false
}Executes form-based HTTP requests.
Query Parameters:
url: Target URL (required)method: HTTP method (default: POST)timeout: Timeout in seconds (default: 60)followRedirects: Whether to follow redirects (default: true)contentType: Content type (application/x-www-form-urlencoded or multipart/form-data)headers: Comma-separated header list
Form Data: Standard form data in request body.
Serves local files from the filesystem. This endpoint is disabled by default
and must be explicitly enabled with the --enable-local-files flag for security
reasons.
Request Body:
{
"path": "/absolute/path/to/file.txt"
}Request Fields:
path: Absolute path to the file (required). Works with both Unix-style (/home/user/file.txt) and Windows-style (C:\Users\user\file.txt) paths.
Response:
- Success (200): Returns the raw file content with appropriate
Content-Typeheader based on file extension and content detection - Not Found (404): File doesn't exist or feature is disabled
- Error: JSON error response for invalid paths, directories, or access errors
Example:
# Enable local file serving
rb-proxy --enable-local-files
# Request a file
curl -X POST http://localhost:8080/file \
-H "Content-Type: application/json" \
-d '{"path": "/home/user/document.pdf"}'Supported Scenarios:
- Text files (
.txt,.json,.xml, etc.) - served with appropriate text MIME types - Images (
.png,.jpg,.gif, etc.) - served with image MIME types - Documents (
.pdf,.docx, etc.) - served with document MIME types - Binary files - served as
application/octet-stream
Error Responses:
When feature is disabled (404):
(Empty response body with 404 status)
File not found:
{
"success": false,
"error_type": "file_not_found",
"error_title": "File Not Found",
"error_message": "File not found: /path/to/file.txt"
}Lists files and directories in a specified path. This endpoint is disabled by
default and must be explicitly enabled with the --enable-local-files flag.
Request Body:
{
"path": "/home/user"
}For root directory, use null:
{
"path": null
}Response:
Returns a JSON array of directory entries sorted with directories first, then files, alphabetically within each group:
[
{
"name": "Documents",
"type": "directory"
},
{
"name": "Downloads",
"type": "directory"
},
{
"name": "file.txt",
"type": "file"
},
{
"name": "photo.jpg",
"type": "file"
}
]Platform Defaults:
When path is null, the endpoint returns the root directory for the platform:
- Unix/Linux/macOS:
/ - Windows:
C:\
Example:
# Enable local file serving
rb-proxy --enable-local-files
# List directory contents
curl -X POST http://localhost:8080/dir \
-H "Content-Type: application/json" \
-d '{"path": "/home/user/Documents"}'
# List root directory
curl -X POST http://localhost:8080/dir \
-H "Content-Type: application/json" \
-d '{"path": null}'Error Responses:
The /dir endpoint uses the same error response format as the /file endpoint:
When feature is disabled (404):
(Empty response body with 404 status)
Directory not found:
{
"success": false,
"error_type": "file_not_found",
"error_title": "File Not Found",
"error_message": "Directory not found: /path/to/dir"
}Path is not a directory:
{
"success": false,
"error_type": "file_access_error",
"error_title": "File Access Error",
"error_message": "Path is not a directory: /path/to/file.txt"
}Run the functionality tests:
./tests.shThis tests the main functionality of the proxy.
Run the proxy in any of the two following supported modes:
Run the proxy as a service and configure nginx to proxy to it:
upstream proxy_backend {
server localhost:7331;
}
location /proxy/ {
proxy_pass http://proxy_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}CLI version of proxy.
./proxy-go --port 8080Command-line flags:
--port: Server port (default: 8080)--enable-local-files: Enable local file serving via/fileendpoint (default: false, disabled for security)--help: Show help information--version: Show version information
Example:
# Run with default settings
rb-proxy
# Run on custom port with local file serving enabled
rb-proxy -port 3000 -enable-local-filesThe proxy implements multiple strategies to prevent infinite request loops:
Incoming requests with User-Agent header containing rb-slingshot are blocked.
This prevents:
- Proxy calling itself
- Chained proxy instances
- Accidental infinite loops in self-hosted deployments
Requests targeting specific hostnames are blocked:
p.requestbite.comlocalhost- etc
Exception: Requests to /health endpoint are always allowed for health checks.
When a loop is detected, the proxy returns HTTP 508 Loop Detected with
error_type: "loop_detected".
Testing Loop Protection:
# This should return 508 Loop Detected
curl -X POST http://localhost:8080/proxy/request \
-H "Content-Type: application/json" \
-d '{
"method": "POST",
"url": "http://localhost:8080/proxy/request",
"body": "{\"method\":\"GET\",\"url\":\"https://example.com\"}"
}'The proxy returns standardized error responses:
url_validation_error: Invalid URL format or schemetimeout: Request exceeded specified timeoutconnection_error: Network connection failedredirect_not_followed: Redirect encountered butfollowRedirects: falserequest_format_error: Invalid JSON or missing required fieldsloop_detected: Request would create an infinite loop. Detected by:- User-Agent header matching
rb-slingshot(any version, any instance) - Target hostname in blocked list (p.requestbite.com, dev.p.requestbite.com)
- User-Agent header matching
file_not_found: Requested file does not exist (404)file_access_error: Cannot access file (permissions, is directory, etc.)feature_disabled: Attempted to use disabled feature
Health check endpoint available at /health:
curl http://localhost:8080/healthReturns:
{
"status": "ok",
"user-agent": "rb-slingshot/0.1.0 (https://requestbite.com/slingshot)",
"version": "0.1.0"
}See details about the license in LICENSE.