self-host →

Static IPs

Static egress IPs for RunsOn Flex and Fleet runners through private subnets, NAT gateways, and Elastic IPs.

RunsOn supports static egress IPs by launching runners in private subnets and routing outbound internet traffic through NAT gateways with Elastic IPs. Use this when third-party services require IP allow lists or when CI jobs must reach private network services.

For the shared networking model and tradeoffs, see Networking.

Usage

Flex

Enable private networking support on the Flex stack, then launch jobs in private subnets with the private=true label:

.github/workflows/deploy.yml
jobs:
deploy:
runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/private=true

Fleet

Fleet private networking is configured in Terraform. Enable private networking support, provide private subnets, then mark the runner definitions that should launch in private subnets:

module "runs_on_fleet" {
private_mode = "true"
vpc_id = module.vpc.vpc_id
public_subnet_ids = module.vpc.public_subnets
private_subnet_ids = module.vpc.private_subnets
runners = {
deploy-static-ip = {
family = ["m7i.large"]
image = "ubuntu24-full-x64"
private = true
}
}
fleets = {
deploy = {
runner = "deploy-static-ip"
}
}
}

See Fleet networking and IAM for the full Terraform input reference.

How it works

With the default Flex CloudFormation template, enabling Private mode makes RunsOn create private subnets for your GitHub Actions runners and provision one managed NAT Gateway. In common AWS regions, a single NAT Gateway costs about $33/month for the hourly charge alone, plus NAT data processing and standard data transfer charges. Check the AWS VPC pricing page for current pricing in your region.

Fleet is Terraform-first. You provide the VPC, public subnets, private subnets, and NAT design. The module can then launch the Fleet worker and selected runner fleets in private subnets.

The NAT Gateway is assigned an Elastic IP (EIP), a static IP address provided by AWS. This EIP becomes the source IP for outbound traffic from private runners, so egress traffic has a consistent and allow-listable IP address.

Configuration

Flex

To take advantage of private networking and static IPs in RunsOn, you need to enable this feature during the setup process, or reconfigure your stack to enable it. RunsOn handles the provisioning and configuration of the necessary AWS resources, including the assignment of the Elastic IPs to the NAT Gateways.

You switch between Public and Private mode by changing the Private CloudFormation parameter. It accepts the same four values as Fleet private_mode:

  • false: public subnets (default).
  • true: jobs opt in to private subnets with the private=true label.
  • always: jobs run in private subnets by default, unless they opt out with private=false.
  • only: all jobs run in private subnets, with no opt-out.

By default, RunsOn creates the Stack in Public mode (false), because NAT gateways incur additional costs and are not needed in most cases.

If you need a different network topology, such as an existing VPC, multiple NAT gateways, or your own egress design, use the Terraform / OpenTofu install path instead of the default CloudFormation template.

Fleet

private_mode controls whether the Fleet worker and runners use private subnets:

  • false: use public subnets.
  • true: run the Fleet worker privately and allow private runner fleets.
  • always: run the Fleet worker privately and make private runners the default, unless a runner fleet opts out.
  • only: run the Fleet worker and runners privately.

With private_mode = "true", runner fleets stay public by default. Set private = true on each runner definition that needs static egress through your NAT gateway.