{"id":32544428,"url":"https://github.com/cdzombak/xrp","last_synced_at":"2025-10-28T17:59:22.921Z","repository":{"id":308603584,"uuid":"1033394762","full_name":"cdzombak/xrp","owner":"cdzombak","description":"HTML/XML aware reverse proxy","archived":false,"fork":false,"pushed_at":"2025-10-20T01:48:18.000Z","size":10110,"stargazers_count":13,"open_issues_count":3,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-23T21:41:36.273Z","etag":null,"topics":["html","http","reverse-proxy","xml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cdzombak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-06T18:42:35.000Z","updated_at":"2025-09-23T08:45:09.000Z","dependencies_parsed_at":"2025-08-06T21:26:43.456Z","dependency_job_id":"754546a5-896b-4205-82f8-e658c3ca3caf","html_url":"https://github.com/cdzombak/xrp","commit_stats":null,"previous_names":["cdzombak/xrp"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/cdzombak/xrp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdzombak%2Fxrp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdzombak%2Fxrp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdzombak%2Fxrp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdzombak%2Fxrp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cdzombak","download_url":"https://codeload.github.com/cdzombak/xrp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdzombak%2Fxrp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281485702,"owners_count":26509764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-28T02:00:06.022Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","http","reverse-proxy","xml"],"created_at":"2025-10-28T17:59:21.775Z","updated_at":"2025-10-28T17:59:22.908Z","avatar_url":"https://github.com/cdzombak.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XRP - HTML/XML-aware Reverse Proxy\n\nAn HTML/XML-aware reverse proxy that allows modifying responses via plugins.\n\n- **Plugin-based content modification** - Go plugins modify HTML/XML responses\n- **Redis caching** - HTTP-compliant caching\n\n## Run: Quick Demo\n\n```shell\ncd examples\ndocker compose build \u0026\u0026 docker compose up\n\n# In another terminal:\ncurl localhost:8080\n```\n\n## Configuration\n\nCreate 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:\n\n- `backend_url`: The upstream URL to proxy requests to\n- `cookie_denylist`: If a request has a cookie whose name is listed in the denylist, the response is not cached in Redis\n- `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.\n- `mime_types`: A list of MIME type configuration objects. These specify the plugins that will run on responses with the specified MIME type.\n- `redis`: Redis cache backend configuration.\n- `health_port`: Port for the health check endpoint server (default: 8081)\n\n## Health Check Endpoint\n\nXRP 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.\n\n- **GET `/health`** on the health port:\n  - Returns `102 Processing` with body `starting` during startup (while plugins are loading)\n  - Returns `200 OK` with body `ok` when fully ready to serve traffic\n  - Returns `102 Processing` during configuration reloads\n\nThis endpoint is useful for:\n- Kubernetes readiness probes\n- Docker health checks\n- Load balancer health monitoring\n- Service mesh integration\n\n## Installation \u0026 Running\n\nXRP is inserted between your web server and your application backend. So, instead of:\n\n```\nnginx  -\u003e  app (e.g. Ghost)\n```\n\nYou'll run:\n\n```\nnginx  -\u003e  xrp -\u003e  app\n```\n\nThe exact details of how to implement this will vary depending on your setup.\n\nYou'll need to write your custom plugins depending on your needs. See the [Plugin Development](#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.\n\n### Docker\n\nDocker 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.\n\nSee [the example Docker Compose file](deployment/docker-compose.prod.yml) for details.\n\n### Debian/Ubuntu via apt repository\n\n[Install my Debian repository](https://www.dzombak.com/blog/2025/06/updated-instructions-for-installing-my-debian-package-repositories/) if you haven't already:\n\n```shell\nsudo mkdir -p /etc/apt/keyrings\ncurl -fsSL https://dist.cdzombak.net/keys/dist-cdzombak-net.gpg -o /etc/apt/keyrings/dist-cdzombak-net.gpg\nsudo chmod 644 /etc/apt/keyrings/dist-cdzombak-net.gpg\nsudo mkdir -p /etc/apt/sources.list.d\nsudo curl -fsSL https://dist.cdzombak.net/cdzombak-oss.sources -o /etc/apt/sources.list.d/cdzombak-oss.sources\nsudo chmod 644 /etc/apt/sources.list.d/cdzombak-oss.sources\nsudo apt update\n```\n\nThen install `xrp` via `apt`:\n\n```shell\nsudo apt install xrp\n```\n\n### Manual from release artifacts\n\nPre-built binaries for Linux on amd64/arm64 are downloadable from each [GitHub Release](https://github.com/cdzombak/xrp/releases). Debian packages are available as well.\n\nCopy the appropriate binary for your architecture and run it using your tools of choice.\n\n### From source\n\nTo build binaries yourself, check out this repository and check out the Git tag for the xrp version you want to build. Then run:\n\n```shell\nmake build/binaries\n```\n\nCopy the resulting binary for your architecture from `dist/` and run it using your tools of choice.\n\n### systemd\n\nIf you've installed XRP binaries, whether from the apt repository, release artifacts, or from source, you can use [the provided systemd unit file](deployment/systemd/xrp.service) to run XRP as a service.\n\n## Plugin Development\n\nPlugins must implement the `Plugin` interface and export struct values (not pointers):\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"net/url\"\n    \"golang.org/x/net/html\"\n    \"github.com/beevik/etree\"\n    \"github.com/cdzombak/xrp/pkg/xrpplugin\"\n)\n\ntype MyPlugin struct{}\n\nfunc (p *MyPlugin) ProcessHTMLTree(ctx context.Context, url *url.URL, node *html.Node) error {\n    // Modify HTML tree in place\n    return nil\n}\n\nfunc (p *MyPlugin) ProcessXMLTree(ctx context.Context, url *url.URL, doc *etree.Document) error {\n    // Modify XML document in place  \n    return nil\n}\n\n// Export struct value (not pointer) for plugin system compatibility\nvar MyPluginInstance = MyPlugin{}\n```\n\n### Development Options\n\n**Local development** (fast, uses current dependencies):\n```bash\ngo build -buildmode=plugin -o plugin.so plugin.go\n```\n\n**Production builds** (guaranteed compatibility):\n```bash\n# Use XRP Plugin SDK for exact dependency matching\ncp -r build/sdk/* my-plugin/\ncd my-plugin/\nmake build XRP_VERSION=v1.0.0\n```\n\n### Documentation\n\n- **Plugin SDK**: [build/sdk/README.md](build/sdk/README.md) - Complete plugin development guide\n- **Dependency Management**: [PLUGIN_DEPENDENCY_MANAGEMENT.md](doc/PLUGIN_DEPENDENCY_MANAGEMENT.md) - Docker-based builds with version enforcement\n- **Build System**: [BUILD.md](doc/BUILD.md) - XRP build system documentation\n\n## License\n\nGNU GPL v3.0; see [LICENSE](LICENSE) in this repo.\n\n## Author\n\nChris Dzombak\n- [dzombak.com](https://www.dzombak.com)\n- [GitHub @cdzombak](https://github.com/cdzombak)\n\n## Special Thanks\n\nThanks to [Namespace](https://namespace.so) for providing GitHub Actions runners for this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdzombak%2Fxrp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcdzombak%2Fxrp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdzombak%2Fxrp/lists"}