Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 20 additions & 42 deletions networking/egress-ips.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@

## Why Egress IPs Matter

Some external services—APIs, databases, payment providers—require allowlisting source IPs. Without static egress IPs, outbound IPs from Fly machines may change due to machine lifecycle or infrastructure changes.

Check warning on line 25 in networking/egress-ips.html.md

View workflow job for this annotation

GitHub Actions / Vale linter

[vale] reported by reviewdog 🐶 [Fly.Spelling] Is 'allowlisting' a typo? Raw Output: {"message": "[Fly.Spelling] Is 'allowlisting' a typo?", "location": {"path": "networking/egress-ips.html.md", "range": {"start": {"line": 25, "column": 67}}}, "severity": "INFO"}

- Machines often egress over IPv6 when the destination has an AAAA record and the application prefers it. For example, `curl` will try IPv6 first if available, then fall back to IPv4 if needed. Fly doesn’t force IPv6, but many apps will use it when it's available.
- IPv4 traffic is NAT'd and may vary. This means the source IP address is rewritten by the host, and which IP you get can change depending on where the machine runs or is restarted.

Check warning on line 28 in networking/egress-ips.html.md

View workflow job for this annotation

GitHub Actions / Vale linter

[vale] reported by reviewdog 🐶 [Fly.Spelling] Is 'NAT'd' a typo? Raw Output: {"message": "[Fly.Spelling] Is 'NAT'd' a typo?", "location": {"path": "networking/egress-ips.html.md", "range": {"start": {"line": 28, "column": 19}}}, "severity": "INFO"}
- You need static egress if you're allowlisting IPs with third-party services.

Check warning on line 29 in networking/egress-ips.html.md

View workflow job for this annotation

GitHub Actions / Vale linter

[vale] reported by reviewdog 🐶 [Fly.Spelling] Is 'allowlisting' a typo? Raw Output: {"message": "[Fly.Spelling] Is 'allowlisting' a typo?", "location": {"path": "networking/egress-ips.html.md", "range": {"start": {"line": 29, "column": 36}}}, "severity": "INFO"}

---

Expand Down Expand Up @@ -86,32 +86,43 @@

## Static Egress IPs (Machine-Scoped)

<div class="warning icon">
Machine-scoped static egress IPs are considered a legacy feature and may be removed in the future. This section is kept for reference purposes only. New apps should use [app-scoped static egress IPs](#static-egress-ips-app-scoped).
</div>
In the past, we supported machine-scoped egress IPs that are statically bound to individual machines rather than apps.
This feature is deprecated, and all new apps should use [app-scoped static egress IPs](#static-egress-ips-app-scoped) instead.

However, if you already have machine-scoped static egress IPs assigned, they continue to work and you may still view and manage them.
You can also "promote" them into app-scoped egress IPs.

### Allocate a Static Egress IP
### View and Manage

```bash
fly machine egress-ip allocate <machine-id> --app <app-name>
fly machine egress-ip list --app <app-name>
fly machine egress-ip release <machine-id> --app <app-name>
```

- This assigns a stable IPv4 + IPv6 pair to the specified machine.
### Migrate to App-scoped Egress IPs

### View and Manage
You can migrate from machine-scoped egress IPs to app-scoped egress IPs by "promoting" a subset of existing machine-scoped egress IPs to be app-scoped. This allows you to keep external allowlist configuration unchanged while switching to app-scoped egress IPs.

The promotion process is mostly seamless, but a short window of downtime is possible while the egress IP is removed from the original machine and reassigned to the app.

```bash
fly machine egress-ip list --app <app-name>
fly machine egress-ip release <machine-id> --app <app-name>
fly machine egress-ip promote <machine-id> --app <app-name>
```

<div class="note icon">
Promoted egress IPs retain the original machine's region.
If your app has machines in multiple regions, promote at least one for each region.

You should also remove any remaining machine-scoped egress IPs that are no longer needed.
</div>

### Caveats

Because legacy static egress IPs are **per-machine**, not per-app:

- IPs are released when a machine is destroyed.
- IPs don’t automatically transfer across deploys.
- Bluegreen deployments will replace machines—and their IPs.

Check failure on line 125 in networking/egress-ips.html.md

View workflow job for this annotation

GitHub Actions / Vale linter

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'bluegreen' instead of 'Bluegreen'. Raw Output: {"message": "[Vale.Terms] Use 'bluegreen' instead of 'Bluegreen'.", "location": {"path": "networking/egress-ips.html.md", "range": {"start": {"line": 125, "column": 3}}}, "severity": "ERROR"}
- Deployment-time jobs may bypass egress routing.
- Extra latency and connectivity issues are possible in some regions.

Expand All @@ -121,39 +132,6 @@

---

## The Proxy Pattern (for Machine-Scoped Static Egress IPs)

<div class="warning icon">
This section only applies to existing apps using machine-scoped static egress IPs. New apps should use [app-scoped static egress IPs](#static-egress-ips-app-scoped) instead.
</div>

To avoid assigning static IPs to every machine, route traffic through a shared proxy app.

### How It Works

1. Deploy a small Fly app (e.g. `egress-proxy`) with static egress IPs.
1. Run a forward HTTP/HTTPS proxy on it.
1. Set `http_proxy` / `https_proxy` env vars in consuming apps.
1. Outbound traffic from those apps will route through the proxy.

### Benefits

- Fewer IPs to manage.
- Primary app machines can be ephemeral.
- Centralize allowlisting.

### Downsides

- Primarily supports HTTP/S traffic. Other protocols (like raw TCP or Postgres) may be possible with extra work, such as using SOCKS5 proxies, `haproxy` in TCP mode, or `socat`, but those setups are more complex and outside the scope of this guide.
- Adds some latency (~100ms typical).
- Requires maintaining a separate proxy app.

<div class="callout">
Example implementation: [fly-apps/fly-fixed-egress-ip-proxy](https://github.com/fly-apps/fly-fixed-egress-ip-proxy)
</div>

---

## Best Practices

- Use static egress only when required.
Expand Down
Loading