Skip to main content
Runners only ever make outbound connections. There is no inbound requirement at all: no SSH, no port 22, no bastion, no VPN. Airship never connects to a machine — the machine connects out, to GitHub and to nothing else it does not need.

What a runner must reach

With caching on, a gateway VPC endpoint for S3 keeps the bucket traffic off the internet and off your NAT bill. It is usually the single best network change you can make.

AWS

By default: the region’s default VPC, every default subnet (Airship rotates availability zones per runner so one zone running short does not fail the job), and an airship-runners security group it creates once per VPC with no inbound rules.
With SubnetId set, Airship launches only there — no zone rotation, so a capacity shortage in that zone becomes a launch failure and moves to the next fallback. A private subnet works and needs a NAT gateway or equivalent for the destinations above. IMDSv2 is required with a hop limit of 1, so a process inside a container cannot reach instance metadata.

Google Cloud

By default: the default network, with an external address per machine.
The first such launch in a region creates a Cloud Router and NAT — airship-nat on the default network, airship-nat-<network> on another — and every later runner there shares it. The service account needs roles/compute.networkAdmin for that.
Up to eight interfaces, each taking network, subnetwork, nicType (GVNIC, VIRTIO_NET, IDPF), stackType and one accessConfigs entry, as Compute Engine spells them. Naming only the subnetwork is enough — Airship reads the network from it, which is also how it knows where a NAT belongs. Airship adds no firewall rules. Instances carry the network tag airship-runner, so a rule you write against that tag applies to every future runner automatically. That is the intended lever.
The same service account needs its roles in that project too, and each project becomes its own inventory scope. For a Shared VPC, grant roles/compute.networkUser on the specific subnet in the host project and reference the subnetwork by full path.

Azure

Airship creates an airship-runners-<region> virtual network and subnet on first launch in a region, with a security group carrying none of its own rules — so Azure’s default denies inbound traffic from the internet.
The default here is a public address per machine, because the subnet Airship creates is private, as Azure makes new subnets. Turning the address off creates airship-nat-<region>, a NAT gateway with a static address of its own, attached to that subnet and shared by every later runner in the region. Each machine’s interface and address are deleted with it; orphans left behind by a failed launch are swept once they are older than fifteen minutes.

No key, no way in

If you need to inspect a runner mid-job, add your own access deliberately — your own security group, your own key in your own image — rather than expecting Airship to have left a door open.

A private setup, end to end

airship.yaml
A private subnet with no route out is the most common cause of “the instance launched but the runner never appeared”. The machine boots, cannot reach GitHub, and powers itself off at its deadline. Check the console output first.