QuotaGuard and Netlify Integration Guide

    QuotaGuard and Netlify Integration Guide

    QuotaGuard Static IPs allow your Netlify Functions to send outbound traffic through a load-balanced pair of static IP addresses. Once set up, you can use QuotaGuard’s IPs to connect to firewalled databases and APIs that require IP allowlisting.

    Netlify offers two serverless compute options:

    Function TypeRuntimeBest For
    Netlify FunctionsNode.js 18+Backend logic, API calls, database connections
    Netlify Edge FunctionsDenoLow-latency personalization, A/B testing, geolocation

    This guide focuses on Netlify Functions (Node.js) as the recommended option for proxy usage. Edge Functions have known limitations with proxy configuration that we’ll address separately.

    You do not need QuotaGuard for internal Netlify operations. QuotaGuard is for connecting to external services that require a known, static source IP address.

    Why Netlify Functions Need Static IPs

    Netlify’s infrastructure uses dynamic, rotating IP addresses from AWS and Google Cloud pools. The platform explicitly states they do not publish outbound IP ranges because these addresses can change without notice.

    This creates problems when your functions need to connect to:

    • Payment providers like Line Pay, PayPal, or Stripe Connect that require IP whitelisting
    • MongoDB Atlas or other databases with IP-based network access controls
    • Azure SQL and Amazon RDS security groups
    • Google Workspace with Context-Aware Access policies
    • Enterprise firewalls that block unknown cloud IP ranges
    • Partner APIs with strict access controls

    The result is connection failures and 403 Forbidden errors that have nothing to do with your code. Your API keys are valid. Your function logic is correct. The target service is simply blocking requests from Netlify’s dynamic IP addresses.

    QuotaGuard gives your Netlify Functions a fixed, verifiable identity that partners can add to their firewall allowlists once.

    Native Private Connectivity vs QuotaGuard

    Netlify offers a Private Connectivity feature for static egress IPs. Here’s how it compares to QuotaGuard:

    FeatureNetlify Private ConnectivityQuotaGuard
    Plan requirementEnterprise onlyAny plan
    Setup processContact account managerSelf-service
    Serverless Functions supportYes (limited regions)Yes (all regions)
    Edge Functions supportNoYes (with caveats)
    Regions availableus-east-2, eu-central-1, eu-west-2 only10+ global regions
    IP allocationMultiple IPs per regionDedicated pair per account
    Add-ons requiredHigh-Performance Edge or BuildNone

    Use Private Connectivity if you’re on an Enterprise plan, only need Serverless Functions, and your target services are in supported regions.

    Use QuotaGuard if you’re on a free, pro, or business plan. Or if you need Edge Functions support, more regional options, or immediate self-service setup.

    Getting Started

    After creating a QuotaGuard account, you will be redirected to your dashboard where you can find your proxy credentials and static IP addresses.

    Choose the right proxy region: Netlify Functions run in a specific AWS region (configurable in site settings). Match your QuotaGuard region to minimize latency.

    Netlify Functions RegionQuotaGuard Region
    us-east-1 (default)US-East
    us-east-2US-East
    eu-central-1EU-Central (Frankfurt)
    ap-southeast-1AP-Southeast (Singapore)
    ap-southeast-2Australia (Sydney)

    To check or change your Netlify Functions region:

    1. Go to your site’s Site configuration
    2. Navigate to Functions settings
    3. Look for Region setting

    Your QuotaGuard proxy URL looks like this:

    http://username:password@us-east-static-01.quotaguard.com:9293
    

    Finding Your Static IPs: Your two static IPs are displayed in the QuotaGuard dashboard. Both IPs are active simultaneously for high availability. Add both to any firewall allowlists you’re configuring on the target service side.

    Configuring Netlify Functions (Node.js)

    Netlify Functions use Node.js 18+ which includes native fetch. However, native fetch requires a proxy agent for routing through QuotaGuard.

    Step 1: Add Your Proxy URL as an Environment Variable

    Using Netlify CLI:

    netlify env:set QUOTAGUARDSTATIC_URL "http://username:password@us-east-static-01.quotaguard.com:9293"
    

    Using Netlify UI:

    1. Go to your site’s Site configuration
    2. Navigate to Environment variables
    3. Click Add a variable
    4. Key: QUOTAGUARDSTATIC_URL
    5. Value: Your proxy URL from the QuotaGuard dashboard
    6. Scopes: Ensure Functions is selected

    Important: Netlify does not read .env files during builds. You must set environment variables through the CLI or UI.

    Step 2: Install the Proxy Agent

    Add the https-proxy-agent package to your project:

    npm install https-proxy-agent
    

    Or with yarn:

    yarn add https-proxy-agent
    

    Step 3: Configure Your Function

    Create your function in the netlify/functions/ directory.

    Basic GET Request

    // netlify/functions/api-call.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      
      if (!proxyUrl) {
        return new Response(
          JSON.stringify({ error: 'Proxy URL not configured' }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    
      const agent = new HttpsProxyAgent(proxyUrl);
    
      try {
        const response = await fetch('https://api.example.com/data', {
          agent: agent
        });
        
        const data = await response.json();
        
        return new Response(JSON.stringify(data), {
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response(
          JSON.stringify({ error: error.message }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    };
    

    POST Request with JSON Body

    // netlify/functions/submit-data.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      // Parse incoming request body
      const payload = await req.json();
    
      try {
        const response = await fetch('https://api.example.com/submit', {
          method: 'POST',
          agent: agent,
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${process.env.API_TOKEN}`
          },
          body: JSON.stringify(payload)
        });
    
        const result = await response.json();
        
        return new Response(JSON.stringify(result), {
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response(
          JSON.stringify({ error: error.message }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    };
    

    Error Handling Pattern

    // netlify/functions/robust-api-call.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      
      if (!proxyUrl) {
        console.error('QUOTAGUARDSTATIC_URL not configured');
        return new Response(
          JSON.stringify({ error: 'Proxy configuration missing' }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    
      const agent = new HttpsProxyAgent(proxyUrl);
    
      try {
        const response = await fetch('https://api.example.com/data', {
          agent: agent,
          headers: {
            'Authorization': `Bearer ${process.env.API_KEY}`
          }
        });
    
        if (!response.ok) {
          console.error(`API returned ${response.status}: ${await response.text()}`);
          return new Response(
            JSON.stringify({ error: `Upstream API error: ${response.status}` }),
            { status: response.status, headers: { 'Content-Type': 'application/json' } }
          );
        }
    
        const data = await response.json();
        
        return new Response(JSON.stringify(data), {
          headers: { 'Content-Type': 'application/json' }
        });
    
      } catch (error) {
        console.error('Request failed:', error);
        
        if (error.message.includes('407')) {
          return new Response(
            JSON.stringify({ error: 'Proxy authentication failed' }),
            { status: 500, headers: { 'Content-Type': 'application/json' } }
          );
        }
        
        return new Response(
          JSON.stringify({ error: 'Request failed' }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    };
    

    Background Function Example

    For long-running operations, use Netlify’s background functions (append -background to the filename):

    // netlify/functions/sync-data-background.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      // This runs for up to 15 minutes instead of 10 seconds
      const records = await fetchAllRecords();
      
      for (const record of records) {
        await fetch('https://partner-api.example.com/sync', {
          method: 'POST',
          agent: agent,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(record)
        });
      }
      
      console.log(`Synced ${records.length} records`);
    };
    

    Using Axios Instead of Fetch

    If you prefer axios:

    // netlify/functions/axios-example.mjs
    import axios from 'axios';
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      try {
        const response = await axios.get('https://api.example.com/data', {
          httpsAgent: agent,
          headers: {
            'Authorization': `Bearer ${process.env.API_KEY}`
          }
        });
    
        return new Response(JSON.stringify(response.data), {
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response(
          JSON.stringify({ error: error.message }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    };
    

    Install axios: npm install axios

    Configuring Netlify Edge Functions (Deno)

    Important: As of January 2026, there are known issues with Deno.createHttpClient in Netlify’s production Edge runtime. The Netlify team is investigating these issues. For production proxy use cases, we recommend using Netlify Functions (Node.js) instead.

    If you need to experiment with Edge Functions proxy configuration:

    // netlify/edge-functions/api-call.ts
    export default async (req: Request, context: Context) => {
      const proxyUrl = Deno.env.get('QUOTAGUARDSTATIC_URL');
      
      if (!proxyUrl) {
        return new Response(
          JSON.stringify({ error: 'Proxy not configured' }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    
      const url = new URL(proxyUrl);
      
      // Note: Deno.createHttpClient may not work reliably in Netlify's Edge runtime
      const client = Deno.createHttpClient({
        proxy: {
          url: `${url.protocol}//${url.host}`,
          basicAuth: {
            username: url.username,
            password: url.password,
          },
        },
      });
    
      try {
        const response = await fetch('https://api.example.com/data', { client });
        const data = await response.json();
        
        return new Response(JSON.stringify(data), {
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response(
          JSON.stringify({ error: error.message }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      } finally {
        client.close();
      }
    };
    

    Recommendation: If your Edge Function needs to call IP-restricted APIs, consider restructuring your application to:

    1. Have the Edge Function call a Netlify Serverless Function
    2. The Serverless Function makes the proxied external API call
    3. The result is returned through the Edge Function to the client

    This adds latency but provides reliable proxy support.

    Database Connections (SOCKS5)

    For non-HTTP protocols like PostgreSQL, MySQL, or MongoDB native drivers, use QuotaGuard’s SOCKS5 proxy on port 1080.

    Limitations in Netlify Functions

    Netlify Functions are serverless and ephemeral. Each invocation starts fresh with no persistent connections. This creates challenges for database connections:

    1. Connection must open, execute, and close within Netlify’s timeout limits (10 seconds default, 26 seconds max for synchronous functions)
    2. Connection pooling is not possible between invocations
    3. Cold starts add additional latency

    Use HTTP/REST APIs when available:

    Many databases offer HTTP APIs that work with the standard proxy configuration:

    • MongoDB Atlas Data API
    • Supabase REST API
    • PlanetScale HTTP API
    • Neon serverless driver

    Example: MongoDB Atlas Data API

    // netlify/functions/mongo-query.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      const query = {
        dataSource: 'Cluster0',
        database: 'mydb',
        collection: 'users',
        filter: { status: 'active' }
      };
    
      const response = await fetch(
        'https://data.mongodb-api.com/app/data-xxxxx/endpoint/data/v1/action/find',
        {
          method: 'POST',
          agent: agent,
          headers: {
            'Content-Type': 'application/json',
            'api-key': process.env.MONGODB_API_KEY
          },
          body: JSON.stringify(query)
        }
      );
    
      const result = await response.json();
      
      return new Response(JSON.stringify(result.documents), {
        headers: { 'Content-Type': 'application/json' }
      });
    };
    

    For native database connections:

    If you must use native database drivers with SOCKS5, consider using a longer-running compute option like Netlify’s background functions or a dedicated service on a platform that supports QGTunnel (Heroku, Render, Fly.io).

    Testing Your Implementation

    Local Testing with Netlify Dev

    Test locally before deploying:

    # Set the environment variable locally
    netlify env:set QUOTAGUARDSTATIC_URL "http://username:password@us-east-static-01.quotaguard.com:9293" --context dev
    
    # Start the local dev server
    netlify dev
    

    Then test your function at http://localhost:8888/.netlify/functions/your-function-name

    Test Function to Verify Proxy

    Create a simple test function:

    // netlify/functions/test-proxy.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      
      if (!proxyUrl) {
        return new Response(
          JSON.stringify({ error: 'QUOTAGUARDSTATIC_URL not set' }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    
      const agent = new HttpsProxyAgent(proxyUrl);
    
      try {
        // ip.quotaguard.com returns the client's IP address
        const response = await fetch('https://ip.quotaguard.com', { agent });
        const data = await response.json();
    
        return new Response(
          JSON.stringify({
            your_static_ip: data.ip,
            proxy_working: true
          }),
          { headers: { 'Content-Type': 'application/json' } }
        );
      } catch (error) {
        return new Response(
          JSON.stringify({
            error: error.message,
            proxy_working: false
          }),
          { status: 500, headers: { 'Content-Type': 'application/json' } }
        );
      }
    };
    

    Deploy and invoke:

    netlify deploy --prod
    curl https://your-site.netlify.app/.netlify/functions/test-proxy
    

    Expected response:

    {
      "your_static_ip": "52.34.188.175",
      "proxy_working": true
    }
    

    The returned IP should match one of your two static IPs shown in the QuotaGuard dashboard. Run it multiple times to see both IPs in action (load-balanced).

    Latency Considerations

    Using QuotaGuard adds a network hop to your requests:

    ConfigurationAdded Latency
    Same region (Netlify us-east-1 + QuotaGuard US-East)10-30ms
    Cross-region50-100ms

    Selective Proxying

    Only proxy requests that require static IPs. Keep non-firewalled API calls using standard fetch without the proxy:

    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      // Non-proxied request to public API (faster)
      const publicData = await fetch('https://api.publicservice.com/data');
      
      // Proxied request to firewalled API (needs static IP)
      const privateData = await fetch('https://partner.firewalled.com/secure', {
        agent: agent
      });
      
      return new Response(JSON.stringify({
        public: await publicData.json(),
        private: await privateData.json()
      }), {
        headers: { 'Content-Type': 'application/json' }
      });
    };
    

    Edge Functions Tradeoff

    Edge Functions are designed for global low-latency execution. Adding a proxy may negate these benefits because:

    1. Traffic routes through QuotaGuard’s infrastructure instead of the nearest edge
    2. The proxy adds a network hop regardless of edge location

    For latency-sensitive operations that also require static IPs, consider whether Serverless Functions in a single region might be more predictable than Edge Functions with a proxy.

    Troubleshooting

    407 Proxy Authentication Required

    Your proxy credentials are incorrect. Verify:

    1. The environment variable is set correctly:
      netlify env:list
      
    2. The URL format includes credentials:
      http://username:password@us-east-static-01.quotaguard.com:9293
      
    3. Check for special characters in your password that may need URL encoding.

    Connection Timeout

    1. Verify the QuotaGuard proxy hostname is correct (check your dashboard)
    2. Ensure port 9293 is used for HTTP proxy connections
    3. Check if the target service is reachable from QuotaGuard’s infrastructure
    4. Increase function timeout in netlify.toml if needed:
    [functions]
      node_bundler = "esbuild"
    
    [functions."your-function-name"]
      timeout = 26
    

    Wrong IP Address Returned

    If ip.quotaguard.com returns an unexpected IP:

    1. Verify the proxy agent is being passed to the fetch call
    2. Check that you’re not accidentally using a non-proxied fetch
    3. Ensure the environment variable scope includes “Functions”

    Edge Functions Proxy Not Working

    This is a known limitation. As of January 2026, Deno.createHttpClient may not work reliably in Netlify’s production Edge runtime.

    Solution: Use Netlify Serverless Functions (Node.js) instead of Edge Functions for proxy use cases.

    Module Not Found: https-proxy-agent

    Ensure the package is in your package.json dependencies (not devDependencies) and committed to your repository:

    npm install https-proxy-agent --save
    git add package.json package-lock.json
    git commit -m "Add https-proxy-agent for QuotaGuard proxy"
    

    Environment Variable Not Available

    1. Verify the variable scope includes “Functions” in the Netlify UI
    2. Environment variables set via CLI may take a few minutes to propagate
    3. Redeploy your site after adding new environment variables

    Common Use Cases

    Payment Provider Integrations

    Payment APIs often require IP allowlisting for security:

    // netlify/functions/process-payment.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
      const payload = await req.json();
    
      const response = await fetch('https://api.paymentprovider.com/v1/charges', {
        method: 'POST',
        agent: agent,
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.PAYMENT_API_KEY}`
        },
        body: JSON.stringify({
          amount: payload.amount,
          currency: 'USD',
          source: payload.token
        })
      });
    
      const result = await response.json();
      
      return new Response(JSON.stringify(result), {
        headers: { 'Content-Type': 'application/json' }
      });
    };
    

    Webhook Delivery to Firewalled Endpoints

    When your function needs to deliver webhooks to systems with IP restrictions:

    // netlify/functions/send-webhook.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    import crypto from 'crypto';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
      const event = await req.json();
    
      const signature = crypto
        .createHmac('sha256', process.env.WEBHOOK_SECRET)
        .update(JSON.stringify(event))
        .digest('hex');
    
      const response = await fetch('https://partner.example.com/webhooks/receive', {
        method: 'POST',
        agent: agent,
        headers: {
          'Content-Type': 'application/json',
          'X-Webhook-Signature': signature
        },
        body: JSON.stringify(event)
      });
    
      if (!response.ok) {
        console.error(`Webhook delivery failed: ${response.status}`);
        return new Response('Webhook delivery failed', { status: 500 });
      }
    
      return new Response('OK', { status: 200 });
    };
    

    Enterprise API Integration

    Connecting to corporate APIs behind firewalls:

    // netlify/functions/enterprise-sync.mjs
    import { HttpsProxyAgent } from 'https-proxy-agent';
    
    export default async (req, context) => {
      const proxyUrl = process.env.QUOTAGUARDSTATIC_URL;
      const agent = new HttpsProxyAgent(proxyUrl);
    
      const response = await fetch('https://api.enterprise-partner.com/v2/data', {
        agent: agent,
        headers: {
          'X-API-Key': process.env.ENTERPRISE_API_KEY,
          'X-Client-ID': process.env.ENTERPRISE_CLIENT_ID
        }
      });
    
      if (!response.ok) {
        return new Response(
          JSON.stringify({ error: `API error: ${response.status}` }),
          { status: response.status, headers: { 'Content-Type': 'application/json' } }
        );
      }
    
      const data = await response.json();
      
      return new Response(JSON.stringify(data), {
        headers: { 'Content-Type': 'application/json' }
      });
    };
    

    QuotaGuard Static vs QuotaGuard Shield

    QuotaGuard offers two products for static IPs:

    FeatureQuotaGuard StaticQuotaGuard Shield
    ProtocolHTTP/SOCKS5HTTPS/SOCKS5 over TLS
    EncryptionStandard proxySSL Passthrough (E2EE)
    Best forGeneral API accessHIPAA, PCI-DSS, regulated data
    Starting price$19/month$69/month

    For most Netlify Functions, QuotaGuard Static provides everything you need. Choose Shield if you’re handling protected health information (PHI), payment card data, or have specific compliance requirements where even the proxy provider must not be able to inspect traffic.


    Ready to Get Started?

    Get in touch or create a free trial account.

    Try QuotaGuard Now

    View Netlify Integration Features

    Contact Support


    Ready to Get Started?

    Get in touch or create a free trial account