foxy-io 0.3.6

A configuration-driven and hyper-extensible HTTP proxy library
Documentation

Foxy 🦊

CI-Crate CI-Docker codecov Crates.io Version Crates.io Downloads Rust Version Docker Version Docker Pulls License Ask DeepWiki

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

Use Cases

Foxy is ideal for:

  • API Gateway: Centralize routing, security, and observability for your microservices.
  • Edge Proxy: Secure and control traffic at the edge of your network.
  • Backend for Frontend (BFF): Tailor API responses for specific client applications.
  • Protocol Translation: Transform requests and responses between different protocols.
  • Load Balancing: Distribute incoming traffic across multiple upstream services.

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: Configurable authentication with built-in OIDC support
  • 📊 Observability: OpenTelemetry integration for distributed tracing
  • 📝 Structured Logging: JSON logging with trace IDs for better observability
  • 🚀 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
  • 🚢 Docker Support: Official container image for rapid deployment

Quickstart

As a Library

Add Foxy to your Cargo.toml:

[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?;

Run the Example

git clone https://github.com/johan-steffens/foxy.git
cd foxy
export RUST_LOG=debug
export FOXY_CONFIG_FILE=$(pwd)/config/example.json
cargo run --bin foxy

Building from Source

Foxy uses platform-specific TLS backends to optimize for different build environments and avoid dependency issues.

Prerequisites

  • Rust 1.70+
  • Platform-specific TLS dependencies handled automatically

Build

git clone https://github.com/johan-steffens/foxy.git
cd foxy
cargo build --release

TLS Backend Strategy

  • Windows: Uses rustls-tls (pure Rust) to avoid OpenSSL build issues completely
  • Unix/Linux: Uses native-tls with vendored OpenSSL for Docker builds
  • Docker: Vendored SSL eliminates build-time dependency issues - no need to install OpenSSL at build time
  • Cross-compilation: Platform detection ensures correct TLS backend automatically

Run with Docker

Prerequisites: Docker 20.10+ installed

Pull the multi-arch image:

docker pull johansteffens/foxy:latest

Run the proxy, exposing port 8080:

docker run --rm -p 8080:8080 johansteffens/foxy:latest

Using a Custom Configuration

  1. Create a config.json file on your host
  2. Ensure your configuration binds to address 0.0.0.0
  3. Mount it into the container:
docker run --rm -p 8080:8080 \
  -v "$(pwd)/config.json:/app/config.json:ro" \
  -e FOXY_CONFIG_FILE=/app/config.json \
  johansteffens/foxy:latest 

Run with Docker Compose

Create a docker-compose.yml file:

version: "3.9"
services:
  foxy:
    image: johansteffens/foxy:latest
    container_name: foxy
    ports:
      - "8080:8080"
    environment:
      FOXY_CONFIG_FILE: /config/config.json
    volumes:
      - ./config.json:/config/config.json:ro

Start the service:

docker compose up -d

Tip: When you update config.json, restart with docker compose restart foxy to apply changes.

Core Concepts

Routing System

Foxy uses a predicate-based routing system to determine how requests are handled:

  • Predicates: Conditions that match against request properties (path, method, headers, query)
  • Priority: Routes with higher priority are evaluated first
  • Filters: Processing steps applied to matched routes

Configuration

Foxy's configuration can be provided through multiple sources:

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

Example configuration:

{
  "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 configuration options, see the Configuration Guide.

Security

Add JWT validation with the OIDC security provider:

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

This configuration validates all requests against the identity provider, while allowing public access to /health.

Basic Auth Provider

Add Basic Authentication to your proxy:

{
  "proxy": {
    "security_chain": [
      {
        "type": "basic",
        "config": {
          "credentials": [
            "user1:pass1",
            "admin:secure_password"
          ],
          "bypass": [
            { "methods": ["GET"], "path": "/public/*" }
          ]
        }
      }
    ]
  }
}

This configuration enables Basic Authentication for all routes, except those matching /public/* with a GET method.

OpenTelemetry Feature

Enable distributed tracing with OpenTelemetry:

# In your Cargo.toml
[dependencies]
foxy-io = { version = "...", features = ["opentelemetry"] }

Configure the OpenTelemetry collector in your configuration:

{
  "proxy": {
    "opentelemetry": {
      "endpoint": "http://otel-collector:4317",
      "service_name": "my-proxy-service",
      "include_headers": true,
      "resource_attributes": {
        "host.name": "proxy-pod-abc123"
      },
      "collector_headers": {
        "X-API-Key": "d41000b6-6191-47c5-99f1-7b88b1b97409"
      }
    }
  }
}

SwaggerUI Feature

Enable the Swagger UI feature:

# In your Cargo.toml
[dependencies]
foxy-io = { version = "...", features = ["swagger-ui"] }

Configure the OpenAPI schemas to be served on the Swagger UI in your configuration:

{
  "proxy": {
    "swagger_ui": {
      "enabled": true,
      "path": "/swagger-ui",
      "sources": [
        {
          "name": "Petstore",
          "url": "https://petstore.swagger.io/v2/swagger.json"
        }
      ]
    }
  }
}

Structured Logging

Foxy supports structured JSON logging for better observability in production environments:

{
  "proxy": {
    "logging": {
      "structured": true,
      "format": "json",
      "include_trace_id": true,
      "static_fields": {
        "environment": "production",
        "service": "api-gateway"
      }
    }
  }
}

Key benefits:

  • Trace IDs: Every request gets a unique ID for end-to-end tracking
  • JSON Format: Machine-parseable logs for integration with log aggregation systems
  • Rich Context: Detailed request information and timing metrics
  • Static Fields: Add environment-specific fields to all logs

For detailed configuration options, see the Configuration Guide.

Performance Features

Streaming Architecture

  • Zero-Copy Streaming: Request and response bodies are streamed end-to-end
  • Backpressure Support: Large uploads/downloads propagate backpressure correctly
  • Memory Efficiency: Memory usage is bound by socket buffers, not by request/response size

Detailed Metrics

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

[timing] GET /api/users -> 200 | total=152ms upstream=148ms internal=4ms
Metric Description
total Wall-clock time from first byte in to last byte out
upstream Time spent awaiting the target server
internal Proxy-side processing time (total − upstream)

Request and Response Logging

The LoggingFilter can peek and log request/response bodies:

  • Logs the first 1,000 bytes/characters (UTF-8 lossy conversion)
  • Safely handles binary or large payloads
  • Configurable log level and content limits

Note: Body logging adds some latency to proxied calls.

Extension Points

Foxy is designed to be highly extensible. You can inject your own custom logic into the proxy pipeline by implementing a few simple traits. This allows you to add custom routing rules, request/response modifications, and authentication mechanisms without forking the project.

The primary extension points are:

  • Filter: Modify requests and responses.
  • Predicate: Implement custom routing logic.
  • SecurityProvider: Add custom authentication and authorization.

All extension points follow a similar pattern:

  1. Implement the corresponding trait.
  2. Register your implementation with Foxy's global registry at startup.
  3. Use your custom component in the configuration file.

For a detailed guide on adding extension points, see the Extension Guide.

Development Status

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

License

This project is licensed under the Mozilla Public License Version 2.0.

Contributions

We welcome and appreciate contributions to Foxy! Please see our Contribution Guide for details on how to get involved, including our development workflow, code style, and testing procedures.

Contributors

A big thank you to all the individuals who have contributed to Foxy!

Johan Steffens Armand Eicker Ohan Smit