#proxy #extensible #http-proxy #configurable #http #config

bin+lib foxy-io

A configuration-driven and hyper-extensible HTTP proxy library

12 releases

Uses new Rust 2024

new 0.1.4 May 1, 2025
0.1.3 May 1, 2025
0.1.0 Apr 26, 2025
0.0.8 Apr 30, 2025

#398 in Web programming

Download history 592/week @ 2025-04-24

593 downloads per month

MPL-2.0 license

115KB
2K SLoC

Foxy 🦊

CI-Crate CI-Docker Crates.io Version Crates.io Downloads Crates.io License Rust Version

A minimal, configuration-driven, hyper-extendible Rust HTTP proxy library.

Features

  • πŸ›£οΈ Powerful Routing: Predicate-based routing with path patterns, HTTP methods, headers, and query matching
  • πŸ”„ Flexible Filters: Pre and post-processing filters for request/response modification
  • βš™οΈ Configuration Superpowers: Layered configuration from files and environment variables
  • 🌐 Fine-grained Control: Route-specific filter chains for precise request handling
  • πŸ”’ Pluggable Security Chain – configurable, provider-based request authentication with built-in providers
  • πŸš€ Modern Async Architecture: Built on Tokio and Hyper for high performance
  • πŸ“¦ Lightweight Dependencies: Minimal external dependencies for core functionality
  • 🧩 Highly Extensible: Custom predicates, filters and security providers via simple traits

Quickstart

Run the basic proxy example

git clone https://github.com/johan-steffens/foxy.git
cd foxy
cargo run --example basic-proxy

Run it in your code

Add Foxy as a dependency to your Cargo.toml file

[dependencies]
foxy-io = "..."

Build an instance and start the server.

use foxy::Foxy;

// Create a new Foxy instance with layered configuration
let foxy = Foxy::loader()
    .with_env_vars()                  // Environment variables (highest priority)
    .with_config_file("config.toml")  // File-based config (medium priority)
    .with_config_file("defaults.toml") // Defaults (lowest priority)
    .build().await?;

// Start the proxy server and wait for it to complete
foxy.start().await?;

Core Principles

  • Predictable Routing: Predicate-based matching with clear priorities determines how requests are routed
  • Configurable Processing: Route-specific and global filters for request/response modification
  • Extensibility: Trait-based design enables custom predicates and filters
  • Configuration-Driven: All behavior controlled via flexible configuration with sensible defaults

Configuration

Foxy's power comes from its rich configuration system. Here's a brief overview:

{
  "routes": [
    {
      "id": "api-route",
      "target": "https://api.example.com",
      "filters": [
        {
          "type": "path_rewrite",
          "config": {
            "pattern": "^/api/(.*)$",
            "replacement": "/v2/$1"
          }
        }
      ],
      "predicates": [
        {
          "type_": "path",
          "config": {
            "pattern": "/api/*"
          }
        }
      ]
    }
  ]
}

For detailed information on all configuration options, see the Configuration Guide.

Configuration Sources

Foxy supports multiple configuration sources with priority order:

// Build a layered configuration
let foxy = Foxy::loader()
    .with_env_vars()                   // First priority
    .with_config_file("config.json")   // Second priority
    .build().await?;

Example: FOXY_SERVER_PORT=8080 β†’ server.port

Enabling security

Add a security_chain with a configured provider to your proxy configuration:

{
  "proxy": {
    "security_chain": [
      {
        "type": "oidc",
        "config": {
          "issuer-uri": "https://id.example.com/.well-known/openid-configuration",
          "aud": "my-api",
          "bypass-routes": [
            { "methods": ["GET"], "path": "/health" }
          ]
        }
      }
    ]
  }
}

That’s it β€” requests hitting /api/** will be validated against the IDP while /health remains public. Full configuration examples can be found in the Configuration Guide.

Streaming bodies

  • Foxy proxies request and response bodies as streams end-to-end to ensure there's no full body buffering in memory.
    • Large uploads/downloads back-pressure correctly.
    • Memory usage is bound only by socket buffers.

Detailed timing metrics

  • Foxy records and logs three high-resolution latencies on every call
    (DEBUG level):

[timing] <METHOD> <PATH> -> <STATUS> | total=<X> upstream=<Y> internal=<Z>

field description
total wall-clock time from first byte in to last byte out
upstream time spent awaiting the target server
internal proxy-side routing / filtering / logging (total βˆ’ upstream)

Request and Response body logging

  • LoggingFilter peeks and logs the first 1 000 bytes/characters of every request and response body (UTF-8-lossy).
  • Binary or very large payloads are safeβ€”the remainder of the stream is forwarded untouched.
  • Please note: enabling request and response logging will introduce additional latency to your calls.

Development Status

  • Configuration System
  • Loader Module
  • Core HTTP Proxy
  • Predicate-based Routing
  • Request/Response Filters
  • Security Chain
    • OIDC provider
    • Basic auth provider

License

This project is licensed under Mozilla Public License Version 2.0

Dependencies

~17–36MB
~625K SLoC