Guide

A Static IP for GitHub Actions

GitHub-hosted runners egress from ranges shared with every GitHub Actions user on the platform, so allow-listing them means allow-listing everybody's CI, including anybody who forks your workflow patterns. GitHub's own fix is static IP ranges on larger runners, which needs Team or Enterprise. A self-hosted runner is free and is the right answer more often than people expect. A dedicated address is worth it when you want hosted runners and one fixed source.

Why the published ranges are not an allow-list

GitHub publishes the address ranges its hosted runners use — fetch them from https://api.github.com/meta under the actions key. It is tempting to paste those into a firewall and call the problem solved. Look at the size of what you just pasted first.

curl -s https://api.github.com/meta | jq '.actions | length'

Those ranges cover thousands of addresses across Azure regions, and they are shared by every GitHub Actions workflow running anywhere in the world. Allow-listing them does not admit your CI. It admits all CI — any GitHub user who can run a workflow is inside your firewall rule. For a staging box that may be an acceptable risk you have chosen deliberately. For a production database or a partner endpoint it is not an allow-list in any meaningful sense, and a reviewer who understands what the range is will say so.

They also change. GitHub updates the published set, and a firewall rule pinned to a copy you pasted last year will start failing without anything on your side having changed.

GitHub's own answer: larger runners with static IPs

GitHub supports assigning unique, static public IP ranges to larger runners: in the runner's networking settings, enable the option to assign a static IP range, and the addresses become yours to allow-list. This is first-party, well integrated, and it is the correct answer if it is available to you.

Larger runners require a Team or Enterprise plan, and are billed per-minute at higher rates than standard hosted runners. If you are already on Team or Enterprise and using larger runners, turn this on and stop reading — nothing below improves on it.

The free answer most people skip: a self-hosted runner

A self-hosted runner is a machine you control, so its outbound address is whatever that machine's address is. No add-on, no per-minute premium, no plan tier. If you already have a server, this costs nothing.

We are saying this plainly because it is frequently the right answer and it competes with us: if the workflow that needs the fixed address is a deploy or a migration that runs a few times a day, a small self-hosted runner is cheaper and simpler than anything else on this page, ours included.

The honest counter-arguments, which are also real:

When a dedicated address is the better trade

The case for an address you hold is narrower and worth stating precisely. It fits when you want to keep using GitHub-hosted runners — ephemeral, maintained by GitHub, safe for public repositories — but need one specific step to leave from a known source.

Attach a TunnelNet address to a small always-on box and route the sensitive step through it: the migration that talks to the production database, the deploy that reaches a firewalled server, the call to a partner API. The rest of the workflow runs on GitHub's runners exactly as before.

What the far end sees is your dedicated address from 23.187.152.0/24, announced by AS396500. It is not shared with other CI users, it does not change when GitHub rotates its ranges, and it is the same address whether the call comes from CI, from a server, or from a laptop — which is the part that tends to decide it. One allow-list entry can cover your CI, your production backend and your on-call engineer's machine.

Honest caveats, same as everywhere else on this site:

Choosing between them

Verify the source address before you file it

Add a step that prints the address the far end will actually see, from the same job that makes the real call:

curl -4 https://api.ipify.org

Check it a second way (curl -4 https://ifconfig.co), and re-run the workflow before you file the address — on hosted runners a single observation tells you about one runner, not about the next one. A mis-filed address fails as a total denial at the far end, not as a warning.

What this costs with us

A dedicated address is $20/month on TunnelNet Full, inbound and outbound on the same address, attached to a machine you already have. TunnelNet Business is $100/month for the same address with a written 8-working-hour response commitment (09:00–17:00 US Central, Monday to Friday), onboarding done with a person who verifies the source address from outside our network before you file it, and our measured uptime published — incidents included.

Plainly, because you are about to put a partner integration on this: we have no SLA and will not offer one until we have six months of measured history, 21 February 2027 at the earliest. A hub failure that withdraws routes takes about 25 seconds to recover, measured — and a hub that stays up while it stops forwarding is not failed over automatically at all. GitHub will quote you better availability numbers than that, and they will be true. Weigh it against what the address itself is worth to you.

Static IP for your platform

The same question, answered for each platform it comes up on most. Every one of them leads with that platform's own native or free answer:

And the general case, if your platform is not listed: