Development moved to MaplePrivacyLabs/Maple, under
proxy/. Use the current proxy guide for installation, configuration, source builds, and contributions. New issues and pull requests belong in the monorepo.
Native proxy archives are distributed with
Maple releases; there is no
new standalone proxy release stream here. Existing standalone releases and
ghcr.io/opensecretcloud/maple-proxy images remain historical artifacts. The
legacy container publisher is disabled, so its latest tag does not track
future Maple releases.
Future container publications target ghcr.io/mapleprivacylabs/maple-proxy.
The first publication and public-pull verification in that namespace are still
pending. Keep existing deployments on their working image until a replacement
has been published and verified; do not assume the new latest exists. Follow
the current container instructions
for the transition.
The source and documentation below describe the legacy standalone checkout. Existing issues and draft pull requests remain here until their disposition is recorded; this notice does not close or port them.
A lightweight proxy for Maple/OpenSecret's OpenAI-compatible inference endpoints, with the security and privacy benefits of Trusted Execution Environment (TEE) processing.
- OpenAI-Compatible Surface - Models, chat completions, and embeddings endpoints
- Secure TEE Processing - All requests processed in secure enclaves
- Lossless Chat Parameters - Provider-specific request fields pass through unchanged
- Streaming and Non-Streaming - Supports both chat completion response modes
- Flexible Authentication - Environment variables or per-request API keys
- Familiar Clients - Point compatible OpenAI clients at the proxy base URL
- Lightweight - Minimal overhead, maximum performance
- CORS Support - Ready for web applications
git clone <repository>
cd maple-proxy
cargo build --locked --releaseAdd to your Cargo.toml:
[dependencies]
maple-proxy = { git = "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/opensecretcloud/maple-proxy" }
# Or if published to crates.io:
# maple-proxy = "0.3.2"Set environment variables or use command-line arguments:
# Environment Variables
export MAPLE_HOST=127.0.0.1 # Server host (default: 127.0.0.1)
export MAPLE_PORT=8080 # Server port (default: 8080)
export MAPLE_BACKEND_URL=http://localhost:3000 # Maple backend URL (prod: https://enclave.trymaple.ai)
export MAPLE_PCR0_ENVIRONMENT=production # PCR0 trust roots: production (default) or development
export MAPLE_API_KEY=your-maple-api-key # Default API key (optional)
export MAPLE_DEBUG=true # Enable debug logging
export MAPLE_ENABLE_CORS=true # Enable CORS
export MAPLE_REQUEST_TIMEOUT_SECS=300 # Backend request timeout
export MAPLE_STREAM_IDLE_TIMEOUT_SECS=300 # Streaming idle timeout between chunksOr use CLI arguments:
cargo run --locked -- --host 0.0.0.0 --port 8080 --backend-url https://enclave.trymaple.ai
# Development enclaves must be selected explicitly
cargo run --locked -- --backend-url https://enclave.secretgpt.ai --pcr0-environment developmentcargo run --lockedYou should see:
π Maple Proxy Server started successfully!
π Available endpoints:
GET /health - Health check
GET /v1/models - List available models
POST /v1/chat/completions - Create chat completions (streaming & non-streaming)
POST /v1/embeddings - Create embeddings
curl http://localhost:8080/v1/models \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY"curl -N http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "llama3-3-70b",
"messages": [
{"role": "user", "content": "Write a haiku about technology"}
],
"stream": true
}'Set stream to true for Server-Sent Events or false for one JSON response.
Additional provider-specific JSON fields are forwarded without being parsed or
rewritten by the proxy or Rust SDK.
curl http://localhost:8080/v1/embeddings \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nomic-embed-text",
"input": "Generate an embedding for this text"
}'You can also embed Maple Proxy in your own Rust application:
use maple_proxy::{Config, Pcr0Environment, create_app};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize tracing
tracing_subscriber::fmt::init();
// Create config programmatically
let config = Config::new(
"127.0.0.1".to_string(),
8081, // Custom port
"https://enclave.trymaple.ai".to_string(),
)
.with_pcr0_environment(Pcr0Environment::Production)
.with_api_key("your-api-key-here".to_string())
.with_debug(true)
.with_cors(true);
// Create the app
let app = create_app(config.clone());
// Start the server
let addr = config.socket_addr()?;
let listener = TcpListener::bind(addr).await?;
println!("Maple proxy server running on http://{}", addr);
axum::serve(listener, app).await?;
Ok(())
}Run the example:
cargo run --locked --example library_usageimport openai
client = openai.OpenAI(
api_key="YOUR_MAPLE_API_KEY",
base_url="http://localhost:8080/v1"
)
# Streaming chat completion
stream = client.chat.completions.create(
model="llama3-3-70b",
messages=[{"role": "user", "content": "Hello, world!"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'YOUR_MAPLE_API_KEY',
baseURL: 'http://localhost:8080/v1',
});
const stream = await openai.chat.completions.create({
model: 'llama3-3-70b',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}# Health check
curl http://localhost:8080/health
# List models
curl http://localhost:8080/v1/models \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY"
# Streaming chat completion
curl -N http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "llama3-3-70b",
"messages": [{"role": "user", "content": "Tell me a joke"}],
"stream": true
}'
# Embeddings
curl http://localhost:8080/v1/embeddings \
-H "Authorization: Bearer YOUR_MAPLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nomic-embed-text",
"input": "Generate an embedding for this text"
}'Maple Proxy supports two authentication methods:
Set MAPLE_API_KEY - all requests will use this key by default:
export MAPLE_API_KEY=your-maple-api-key
cargo run --lockedOverride the default key or provide one if not set:
curl -H "Authorization: Bearer different-api-key" ...Enable CORS for web applications:
export MAPLE_ENABLE_CORS=true
cargo run --lockedPull and run the official image from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/opensecretcloud/maple-proxy:latest
# Run with your API key
docker run -p 8080:8080 \
-e MAPLE_BACKEND_URL=https://enclave.trymaple.ai \
-e MAPLE_REQUEST_TIMEOUT_SECS=300 \
-e MAPLE_STREAM_IDLE_TIMEOUT_SECS=300 \
ghcr.io/opensecretcloud/maple-proxy:latest# Build the image locally
just docker-build
# Run the container
just docker-run- Option A: Use pre-built image from GHCR
# In your docker-compose.yml, use:
image: ghcr.io/opensecretcloud/maple-proxy:latest- Option B: Build your own image
docker build -t maple-proxy:latest .- Run with docker-compose:
# Copy the example environment file
cp .env.example .env
# Edit .env with your configuration
vim .env
# Start the service
docker-compose up -dWhen deploying Maple Proxy on a public network:
- DO NOT set
MAPLE_API_KEYin the container environment - Instead, require clients to pass their API key with each request:
# Client-side authentication for public proxy
client = OpenAI(
base_url="https://your-proxy.example.com/v1",
api_key="user-specific-maple-api-key" # Each user provides their own key
)This ensures:
- Users' API keys remain private
- Multiple users can share the same proxy instance
- No API keys are exposed in container configurations
# Build image
just docker-build
# Run interactively
just docker-run
# Run in background
just docker-run-detached
# View logs
just docker-logs
# Stop container
just docker-stop
# Use docker-compose
just compose-up
just compose-logs
just compose-downThe Docker image:
- Uses multi-stage builds for minimal size (~130MB)
- Runs as non-root user for security
- Includes health checks
- Optimizes dependency caching with cargo-chef
- Supports both x86_64 and ARM architectures
# docker-compose.yml environment section
environment:
- MAPLE_BACKEND_URL=https://enclave.trymaple.ai # Production backend
- MAPLE_ENABLE_CORS=true # Enable for web apps
- MAPLE_REQUEST_TIMEOUT_SECS=300 # Backend request timeout
- MAPLE_STREAM_IDLE_TIMEOUT_SECS=300 # Streaming idle timeout
- RUST_LOG=info # Logging level
# - MAPLE_API_KEY=xxx # Only for private deployments!Automated Builds (GitHub Actions)
- Every push to
masterautomatically builds and publishes toghcr.io/opensecretcloud/maple-proxy:latest - Git tags (e.g.,
v1.0.0) trigger versioned releases - Multi-platform images (linux/amd64, linux/arm64) built automatically
- No manual intervention needed - just push your code!
Local Development (Justfile)
# For local testing and debugging
just docker-build # Build locally
just docker-run # Test locally
just ghcr-push v1.2.3 # Manual push (requires login)Use GitHub Actions for production releases, Justfile for local development.
cargo build --lockedexport MAPLE_DEBUG=true
cargo run --lockedcargo test --lockedMaple Proxy supports all models available in the Maple/OpenSecret platform, including:
llama3-3-70b- Llama 3.3 70B parameter modelnomic-embed-text- Embedding model for/v1/embeddings- And many others - check
/v1/modelsendpoint for current list
"No API key provided"
- Set
MAPLE_API_KEYenvironment variable or provideAuthorization: Bearer <key>header
"Failed to establish secure connection"
- Check your
MAPLE_BACKEND_URLis correct - Ensure your API key is valid
- Check network connectivity
Connection refused
- Make sure the server is running on the specified host/port
- Check firewall settings
Enable debug logging for detailed information:
export MAPLE_DEBUG=true
cargo run --lockedβββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β OpenAI Client βββββΆβ Maple Proxy βββββΆβ Maple Backend β
β (Python/JS) β β (localhost) β β (TEE) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
- Client makes standard OpenAI API calls to localhost
- Maple Proxy handles authentication and TEE handshake
- Requests are securely forwarded to Maple's TEE infrastructure
- Responses are streamed back to the client in OpenAI format
MIT License - see LICENSE file for details.
Contributions welcome! Please feel free to submit a Pull Request.