QuotaGuard and Elastic Cloud Integration Guide

QuotaGuard Static IPs let your cloud application reach an Elastic Cloud deployment protected by an IP filter. You add the two static IPs assigned to your subscription to a network security policy, and every request arrives from a known address no matter which platform your app runs on.

You do not need QuotaGuard for local development or for infrastructure with stable IPs. This guide is for applications on Heroku, Render, Railway, Fly.io, Vercel, AWS Lambda, Google Cloud Run, Kubernetes, and other platforms where outbound IPs are dynamic.

Elasticsearch is reached over HTTPS, so this integration uses QuotaGuard’s HTTP proxy on port 9293. There is no tunnel to configure and no SOCKS5 client library required.

The Problem: An IP Filter Needs an Address You Cannot Pin Down

Elastic’s documentation states that by default, deployments in Elastic Cloud Hosted and Elastic Cloud Serverless are accessible over the public internet without restrictions. Once you associate at least one network security policy with a deployment, traffic that does not match that policy or any other policy on the resource is denied.

Elastic also notes that network security policies were formerly called traffic filter rules, so you will encounter both names depending on which document or API you are reading.

That restriction is the control your security review asks for. On a platform with rotating egress IPs there is no stable CIDR to enter.

Rejected requests come back as 403 Forbidden with a body indicating the request was blocked by traffic filtering, rather than an authentication error. That distinction is the fastest diagnostic you have. A 401 means you reached the cluster and your credentials were wrong. A 403 mentioning filtering means the proxy layer stopped you before the cluster ever saw the request.

The Common Workaround

The usual response is to leave the deployment open to the internet and rely on the API key or the username and password alone.

Elasticsearch clusters routinely hold log data, customer records, search indexes over proprietary content, and increasingly vector embeddings of internal documents. Leaving the endpoint publicly reachable means a leaked API key is complete access from anywhere.

The QuotaGuard Solution

Route your Elasticsearch requests through QuotaGuard’s HTTP proxy. They exit from one of the two static IP addresses assigned to your subscription. Add those two addresses to an IP filter policy and attach it to the deployment.

  • Network-level protection that works on a platform with no fixed egress
  • The same two IPs cover every service in your stack
  • Adding a worker on Fly.io or moving off Heroku changes nothing on the Elastic side
  • A leaked API key is no longer sufficient on its own

Native Elastic Cloud Options (What They Cover)

Option Availability Best for
IP filter policy Elastic Cloud Hosted deployments and Elasticsearch Serverless projects, no specific tier requirement Any application that can present a stable source address
Private connections ECH supports AWS PrivateLink, Azure Private Link, and GCP Private Service Connect. Serverless supports AWS PrivateLink only Teams already inside a matching cloud who want to bypass the public internet
Egress or outbound IP filters API only, not exposed in the console Restricting what your deployment can reach, the opposite direction from this guide

Three details worth knowing before you start.

Elastic’s documentation states there are no specific tier requirements for Elastic Cloud Hosted deployments or Elasticsearch Serverless projects. Observability projects require the Observability Complete feature tier, and Security projects require the Security Analytics Complete feature tier.

Policies are created at the organization level and then applied at the deployment level. Creating one does nothing until you attach it to a resource.

In Elastic Cloud Hosted deployments, IP filters do not apply to the managed OTLP endpoint. If you ship telemetry through that endpoint, the filter will not cover it.

Use QuotaGuard when:

  • Your application runs on a platform with dynamic egress IPs you cannot enumerate
  • Your platform has no private link option, which covers Heroku, Render, Railway, Vercel, and most serverless runtimes
  • Your stack spans several platforms and you want one pair of entries for all of them
  • You want the IP filter on today without a networking project
  • You need the same static identity for other destinations too, not just Elastic

Getting Started

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

Choose the right proxy region. Match your QuotaGuard region to the cloud region hosting your Elastic Cloud deployment.

QuotaGuard proxies run in 12 AWS regions:

Region Location
US-East-1 N. Virginia
US-East-2 Ohio
US-West-2 Oregon
CA-Central-1 Montreal
EU-West-1 Ireland
EU-West-2 London
EU-Central-1 Frankfurt
AP-Northeast-1 Tokyo
AP-Southeast-1 Singapore
AP-Southeast-2 Sydney
AP-South-1 Mumbai
SA-East-1 Sao Paulo

Your deployment’s region is shown in the Elastic Cloud Console and is encoded in the endpoint hostname. Pick the matching QuotaGuard region, or the nearest available one, from the region list in your dashboard.

Your proxy URL will look like this:

http://username:password@<region>-static-01.quotaguard.com:9293

For example, http://username:password@us-east-static-01.quotaguard.com:9293. Use the exact QUOTAGUARDSTATIC_URL value shown in your dashboard, not a hostname assembled by hand.

Finding your static IPs: both addresses are shown in the QuotaGuard dashboard. Add both. The dashboard pair is the single source of truth. Do not resolve the proxy hostname to obtain an address, and do not add only one of the two.

Configuring the Elastic Cloud IP Filter

Step 1: Create the Policy at the Organization Level

  1. Log in to the Elastic Cloud Console
  2. From the navigation menu, select Security > Network security
  3. Create a new IP filter policy, giving it a name you will recognize later, such as QuotaGuard static IPs

Step 2: Add Your QuotaGuard IPs

Add both static IPs from your QuotaGuard dashboard as rules. Elastic accepts individual IP addresses and CIDR blocks:

203.0.113.10/32
203.0.113.11/32

Substitute the actual addresses shown in your dashboard. DNS names are not supported in IP filter rules.

Decide whether to mark the policy as applied by default. A default policy attaches automatically to new deployments you create in its region, and does not attach retroactively to existing ones.

Step 3: Attach the Policy to Your Deployment

  1. On the Hosted deployments page, select your deployment
  2. Select the Security tab in the left-hand menu
  3. Under Network security, select Apply policies and choose your IP filter

The policy takes effect only once it is attached. Creating it in step 1 changes nothing on its own.

Step 4: Add Any Other Sources Before You Rely on It

Once at least one policy is attached, everything not matching a policy on that deployment is denied. If you also connect from an office network, a CI runner, or a bastion host, cover those sources too.

Elastic notes that multiple policies can be attached to one deployment, and traffic matching any of them is allowed. That makes it clean to keep your QuotaGuard pair in one policy and your office ranges in another, rather than maintaining a single combined list.

Step 5: Verify Before You Lock Down

Confirm a successful request through the proxy before you treat the filter as your access control. Attach the policy, deploy the proxy configuration, confirm the application connects, then finish tightening.

If you make a mistake in the address, the deployment locks out all of your traffic. You can still adjust or remove the policy from the console, so this is recoverable, but it is an outage while you do it.

Configuring Your Application

Elasticsearch on Elastic Cloud is served over HTTPS, typically on port 9243. That means the standard HTTP proxy handles it. Set QUOTAGUARDSTATIC_URL and point your client’s proxy or agent option at it.

Because the proxy tunnels HTTPS with CONNECT rather than terminating it, your Elasticsearch credentials and query payloads are not decrypted at the proxy, and certificate verification against the Elastic hostname works normally.

Node.js with @elastic/elasticsearch

npm install @elastic/elasticsearch https-proxy-agent
const { Client } = require('@elastic/elasticsearch');
const { HttpsProxyAgent } = require('https-proxy-agent');

const agent = new HttpsProxyAgent(process.env.QUOTAGUARDSTATIC_URL);

const client = new Client({
  node: process.env.ELASTIC_URL,
  auth: { apiKey: process.env.ELASTIC_API_KEY },
  agent: () => agent,
});

client.info()
  .then((res) => console.log('Connected to Elastic Cloud through QuotaGuard:', res.version.number))
  .catch((err) => console.error('Connection failed:', err.message));

Recent versions of the client also accept a proxy option directly on ClientOptions, which is cleaner than supplying an agent. Check the client version you have pinned before choosing between them.

Python with elasticsearch-py

pip install elasticsearch
import os
from elasticsearch import Elasticsearch

es = Elasticsearch(
    os.environ["ELASTIC_URL"],
    api_key=os.environ["ELASTIC_API_KEY"],
    node_class="requests",
)

print("Connected to Elastic Cloud through QuotaGuard:", es.info()["version"]["number"])

With the requests transport, the standard HTTP_PROXY and HTTPS_PROXY environment variables are honored, so set HTTPS_PROXY to your QUOTAGUARDSTATIC_URL value in your platform’s config and no code change is needed.

Transport configuration changed between elasticsearch-py 7.x and 8.x, which moved to elastic-transport. Confirm the proxy behavior on the version you have pinned rather than assuming it carries over.

Go with go-elasticsearch

Go’s standard http.Transport takes a proxy function, and the Elasticsearch client accepts a custom transport.

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"

	"github.com/elastic/go-elasticsearch/v8"
)

func main() {
	proxyURL, err := url.Parse(os.Getenv("QUOTAGUARDSTATIC_URL"))
	if err != nil {
		log.Fatal("parse proxy url:", err)
	}

	cfg := elasticsearch.Config{
		Addresses: []string{os.Getenv("ELASTIC_URL")},
		APIKey:    os.Getenv("ELASTIC_API_KEY"),
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		},
	}

	es, err := elasticsearch.NewClient(cfg)
	if err != nil {
		log.Fatal("client:", err)
	}

	res, err := es.Info()
	if err != nil {
		log.Fatal("info:", err)
	}
	defer res.Body.Close()

	fmt.Println("Connected to Elastic Cloud through QuotaGuard:", res.Status())
}

http.ProxyURL carries the credentials embedded in the URL, so no separate authentication step is needed.

Java with the Elasticsearch Java client

The low-level REST client exposes the underlying Apache HTTP client, which takes a proxy directly.

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;

import java.net.URI;

URI proxy = URI.create(System.getenv("QUOTAGUARDSTATIC_URL"));
String[] userInfo = proxy.getUserInfo().split(":", 2);

BasicCredentialsProvider credentials = new BasicCredentialsProvider();
credentials.setCredentials(
    new AuthScope(proxy.getHost(), proxy.getPort()),
    new UsernamePasswordCredentials(userInfo[0], userInfo[1])
);

RestClient restClient = RestClient
    .builder(HttpHost.create(System.getenv("ELASTIC_URL")))
    .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
        .setProxy(new HttpHost(proxy.getHost(), proxy.getPort()))
        .setDefaultCredentialsProvider(credentials))
    .build();

Add your Elasticsearch authentication to the same builder alongside the proxy credentials.

Ruby with elasticsearch-ruby

require 'elasticsearch'

client = Elasticsearch::Client.new(
  host: ENV['ELASTIC_URL'],
  api_key: ENV['ELASTIC_API_KEY'],
  transport_options: {
    proxy: ENV['QUOTAGUARDSTATIC_URL']
  }
)

puts "Connected to Elastic Cloud through QuotaGuard: #{client.info['version']['number']}"

PHP with elasticsearch-php

<?php
use Elastic\Elasticsearch\ClientBuilder;

$client = ClientBuilder::create()
    ->setHosts([getenv('ELASTIC_URL')])
    ->setApiKey(getenv('ELASTIC_API_KEY'))
    ->setHttpClientOptions([
        'proxy' => getenv('QUOTAGUARDSTATIC_URL'),
    ])
    ->build();

$info = $client->info();
echo "Connected to Elastic Cloud through QuotaGuard\n";

The exact option name depends on which PSR-18 HTTP client the library is configured with. Confirm against your installed client if the source address does not change.

curl

Useful for a fast check before touching application code:

curl -x "$QUOTAGUARDSTATIC_URL" \
  -H "Authorization: ApiKey $ELASTIC_API_KEY" \
  "$ELASTIC_URL"

A 200 with cluster information means the proxy and the filter are both configured correctly. A 403 mentioning traffic filtering means the request reached Elastic but the address was not on an attached policy.

Testing Your Implementation

Confirm the Outbound IP

Before testing against Elastic, confirm the proxy is actually in the path:

curl -x "$QUOTAGUARDSTATIC_URL" https://ip.quotaguard.com

The returned address should match one of the two in your QuotaGuard dashboard. Run it several times and both should appear.

Confirm the Filter Is Doing Something

The useful test is the negative one. Make the same request without the proxy:

curl "$ELASTIC_URL" -H "Authorization: ApiKey $ELASTIC_API_KEY"

This should fail with a 403 referencing traffic filtering. If it succeeds, the policy is either not attached to the deployment or contains a range wide enough to include your current address, and you do not yet have the protection you think you have.

A request that succeeds through the proxy is only half the confirmation. A request that fails without it is the other half.

Latency Considerations

Routing through a proxy adds a network hop to each request. Elasticsearch workloads vary widely in how much that matters.

  1. Match all three regions. Application, QuotaGuard proxy, and Elastic deployment in the same cloud region wherever possible.
  2. Reuse connections. Keep a long-lived client rather than constructing one per request, so TLS and proxy setup are not repeated. Every official Elasticsearch client pools connections by default. Do not defeat that by creating clients inside a request handler.
  3. Use the bulk API for indexing. One bulk request pays the hop once instead of once per document. This matters far more through a proxy than without one.
  4. Only proxy what needs a static IP. If your application also calls services with no IP restriction, leave those on a normal client without the proxy.

Measure against your own workload and region pairing rather than assuming a fixed figure.

Troubleshooting

403 Forbidden mentioning traffic filtering

The filter refused the request. In order:

  1. Confirm both QuotaGuard IPs are in the policy, not just one
  2. Confirm the addresses match your dashboard exactly
  3. Confirm the policy is attached to the deployment, not just created at the organization level. This is the most common miss.
  4. Confirm the request is actually going through the proxy using the IP check above

401 Unauthorized

An Elasticsearch credential error, not a filter or proxy problem. You reached the cluster. Check the API key or the username and password, and confirm the key has not expired or been revoked.

The proxy works for some code paths and not others

Most likely you configured the proxy on one client instance and other parts of the application construct their own. Search for every place a client is created. Kibana dashboards, background jobs, and health checks are common stragglers.

Requests succeed without the proxy too

The policy is not attached, or an attached policy includes a range covering your current address. Remember that multiple attached policies are evaluated as a match against any of them, so a permissive policy attached alongside your restrictive one leaves the deployment open.

Telemetry still arrives but application requests fail

Elastic’s documentation states that in Elastic Cloud Hosted deployments, IP filters do not apply to the managed OTLP endpoint. Traffic to that endpoint is not covered by your policy.

407 Proxy Authentication Required

  1. Confirm the secret holds the full URL including credentials
  2. Check for characters in the password that need URL encoding
  3. Confirm port 9293 for the HTTP proxy, not 1080

Certificate errors

The HTTP proxy tunnels HTTPS with CONNECT rather than terminating it, so certificate verification should behave exactly as it does without the proxy. If you see certificate errors that appear only with the proxy configured, check whether your client is treating the proxy URL as the request target rather than as a proxy.

Environment Variables Reference

# HTTP proxy (port 9293) - used for all Elasticsearch requests
QUOTAGUARDSTATIC_URL=http://username:password@<region>-static-01.quotaguard.com:9293

# Some clients read the standard proxy variables instead
HTTPS_PROXY=http://username:password@<region>-static-01.quotaguard.com:9293

# Your Elastic Cloud endpoint and credentials
ELASTIC_URL=https://<deployment>.es.<region>.<provider>.elastic-cloud.com:9243
ELASTIC_API_KEY=your-api-key

Use the exact values from your QuotaGuard dashboard and your Elastic Cloud Console.

Security Best Practices

  1. Attach the policy, do not just create it. A policy sitting at the organization level with no deployment association protects nothing.
  2. Add both static IPs. Adding one produces intermittent failures that are hard to diagnose.
  3. Keep separate policies for separate sources. Multiple attached policies are matched against any, so keeping your proxy pair and your office ranges in different policies makes each easy to remove without disturbing the other.
  4. Use API keys with least privilege. The IP filter controls where connections come from. Role-based access controls what they can do once connected.
  5. Never commit credentials. Use your platform’s secret storage for both the Elastic API key and the proxy URL.
  6. Rotate credentials periodically, on both the Elastic and QuotaGuard sides.

QuotaGuard Static vs QuotaGuard Shield

Feature QuotaGuard Static QuotaGuard Shield
Protocol HTTP / HTTPS / SOCKS5 HTTPS / SOCKS5 over TLS
Customer-to-proxy hop Plaintext TLS-encrypted
HTTPS payload Tunneled end-to-end, never decrypted at the proxy Tunneled end-to-end, never decrypted at the proxy
Best for Most apps Regulated data or environments that require TLS on every hop
Starting price (direct) $19/month $29/month

Your Elasticsearch queries and results travel inside the HTTPS tunnel in both cases and are never decrypted at the proxy. Static is right for most Elastic Cloud deployments.

Choose Shield if the cluster holds regulated data under HIPAA, PCI-DSS, or SOC 2, or if your environment requires TLS between your app and the proxy itself. This is worth a real look for Elastic specifically, because clusters holding application logs frequently contain more regulated data than anyone intended, and log pipelines are a common source of unplanned PHI and cardholder data exposure.


Ready to Get Started?

Lock your Elastic Cloud deployment to two addresses without locking out your own application.

Try QuotaGuard Now

Contact Support


Ready to Get Started?

Get in touch or create a free trial account

Back to top ↑

Copyright © 2009 - 2026 QuotaGuard. All rights reserved.

Copyright © 2009 - 2026 QuotaGuard. All rights reserved.