Skip to content
Fixedmark
Integration · Serverless and edge functions

AWS Lambda Static IP Without a NAT Gateway

AWS Lambda functions outside a VPC use AWS-owned IPs that change. The native fix is to put the function in private subnets behind a NAT Gateway with an Elastic IP, which costs about $73 a month across two Availability Zones before any traffic. A Fixedmark proxy URL gives the same function a dedicated IP pair with no VPC changes.

Why Lambda's outbound IP changes

A Lambda function that is not attached to your VPC runs in a Lambda-managed network with internet access. Its outbound address comes from AWS's shared regional ranges and changes as execution environments are created and recycled. AWS publishes those ranges, but they cover every customer in the region.

The native route: VPC and NAT Gateway

To give Lambda a fixed IP on AWS alone, you attach the function to private subnets, route 0.0.0.0/0 to a NAT Gateway, and give the gateway an Elastic IP. In us-east-1, a NAT Gateway costs $0.045 per hour plus $0.045 per GB processed, and each public IPv4 address costs $0.005 per hour. One gateway is about $32.85 a month before traffic. High availability needs coverage in each Availability Zone, so two AZs cost about $66 a month in gateway hours, or about $73 with two public IPv4 addresses, before data processing or internet egress.

AWS added a regional NAT Gateway mode in November 2025. One gateway spans AZs automatically and needs no public subnet, but it is still billed per AZ it covers, so the hourly total is about the same. The NAT route is the right choice if your Lambdas already live in a VPC for RDS or ElastiCache, or if policy requires all traffic to stay on AWS. It is a lot of infrastructure if you only need one partner API to see a fixed address. Run your own numbers in the NAT gateway cost calculator.

Sources for AWS Lambda pricing

Checked October 2026. Confirm current details on the vendor's site before you decide. Prices and limits change.

Set up a static IP on AWS Lambda

Use a dedicated variable name, not HTTPS_PROXY. boto3 reads HTTPS_PROXY automatically, and you do not want AWS API calls going through the proxy.

Fixedmark is in early access. Proxy URLs are issued at launch. Join early access to get yours when your region opens.

Before you start

  • A Lambda function on a current runtime (nodejs22.x, nodejs24.x, or Python 3.12 to 3.14) that is not in a VPC, or is in a VPC that already has internet egress.
  • A Fixedmark proxy URL (https://APP_ID:TOKEN@mum.egress.fixedmark.com:443) and the two IPs of your pair. Both are issued at launch. Join early access to get them.
  • IAM permission to update the function's configuration.
  • Access to the partner's or database's allowlist, or a contact who can add two IPv4 addresses for you.

Steps

  1. 1
    Store the proxy URLSet FIXEDMARK_PROXY_URL as an environment variable in the function configuration, or keep it in Secrets Manager or SSM Parameter Store and load it at init. With the CLI, aws lambda update-function-configuration --environment replaces all existing variables, so include the ones you already have.
  2. 2
    Bundle the HTTP clientNode.js: add undici to the deployment package. Python: requests is not in the Lambda runtime, so add it to the package or a layer.
  3. 3
    Create the client at initBuild the proxy agent or session outside the handler so warm invocations reuse the connection to the proxy.
  4. 4
    Deploy, verify, allowlistInvoke the IP check handler below once, confirm it returns a Fixedmark IP, then give the partner both IPs.
// Bundle undici with the function (npm install undici).
import { fetch, ProxyAgent } from "undici";

// Created at init, reused across warm invocations.
const proxy = new ProxyAgent(process.env.FIXEDMARK_PROXY_URL);

export const handler = async () => {
  const res = await fetch("https://api.partner.example/v1/orders", {
    dispatcher: proxy,
  });
  return { statusCode: res.status, body: await res.text() };
};

SDKs that do not use fetch (the Stripe and Salesforce Node SDKs, got, axios) accept an HTTP agent. Pass new HttpsProxyAgent(process.env.FIXEDMARK_PROXY_URL) from the https-proxy-agent package, which supports https:// proxy URLs. With axios, also set proxy: false so it does not apply its own proxy logic. undici 8 needs Node 22.19 or later. On older Node, install undici@7.

Verify the egress IP on Lambda

Check the IP before you send it to a partner. Deploy the handler below as a separate function, or as a temporary path in an existing one, and invoke it with aws lambda invoke. The endpoint https://fixedmark.com/api/ip returns the caller's IP as plain text, and the What's my IP tool shows the same thing in a browser.

The proxied call should print one of your two Fixedmark IPs every time. The direct call should print a different address. If both print the same platform IP, the client is not using the proxy.

import { fetch, ProxyAgent } from "undici";

const proxy = new ProxyAgent(process.env.FIXEDMARK_PROXY_URL);

// Invoke with: aws lambda invoke --function-name egress-check out.json
export const handler = async () => {
  const via = await fetch("https://fixedmark.com/api/ip", { dispatcher: proxy });
  const direct = await fetch("https://fixedmark.com/api/ip");
  return {
    fixedmark: (await via.text()).trim(),
    platform: (await direct.text()).trim(),
  };
};

Databases: Postgres, MySQL, and MongoDB

Lambda functions cannot run a background process, so the bm tunnel CLI is not an option there. Use a driver that can dial through SOCKS5 with FIXEDMARK_SOCKS_URL. The MongoDB Node.js driver supports this with its proxyHost, proxyPort, proxyUsername, and proxyPassword options (install the socks package next to it). Go's pgx accepts a SOCKS5 dialer through DialFunc.

node-postgres, mysql2, and psycopg have no SOCKS5 option. For those, move the queries into a small long-running service on a platform that can run bm tunnel, or use your database provider's HTTP API through the HTTPS proxy. Connection setup costs more with a proxy hop: open the client once per function instance, not per request.

// npm install mongodb socks
import { MongoClient } from "mongodb";

// FIXEDMARK_SOCKS_URL=socks5h://APP_ID:TOKEN@mum.egress.fixedmark.com:1080
const socks = new URL(process.env.FIXEDMARK_SOCKS_URL);

const client = new MongoClient(process.env.MONGODB_URI, {
  proxyHost: socks.hostname,
  proxyPort: Number(socks.port),
  proxyUsername: decodeURIComponent(socks.username),
  proxyPassword: decodeURIComponent(socks.password),
});
await client.connect();

Common errors and fixes

Task timed out with no response from the proxy

The function is attached to a VPC with no route to the internet, so it cannot reach the proxy either. Detach it from the VPC or add internet egress first.

AWS SDK calls start failing after adding a proxy

You set HTTPS_PROXY or NODE_USE_ENV_PROXY on the function. boto3 and Node's built-in clients then send AWS API calls through the proxy. Remove those variables and pass FIXEDMARK_PROXY_URL to your HTTP client only.

407 Proxy Authentication Required

The proxy did not get valid credentials. Check that the env var holds the full URL with APP_ID:TOKEN@, with no quotes or trailing newline. If the token contains @, :, or /, URL-encode it. Some clients drop credentials from the URL: pass them separately (Deno's basicAuth, axios proxy.auth) or switch to undici's ProxyAgent, which reads them from the URL.

TLS errors to the proxy: wrong version number, EPROTO, Proxy CONNECT aborted, or unable to connect to proxy

The client does not support an https:// proxy URL and is speaking plain HTTP to port 443. Upgrade it: curl 7.52+, urllib3 1.26+ (requests), httpx 0.26+, undici ProxyAgent, Go 1.10+. In Ruby, use Typhoeus: Net::HTTP and Faraday's default adapter cannot tunnel HTTPS through a TLS proxy. For older axios releases, set proxy: false and pass https-proxy-agent as httpsAgent. Java's built-in HttpClient cannot speak TLS to a proxy at all. If you cannot upgrade, use the SOCKS5 URL.

ETIMEDOUT or ECONNRESET to the partner, or a 403 from the partner

The proxy connected, but the destination dropped you. Usually only one IP of the pair is on the allowlist, or the partner has not applied the change yet. Add both IPs. If a destination allowlist is set on your Fixedmark token, check the host and port are on it.

The IP check prints the platform's IP, not a Fixedmark IP

The request went direct. Node's built-in fetch ignores HTTPS_PROXY unless NODE_USE_ENV_PROXY=1 is set (Node 22.21+ and 24+). Many SDKs ignore proxy env vars too. Pass the proxy to the client explicitly, as in the snippets above.

429 or 407 with an X-Proxy-Error: quota_exceeded header

Planned behavior when you pass your plan's soft limit. Check usage in the dashboard or raise the plan.

Database driver has no proxy option

node-postgres, mysql2, psycopg, and most ORMs cannot use an HTTP proxy. Use a SOCKS5-capable driver with FIXEDMARK_SOCKS_URL, or run bm tunnel where the platform allows a second process.

Gotchas on Lambda

The AWS SDK for JavaScript v3 ignores proxy env vars, while boto3 honors them. Using a dedicated variable name keeps both behaving the same: AWS calls direct, partner calls through the proxy.

  • Lambda@Edge and CloudFront Functions are out of scope.
  • Data transfer out of AWS to the proxy is billed by AWS at normal internet egress rates.
  • undici 8 needs Node 22.19 or later. Bundle undici@7 if you pin an older runtime.

Frequently asked questions

How do I give AWS Lambda a static IP?

Either attach the function to private subnets behind a NAT Gateway with an Elastic IP, or route its outbound calls through a static IP proxy such as Fixedmark. The proxy needs no VPC changes.

Can Lambda have a static IP without a NAT Gateway?

Not on AWS alone. Outside a VPC, Lambda uses shared AWS addresses. Without a NAT Gateway, the way to get a fixed source IP is to send the calls through a static IP proxy.

How much does a NAT Gateway cost for Lambda?

In us-east-1, $0.045 per hour plus $0.045 per GB processed, plus $0.005 per hour per public IPv4. Two Availability Zones come to about $66 a month in gateway hours, or about $73 with two public IPv4 addresses, before traffic.

Should I set HTTPS_PROXY on Lambda?

No. boto3 reads HTTPS_PROXY and would send AWS API calls through the proxy. Use a dedicated variable such as FIXEDMARK_PROXY_URL and pass it only to the client that needs it.

Fix your egress IP.

Fixedmark is in early access. Join the list to get a dedicated IP pair for AWS Lambda when your region opens.