Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

cdzombak/xrp

Repository files navigation

XRP - HTML/XML-aware Reverse Proxy

An HTML/XML-aware reverse proxy that allows modifying responses via plugins.

  • Plugin-based content modification - Go plugins modify HTML/XML responses
  • Redis caching - HTTP-compliant caching

Run: Quick Demo

cd examples
docker compose build && docker compose up

# In another terminal:
curl localhost:8080

Configuration

Create a config.json file based on deployment/config.example.json. This file configures the proxy server, content modification plugins, Redis cache, and certain policies. It contains the following top-level keys:

  • backend_url: The upstream URL to proxy requests to
  • cookie_denylist: If a request has a cookie whose name is listed in the denylist, the response is not cached in Redis
  • max_response_size_mb: The maximum response size to process via plugins and cache. If a response exceeds this size, it is streamed through to the client unchanged without plugin processing or caching.
  • mime_types: A list of MIME type configuration objects. These specify the plugins that will run on responses with the specified MIME type.
  • redis: Redis cache backend configuration.
  • health_port: Port for the health check endpoint server (default: 8081)

Health Check Endpoint

XRP provides a dedicated health check endpoint on a separate port (default: 8081) that can be used by container orchestrators, load balancers, and monitoring systems to determine when the proxy is ready to handle traffic.

  • GET /health on the health port:
    • Returns 102 Processing with body starting during startup (while plugins are loading)
    • Returns 200 OK with body ok when fully ready to serve traffic
    • Returns 102 Processing during configuration reloads

This endpoint is useful for:

  • Kubernetes readiness probes
  • Docker health checks
  • Load balancer health monitoring
  • Service mesh integration

Installation & Running

XRP is inserted between your web server and your application backend. So, instead of:

nginx  ->  app (e.g. Ghost)

You'll run:

nginx  ->  xrp ->  app

The exact details of how to implement this will vary depending on your setup.

You'll need to write your custom plugins depending on your needs. See the Plugin Development section below for more information. Build the plugin binaries for the exact XRP version your server is running. The resulting plugin .so binaries must be accessible to XRP and references in your configuration.

Docker

Docker images for xrp are available from GHCR. To ensure compatibility with your plugins, I recommend using the Docker image tagged with the exact XRP version your plugins were built for.

See the example Docker Compose file for details.

Debian/Ubuntu via apt repository

Install my Debian repository if you haven't already:

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://dist.cdzombak.net/keys/dist-cdzombak-net.gpg -o /etc/apt/keyrings/dist-cdzombak-net.gpg
sudo chmod 644 /etc/apt/keyrings/dist-cdzombak-net.gpg
sudo mkdir -p /etc/apt/sources.list.d
sudo curl -fsSL https://dist.cdzombak.net/cdzombak-oss.sources -o /etc/apt/sources.list.d/cdzombak-oss.sources
sudo chmod 644 /etc/apt/sources.list.d/cdzombak-oss.sources
sudo apt update

Then install xrp via apt:

sudo apt install xrp

Manual from release artifacts

Pre-built binaries for Linux on amd64/arm64 are downloadable from each GitHub Release. Debian packages are available as well.

Copy the appropriate binary for your architecture and run it using your tools of choice.

From source

To build binaries yourself, check out this repository and check out the Git tag for the xrp version you want to build. Then run:

make build/binaries

Copy the resulting binary for your architecture from dist/ and run it using your tools of choice.

systemd

If you've installed XRP binaries, whether from the apt repository, release artifacts, or from source, you can use the provided systemd unit file to run XRP as a service.

Plugin Development

Plugins must implement the Plugin interface and export struct values (not pointers):

package main

import (
    "context"
    "net/url"
    "golang.org/x/net/html"
    "github.com/beevik/etree"
    "github.com/cdzombak/xrp/pkg/xrpplugin"
)

type MyPlugin struct{}

func (p *MyPlugin) ProcessHTMLTree(ctx context.Context, url *url.URL, node *html.Node) error {
    // Modify HTML tree in place
    return nil
}

func (p *MyPlugin) ProcessXMLTree(ctx context.Context, url *url.URL, doc *etree.Document) error {
    // Modify XML document in place  
    return nil
}

// Export struct value (not pointer) for plugin system compatibility
var MyPluginInstance = MyPlugin{}

Development Options

Local development (fast, uses current dependencies):

go build -buildmode=plugin -o plugin.so plugin.go

Production builds (guaranteed compatibility):

# Use XRP Plugin SDK for exact dependency matching
cp -r build/sdk/* my-plugin/
cd my-plugin/
make build XRP_VERSION=v1.0.0

Documentation

License

GNU GPL v3.0; see LICENSE in this repo.

Author

Chris Dzombak

Special Thanks

Thanks to Namespace for providing GitHub Actions runners for this project.

About

HTML/XML aware reverse proxy

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •