QuotaGuard and Gigalixir Integration Guide
QuotaGuard Static IPs allow your Gigalixir applications 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. Gigalixir supports Elixir, Node, Python, Ruby, and Go, and this works across all of them.
You do not need QuotaGuard for internal Gigalixir clustering. Distributed Erlang clustering with libcluster runs over Gigalixir’s internal network and is unaffected. QuotaGuard handles outbound traffic to external services that require a known, static source IP.
Why Gigalixir Apps Need Static IPs
Gigalixir runs your app in containers with dynamically assigned IP addresses, so outbound traffic leaves from an address that changes. Gigalixir offers Dedicated Ingress for static inbound IPs, such as apex domains and webhook receivers, but that is inbound only. It does not give you a static outbound egress IP. Gigalixir’s own documentation recommends QuotaGuard for outbound static IPs.
Common scenarios where you need a static outbound IP:
- MongoDB Atlas: Requires IP allowlisting in Network Access settings
- Amazon RDS and managed Postgres: Security groups with IP-based rules
- Payment and banking APIs: Only accept requests from registered IPs
- Partner APIs: Corporate firewalls that require known source addresses
- Legacy systems: On-premise databases and ERPs with strict firewall policies
Getting Started
After creating a QuotaGuard account, you are redirected to your dashboard, where you can find your proxy credentials and two static IP addresses.
Choose the right proxy region: Select the QuotaGuard region closest to where your Gigalixir app runs to minimize latency. The region is set at sign-up. Changes after sign-up require contacting support.
Your proxy URL looks like this:
http://username:password@<your-quotaguard-proxy-host>:9293
Configuring Your Application
Step 1: Add Your Proxy URL as a Config Variable
Store your QuotaGuard credentials as a Gigalixir config variable. Keep them out of your Git repository.
gigalixir config:set QUOTAGUARDSTATIC_URL="http://username:password@<your-quotaguard-proxy-host>:9293"
Verify it was set:
gigalixir config
You should see QUOTAGUARDSTATIC_URL in the list.
For Elixir Releases: config variables are available as OS environment variables at runtime. Read them in config/runtime.exs so they are evaluated when the release boots, not at compile time:
# config/runtime.exs
config :my_app, :proxy_url, System.get_env("QUOTAGUARDSTATIC_URL")
Step 2: Configure Your HTTP Client
Route the outbound calls that need a static IP through the proxy. The Elixir clients are below, followed by Node, Python, Ruby, and Go for polyglot Gigalixir apps.
Elixir (Req)
proxy_url = System.get_env("QUOTAGUARDSTATIC_URL")
uri = URI.parse(proxy_url)
Req.get!("https://api.example.com/data",
connect_options: [
proxy: {:http, uri.host, uri.port, []},
proxy_headers: [{"proxy-authorization", "Basic " <> Base.encode64(uri.userinfo)}]
]
)
Req runs on Finch and Mint, so the proxy is a {:http, host, port, opts} tuple, not a URL string, and the credentials go in proxy_headers.
Elixir (HTTPoison)
proxy_url = System.get_env("QUOTAGUARDSTATIC_URL")
uri = URI.parse(proxy_url)
[username, password] = String.split(uri.userinfo, ":")
options = [
proxy: {String.to_charlist(uri.host), uri.port},
proxy_auth: {String.to_charlist(username), String.to_charlist(password)}
]
{:ok, response} = HTTPoison.get("https://api.example.com/data", [], options)
IO.inspect(response.body)
Elixir (Finch)
# In your application supervision tree
proxy_url = System.get_env("QUOTAGUARDSTATIC_URL")
uri = URI.parse(proxy_url)
Finch.start_link(
name: MyFinch,
pools: %{
:default => [
conn_opts: [
proxy: {:http, uri.host, uri.port, []},
proxy_headers: [{"proxy-authorization", "Basic " <> Base.encode64(uri.userinfo)}]
]
]
}
)
Elixir (Tesla with Hackney adapter)
proxy_url = System.get_env("QUOTAGUARDSTATIC_URL")
uri = URI.parse(proxy_url)
[user, pass] = String.split(uri.userinfo, ":")
client = Tesla.client([], {Tesla.Adapter.Hackney, [
proxy: {uri.host, uri.port},
proxy_auth: {user, pass}
]})
Tesla.get(client, "https://api.example.com/data")
Requires the hackney dependency.
Node.js (axios with https-proxy-agent)
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const agent = new HttpsProxyAgent(process.env.QUOTAGUARDSTATIC_URL);
axios.get('https://api.example.com/data', { httpsAgent: agent })
.then(response => console.log(response.data));
Install the agent: npm install https-proxy-agent
Python (requests)
import os, requests
proxy_url = os.environ['QUOTAGUARDSTATIC_URL']
proxies = {'http': proxy_url, 'https': proxy_url}
response = requests.get('https://api.example.com/data', proxies=proxies)
print(response.json())
Ruby (Net::HTTP)
require 'net/http'
require 'uri'
proxy = URI.parse(ENV['QUOTAGUARDSTATIC_URL'])
http = Net::HTTP.new('api.example.com', 443, proxy.host, proxy.port, proxy.user, proxy.password)
http.use_ssl = true
puts http.get('/data').body
Go
proxyURL, _ := url.Parse(os.Getenv("QUOTAGUARDSTATIC_URL"))
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}
resp, _ := client.Get("https://api.example.com/data")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Connecting to Firewalled Databases with QGTunnel
For database connections such as PostgreSQL, MySQL, or MongoDB, use QuotaGuard’s SOCKS5 proxy through QGTunnel. QGTunnel transparently routes your Ecto traffic through your static IPs without changing your connection code.
Step 1: Add QGTunnel to Your Release
Download QGTunnel and include it in your release overlay so it ships inside the container:
mkdir -p rel/overlays/bin
curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz -C rel/overlays
This places bin/qgtunnel and vendor/nss_wrapper/ into your release.
Step 2: Prefix Your Start Command
Gigalixir reads a Procfile to determine the start command. Prefix it with bin/qgtunnel so the tunnel starts before your app:
web: bin/qgtunnel bin/my_app start
Step 3: Configure the Tunnel in the Dashboard
In the QuotaGuard dashboard, go to Setup > QGTunnel Configuration > Create a Tunnel.
Example PostgreSQL configuration:
| Setting | Value |
|---|---|
| Remote Destination | tcp://your-database.example.com:5432 |
| Local Port | 5432 |
| Transparent | true |
| Encrypted | false |
Transparent mode overrides DNS so Ecto connects to the original database hostname while traffic routes through your static IPs. QGTunnel reads QUOTAGUARDSTATIC_URL automatically, so no code change is needed in your Repo config.
The SOCKS5 proxy is on port 1080 if you prefer to configure a driver directly instead of using QGTunnel.
Testing Your Implementation
From Your Local Machine
curl -x "$QUOTAGUARDSTATIC_URL" https://ip.quotaguard.com
Expected response:
{"ip":"<one of your two QuotaGuard static IPs>"}
The returned IP should match one of the two static IPs in your QuotaGuard dashboard. Run it more than once to see both IPs (load-balanced).
From Inside Your Running App
Add a temporary route or run it in a remote console to confirm the proxy works from the deployed container, not just locally.
proxy_url = System.get_env("QUOTAGUARDSTATIC_URL")
{:ok, resp} = Req.get("https://ip.quotaguard.com", connect_options: [proxy: proxy_url])
IO.inspect(resp.body)
Open a remote console against your running app with gigalixir ps:remote_console -a my-app and run the snippet. The IP returned must be one of your two static IPs.
Latency Considerations
Routing through QuotaGuard adds one network hop:
| Configuration | Added Latency |
|---|---|
| Same region (app and proxy co-located) | 10-20ms |
| Cross-region | 50-100ms |
Select a QuotaGuard region that matches your Gigalixir deployment region to keep this minimal.
Troubleshooting
407 Proxy Authentication Required
Your credentials are wrong. Confirm the config variable:
gigalixir config
Check that the username and password match your QuotaGuard dashboard exactly.
Connection Timeout
- Confirm your app can reach external networks.
- Check the proxy hostname is correct.
- Ensure nothing blocks outbound connections to port 9293.
Wrong IP Address Returned
The proxy is not being applied to the request.
- Confirm the env var is read at runtime, not compile time (
config/runtime.exs, notconfig.exs). - Check you are passing the proxy to the specific request, not only setting an environment variable.
- Some Elixir HTTP clients require explicit per-request proxy options, as shown above.
Config Not Available at Boot
Elixir Releases evaluate config/runtime.exs at boot and config/config.exs at compile time. If you read QUOTAGUARDSTATIC_URL in compile-time config, it will be missing. Move it to config/runtime.exs.
QGTunnel Not Starting
- Confirm
bin/qgtunnelis in your release overlay and is executable. - Confirm
QUOTAGUARDSTATIC_URLis set as a config variable. - Enable debug logging:
gigalixir config:set QGTUNNEL_DEBUG="true"
Then check logs:
gigalixir logs | grep qgtunnel
Clustering Stopped Working
It should not. QuotaGuard only handles the outbound calls you route through it. If clustering broke, you are routing internal libcluster traffic through the proxy by mistake. Apply the proxy per external request rather than forcing all traffic through it.
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 | $19/month | $29/month |
For most Gigalixir apps, Static is the right product. Choose QuotaGuard Shield if your app handles regulated data or your environment requires TLS between your app and the proxy itself.
Ready to Get Started?
Get in touch or create a free trial account.
View Gigalixir Integration Features
Read: How to Get a Static IP for Gigalixir Apps