FortiBlox LogoFortiBlox Docs
NexusSecurity

RPC Proxy

Deploy a secure RPC proxy to hide your API keys in browser applications

FortiBlox RPC Proxy

The FortiBlox RPC Proxy is a lightweight, secure proxy that allows you to hide your FortiBlox API keys from client-side applications. Deploy it to Cloudflare Workers, Vercel Edge Functions, or your own infrastructure in minutes.

Status: Coming Q1 2025. The RPC proxy is currently under development. Sign up for early access at nexus.fortiblox.com/rpc-proxy

The Problem

When building browser-based X1 Blockchain applications, you face a security dilemma:

// ❌ This exposes your API key to anyone using DevTools
const connection = new Connection(
  `https://nexus.fortiblox.com/rpc?api-key=${apiKey}` // Visible in network tab!
);

Anyone can:

  • Open browser DevTools → Network tab
  • See your API key in plain text
  • Copy it and abuse your credits
  • Exhaust your rate limits

The Solution

The FortiBlox RPC Proxy acts as a secure intermediary:

Browser → Your Proxy (with API key) → FortiBlox RPC

Your API key stays on the server-side, never exposed to clients.

Features

Planned Features

  • One-Click Deployment

    • Cloudflare Workers (recommended)
    • Vercel Edge Functions
    • Netlify Functions
    • AWS Lambda
    • Self-hosted Docker
  • Security Features

    • API key hidden from clients
    • Domain whitelisting (CORS)
    • IP allowlisting
    • Request rate limiting
    • Request method filtering
    • Custom authentication
  • Performance

    • Edge deployment (low latency)
    • WebSocket support
    • Request caching
    • Automatic retries
    • Load balancing
  • Developer Experience

    • Zero configuration defaults
    • Environment variable management
    • Detailed logging
    • Metrics dashboard
    • Error tracking

Deployment Options

Why Cloudflare Workers?

  • Global edge network (200+ cities)
  • Zero cold starts
  • Free tier: 100,000 requests/day
  • Built-in DDoS protection
  • WebSocket support

Deployment (Coming Soon):

# 1. Install Wrangler CLI
npm install -g wrangler

# 2. Clone the proxy repo
git clone https://github.com/fortiblox/fortiblox-rpc-proxy
cd fortiblox-rpc-proxy

# 3. Configure your API key
wrangler secret put FORTIBLOX_API_KEY
# Enter your API key when prompted

# 4. Deploy
wrangler deploy

# Output:
# ✨ Deployed to: https://fortiblox-proxy.your-subdomain.workers.dev

Configuration:

# wrangler.toml
name = "fortiblox-rpc-proxy"
main = "src/index.js"
compatibility_date = "2025-01-01"

[vars]
# Allowed origins (comma-separated)
ALLOWED_ORIGINS = "https://myapp.com,https://*.myapp.com"

# Rate limiting (requests per minute)
RATE_LIMIT = "60"

# Enable request logging
DEBUG = "false"

Option 2: Vercel Edge Functions

Deployment (Coming Soon):

# 1. Install Vercel CLI
npm install -g vercel

# 2. Clone and deploy
git clone https://github.com/fortiblox/fortiblox-rpc-proxy
cd fortiblox-rpc-proxy
vercel deploy

# 3. Set environment variables
vercel env add FORTIBLOX_API_KEY
# Enter your API key when prompted

# Output:
# ✨ Deployed to: https://fortiblox-proxy.vercel.app

Option 3: Self-Hosted Docker

Deployment:

# Coming soon - Docker image will be available at:
docker pull fortiblox/rpc-proxy:latest

docker run -d \
  -p 3000:3000 \
  -e FORTIBLOX_API_KEY=your_api_key_here \
  -e ALLOWED_ORIGINS=https://myapp.com \
  fortiblox/rpc-proxy:latest

Usage

Once deployed, use your proxy URL instead of the FortiBlox API directly:

import { Connection } from '@solana/web3.js';

// ✅ Use your proxy URL (no API key exposed!)
const connection = new Connection(
  'https://fortiblox-proxy.your-subdomain.workers.dev',
  'confirmed'
);

// Make RPC calls as normal
const slot = await connection.getSlot();
const health = await connection.getHealth();

// Send transactions
const signature = await connection.sendTransaction(transaction, [signer]);
from solana.rpc.api import Client

# ✅ Use your proxy URL (no API key exposed!)
client = Client("https://fortiblox-proxy.your-subdomain.workers.dev")

# Make RPC calls as normal
slot = client.get_slot()
health = client.get_health()

# Send transactions
signature = client.send_transaction(transaction)
import { Connection } from '@solana/web3.js';
import { useMemo } from 'react';

function App() {
  // ✅ Use your proxy URL (no API key exposed!)
  const connection = useMemo(
    () => new Connection(
      'https://fortiblox-proxy.your-subdomain.workers.dev',
      'confirmed'
    ),
    []
  );

  async function fetchData() {
    const slot = await connection.getSlot();
    console.log('Current slot:', slot);
  }

  return (
    <div>
      <button onClick={fetchData}>Fetch Slot</button>
    </div>
  );
}
import { Connection } from '@solana/web3.js';
import { ref, onMounted } from 'vue';

export default {
  setup() {
    // ✅ Use your proxy URL (no API key exposed!)
    const connection = new Connection(
      'https://fortiblox-proxy.your-subdomain.workers.dev',
      'confirmed'
    );

    const slot = ref(null);

    async function fetchSlot() {
      slot.value = await connection.getSlot();
    }

    onMounted(fetchSlot);

    return { slot, fetchSlot };
  }
};

Configuration

Environment Variables

# Required
FORTIBLOX_API_KEY=fbx_your_api_key_here

# Optional
ALLOWED_ORIGINS=https://myapp.com,https://*.myapp.com
ALLOWED_METHODS=POST,GET
RATE_LIMIT=60
CACHE_TTL=60
DEBUG=false
ENABLE_WEBSOCKET=true

Advanced Configuration

Rate Limiting:

// wrangler.toml or .env
RATE_LIMIT=60              // 60 requests per minute
RATE_LIMIT_WINDOW=60       // 60 second window
RATE_LIMIT_BY=ip           // Rate limit by: ip, origin, or custom-header

Request Filtering:

// Only allow specific RPC methods
ALLOWED_METHODS=getAccountInfo,getBalance,sendTransaction

// Block specific RPC methods
BLOCKED_METHODS=getProgramAccounts,getTokenAccountsByOwner

Custom Headers:

// Add custom headers to responses
CUSTOM_HEADERS={
  "X-Powered-By": "FortiBlox",
  "X-Proxy-Version": "1.0.0"
}

Security Best Practices

1. Enable CORS Restrictions

// Restrict to your domains only
ALLOWED_ORIGINS=https://myapp.com,https://www.myapp.com

// ✅ Requests from myapp.com - Allowed
// ❌ Requests from attacker.com - Blocked

2. Implement Rate Limiting

// Prevent abuse
RATE_LIMIT=60              // 60 requests per minute per IP
BURST_LIMIT=10             // Allow short bursts

// When exceeded:
// HTTP 429: Too Many Requests
// Retry-After: 30

3. Use Request Authentication (Optional)

Add custom authentication:

// Require custom auth header
REQUIRE_AUTH_HEADER=true
AUTH_HEADER_NAME=X-App-Secret
AUTH_HEADER_VALUE=your_secret_value

// In your frontend:
fetch('https://your-proxy.com', {
  headers: {
    'X-App-Secret': 'your_secret_value'
  }
});

4. Monitor Usage

Track proxy usage in Cloudflare/Vercel dashboard:

  • Total requests
  • Blocked requests
  • Error rates
  • Response times
  • Geographic distribution

WebSocket Support

The proxy supports WebSocket connections for real-time data:

import { Connection } from '@solana/web3.js';

const connection = new Connection(
  'https://fortiblox-proxy.your-subdomain.workers.dev',
  'confirmed'
);

// Subscribe to account changes
const subscriptionId = connection.onAccountChange(
  publicKey,
  (accountInfo) => {
    console.log('Account updated:', accountInfo);
  }
);

// WebSocket connection goes through proxy securely

Troubleshooting

CORS Errors

Access to fetch has been blocked by CORS policy

