Skip to content
Fixedmark
Use case · Databases

Static IP for Postgres and MySQL Allowlists

To connect a serverless or PaaS app to an IP-restricted Postgres or MySQL database, send the database connection through a static IP and allow only that IP in the database firewall. Fixedmark supports this with SOCKS5 for drivers that accept a custom dialer and the `bm tunnel` CLI for every other driver.

Where the database allowlist lives

Every managed database has a network allowlist, and each one wants a fixed source address:

  • AWS RDS and Aurora: an inbound rule on the instance's security group, for example TCP 5432 from 203.0.113.10/32.
  • Google Cloud SQL: authorized networks on an instance with a public IP.
  • Self-hosted Postgres: a hostssl line in pg_hba.conf plus your cloud or host firewall.
  • Self-hosted MySQL: the host part of the user account, such as 'app'@'203.0.113.10', plus the firewall.

Why this breaks on serverless and PaaS

Functions on Vercel, Netlify, and AWS Lambda outside a VPC connect from changing addresses. Containers on Railway, Render, and Heroku get new IPs when they move. Teams end up opening port 5432 or 3306 to 0.0.0.0/0, which exposes the database to internet-wide scanning and password guessing.

On AWS, you can place Lambda in a VPC and route through a NAT gateway with an Elastic IP. That works for compute inside AWS, but a highly available setup across two Availability Zones costs about $66 per month in gateway hours, about $73 with two public IPv4 addresses, before traffic. The NAT gateway comparison covers the numbers.

Choose a connection path

SOCKS5 is the best fit for serverless functions, because nothing extra runs beside your code. Go's pgx driver accepts a custom DialFunc, so you can dial through golang.org/x/net/proxy with a few lines. Check your driver's documentation for a SOCKS5 or custom socket option.

The bm tunnel CLI, planned for launch, forwards a local port to the database through your Fixedmark IPs. Run it in the start command of a long-lived service on Railway, Render, Fly.io, or Heroku, then point any driver at 127.0.0.1. Serverless functions cannot run a background tunnel, so use SOCKS5 there.

TLS still runs from your driver to the database. When you connect to 127.0.0.1 through a tunnel, set the TLS server name to the real database hostname so certificate checks pass.

Allowlist a static IP on your database

Add the new rule before you remove the old one, so there is no downtime.

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

  1. 1
    Create an endpoint near the databaseChoose the Fixedmark region closest to the database, for example Virginia for RDS in us-east-1.
  2. 2
    Allow both IPsAdd each IP as a /32 to the security group, authorized networks, or pg_hba.conf. Restrict the rule to the database port.
  3. 3
    Store the SOCKS URLSet FIXEDMARK_SOCKS_URL on your platform. For the tunnel path, the CLI reads its token from its own config.
  4. 4
    Connect through SOCKS5 or the tunnelUse a custom dialer in drivers that support one. Otherwise start bm tunnel and point the connection string at localhost.
  5. 5
    Close the open ruleOnce connections succeed, remove any 0.0.0.0/0 rule and confirm in the connection logs that traffic uses your pair.
import (
	"context"
	"net/url"
	"os"

	"github.com/jackc/pgx/v5/pgxpool"
	"golang.org/x/net/proxy"
)

func connect(ctx context.Context) (*pgxpool.Pool, error) {
	u, err := url.Parse(os.Getenv("FIXEDMARK_SOCKS_URL"))
	if err != nil {
		return nil, err
	}
	pw, _ := u.User.Password()
	dialer, err := proxy.SOCKS5("tcp", u.Host,
		&proxy.Auth{User: u.User.Username(), Password: pw}, proxy.Direct)
	if err != nil {
		return nil, err
	}
	cfg, err := pgxpool.ParseConfig(os.Getenv("DATABASE_URL"))
	if err != nil {
		return nil, err
	}
	cfg.ConnConfig.DialFunc = dialer.(proxy.ContextDialer).DialContext
	return pgxpool.NewWithConfig(ctx, cfg)
}

Frequently asked questions

How do I connect Vercel to an IP-restricted Postgres database?

Route the driver through a SOCKS5 proxy with a static IP, then allow that IP in the database firewall. Drivers with a custom dialer option, such as Go's pgx, can do this directly.

Can I use bm tunnel inside a serverless function?

No. Functions cannot keep a background process running. Use the tunnel on long-lived services and SOCKS5 inside functions.

Does the tunnel break TLS certificate checks?

Only if the driver verifies against 127.0.0.1. Set the TLS server name to the real database hostname and verification works as usual.

Is this cheaper than a NAT gateway?

For most small and mid-sized apps, yes. Two NAT gateways for high availability cost about $73 per month including their public IPv4 addresses, before data processing charges, and they only serve compute inside your AWS VPC.

Make it fixed.

Fixedmark is in early access. Join the list to get dedicated static IPs when your region opens.