Solution: Add your domain to ALLOWED_ORIGINS:

wrangler secret put ALLOWED_ORIGINS
# Enter: https://myapp.com,https://www.myapp.com

Rate Limit Errors

429 Too Many Requests
Retry-After: 60

Solution: Increase rate limit or implement client-side throttling:

// Implement exponential backoff
async function makeRequestWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429 && i < maxRetries - 1) {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
}

Proxy Not Responding

Checklist:

  • Is the proxy deployed? Check deployment status
  • Is FORTIBLOX_API_KEY set correctly?
  • Are you making requests from an allowed origin?
  • Check proxy logs for errors

Comparison with Alternatives

FortiBlox RPC Proxy vs DIY Backend

FeatureFortiBlox ProxyDIY Backend
Setup Time5 minutesHours
InfrastructureManaged (Cloudflare)Self-managed
Global Edge✅ 200+ locations❌ Single region
Cold Starts✅ None❌ Possible
CostFree (100K req/day)Server costs
Maintenance✅ None❌ Ongoing
WebSocket✅ SupportedRequires work
Updates✅ Automatic❌ Manual

FortiBlox vs Helius RPC Proxy

FeatureFortiBloxHelius
Open Source✅ Yes✅ Yes
Cloudflare Workers✅ Yes✅ Yes
Vercel Edge✅ Yes❌ No
Docker✅ Yes❌ No
Rate Limiting✅ Built-in⚠️ Basic
Request Filtering✅ Advanced⚠️ Basic
Custom Auth✅ Yes❌ No
Analytics✅ Built-in⚠️ Basic

Roadmap

Q1 2025

  • ✅ Core proxy functionality
  • ✅ Cloudflare Workers support
  • ✅ Basic rate limiting
  • ✅ CORS configuration

Q2 2025

  • ⏳ Vercel Edge Functions support
  • ⏳ Advanced rate limiting (per-user)
  • ⏳ Request analytics dashboard
  • ⏳ Custom authentication hooks

Q3 2025

  • ⏳ AWS Lambda support
  • ⏳ Docker image
  • ⏳ Load balancing
  • ⏳ Automatic failover

Q4 2025

  • ⏳ Redis-based rate limiting
  • ⏳ Request caching
  • ⏳ GraphQL support
  • ⏳ Multi-key load balancing

Get Early Access

Sign up for early access to the FortiBlox RPC Proxy:

  1. Visit nexus.fortiblox.com/rpc-proxy
  2. Enter your email
  3. We'll notify you when it's ready (Q1 2025)

Early access benefits:

  • Beta access before public launch
  • Priority support
  • Feature requests
  • Extended free tier

Temporary Solution: Build Your Own

While the official proxy is in development, you can build a simple proxy:

// server.js
const express = require('express');
const fetch = require('node-fetch');
require('dotenv').config();

const app = express();
app.use(express.json());

// CORS
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://yourdomain.com');
  res.header('Access-Control-Allow-Methods', 'POST');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

// Proxy endpoint
app.post('/rpc', async (req, res) => {
  try {
    const response = await fetch(
      `https://nexus.fortiblox.com/rpc?api-key=${process.env.FORTIBLOX_API_KEY}`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(req.body)
      }
    );

    const data = await response.json();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: 'Proxy error' });
  }
});

app.listen(3000, () => console.log('Proxy running on port 3000'));
// src/index.js
export default {
  async fetch(request, env) {
    // CORS preflight
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': 'https://yourdomain.com',
          'Access-Control-Allow-Methods': 'POST',
          'Access-Control-Allow-Headers': 'Content-Type'
        }
      });
    }

    // Only allow POST
    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }

    try {
      // Forward to FortiBlox
      const response = await fetch(
        `https://nexus.fortiblox.com/rpc?api-key=${env.FORTIBLOX_API_KEY}`,
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: await request.text()
        }
      );

      // Return response with CORS
      return new Response(await response.text(), {
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': 'https://yourdomain.com'
        }
      });
    } catch (error) {
      return new Response(
        JSON.stringify({ error: 'Proxy error' }),
        { status: 500, headers: { 'Content-Type': 'application/json' } }
      );
    }
  }
};

Support

Questions about the RPC Proxy?