
- Via Fly Proxy, the Fly.io component that handles load balancingāthis is what youāll need for any public web service
- Over the WireGuard IPv6 private network (ā6PNā) that the app belongs toāthis can be useful for, e.g., providing private supporting services to your Fly Apps
TL;DR
Hereās a cheat sheet for configuring apps to be reachable by each of these means:
Thereās a bit more to the whole picture, which is why the rest of this document exists.
Services Routed with Fly Proxy
All services reachable from the public internet via a Fly Appās global Anycast address are routed by Fly Proxy. Fly Proxy can load-balance requests for both public and private (Flycast) services among a Fly Appās VMs. Routing to a service with Fly Proxy also enables other Fly Proxy features, such as automatically starting and stopping Machines in response to fluctuations in request traffic.Get the service listening on the right address within the VM
Fly Proxy reaches services through a private IPv4 address on each VM, so the process should listen on0.0.0.0:<port> (but see A note on IPv4 and IPv6 wildcards).
UDP is special
UDP services have to listen at a different specific address,fly-global-services, on their VM, due to how our UDP proxying logic works.
Configure the service for Fly Proxy to reach it
Public apps
Define a service infly.toml (or in the case of standalone Machines that donāt belong to Fly Launch, in individual Machine configs), making sure the internal_port on the service definition is the same port the process is bound to inside the VM. Without this config, Fly Proxy isnāt aware of the service and canāt route to it.
Private (Flycast) apps
Configure a service as for a public app, but in addition: Flycast doesnāt do HTTPS, so make sure youāve defined a non-HTTPS service, and also ensure thatforce_https = true is not included in any HTTP service definition.
Allocate a public or private IP to the app
Public apps
To have Fly Proxy route requests to an app from the public internet, provision at least one public Anycast IP for the app. An app with HTTP and HTTPS services defined is allocated public IPs automatically on the first run offly deploy; you can confirm with fly ips list.
Private (Flycast) apps
To have Fly Proxy load-balance among VMs on a non-public app, allocate a private (Flycast) IPv6 address usingfly ips allocate-v6 --private, and remove any public IPs from the app using fly ips release <address>. A Flycast IP can only be reached from within the private network itās allocated on, which must belong to the same Fly Organization as the Fly App it points to.
A note on Fly App IPs and Fly-Replay routing
App-wide IP addresses (public and private) tell Fly Proxy which app to deliver a request to. If a service only needs to be reachable by Fly Proxy in its handling of the Fly-Replay response header, its app does not need an IP; app information is incorporated directly in the header.Private services on 6PN (direct WireGuard connections)
If you donāt need load balancing or other Fly Proxy features, you (or one of your apps) can connect directly on a VMās 6PN address (i.e., its address on its IPv6 private WireGuard network).By default, all of an organizationās Fly Apps live on the same private network, but you can create apps on different private networks to isolate them from one another. Youād want to do this if you run separate apps for your customers, for example.
Get the service listening on the right address within the VM
Each VM has the hostnamefly-local-6pn mapped to its own 6PN address in its /etc/hosts file, so to make a service reachable over the private network, bind it to fly-local-6pn:<port>. Binding to a port on the IPv6 wildcard āaddressā ([::]:<port>) also works (but see A note on IPv4 and IPv6 wildcards).
Thatās it, really. Thereās no need to define any service in fly.toml, and thereās no need to provision any IPs for the app.
If your service works publicly but canāt be reached directly over WireGuard, the problem may be that itās not listening on IPv6.
Fly.io internal DNS and 6PN addresses
Fly.io runs a specialized internal DNS service to find 6PN addresses for VMs. Queries on the various.internal names return either AAAA records for 6PN addresses, or a TXT record with information about your app, your network, or your Machines.
Internal DNS gives us some useful presets for targeting requests. For instance, a DNS query on the address <region>.<appname>.internal yields the 6PN addresses of the VMs of app <appname> in region <region>. Addressing a request to <region>.<appname>.internal gets it delivered to one of those VMs.
Our private networking docs list the .internal names and what kind of information a DNS query returns for each.
A note on IPv4 and IPv6 wildcards
Services to be routed to using Fly Proxy need to bind to IPv4 addresses, and services to be reached over 6PN need to bind to IPv6, as described above. However, you may find that your service works even if you havenāt used the addresses we specified. IPv4-mapped IPv6 addresses, if enabled on the VM, can allow IPv4 (and thus Fly Proxy) connections to a service bound on[::]. Further, the wildcard syntax [::] or 0.0.0.0 sometimes covers both IPv4 and IPv6, depending on the language, library, or application.
Troubleshoot connections to a service
Connect to the process from inside the VM
You may want to make sure the process is doing what you think it is, inside the VM. If you should have a service running internally, you can try connecting to it with cURL from within the VM (usefly ssh console to pop a shell; see note [2] below the tables). If your appās Docker image doesnāt have curl installed, you can install it; itāll be wiped away next time the VM is restarted (e.g. on the next fly deploy).
A HEAD request (curl -I) should be enough to see if youāre getting a response:
200 OK means the service (nginx) is running, and listening on port 80 as anticipated.
You can further check that the right HTML is being served, with curl http://localhost:<port> (leaving out the -I).
cURL is a useful tool for checking that a service is reachable where it should be. Here are some further tests that may help with understanding networking issues. Weāll carry on with the example of an HTTP app.
Connect to Public or Flycast services
Connect to Private 6PN services
[1] If this fails (i.e. you donāt get the expected response from the service), then either (a) the service isnāt functioning the way you expect (b) itās not bound to the port you pointed cURL at, or (c) itās not bound to the IPv4 address Fly Proxy uses to reach the VM, and so Fly Proxy wonāt be able to route to it.
[2] Pull up an interactive shell on a VM that should be running this service, with
fly ssh console. Donāt use the fly console command; this brings up an ephemeral VM from the appās Docker image, but doesnāt start up the same process(es), so your service wonāt be running there.
[3] Except UDP services.
[4] If this fails, but the local check succeeded, the next thing to confirm is that the app or Machine config includes a properly configured services or http_service section, with internal_port matching <port> used in this test. Also check fly ips list: if the app has only an IPv6 address, it wonāt be reachable from IPv4-only networks. You can allocate a free shared IPv4 address with fly ips allocate-v4 --shared.
[5] The HTTP URL always elicits a 301 redirect, because the Fly Proxy upgrades HTTP connections to HTTPS. To get cURL to follow the redirect to see if thereās anything there, use the -L flag. This example has the services configured to handle HTTP and HTTPS requests on the conventional ports 80 and 443 respectively; if youāre using different ports, substitute those in.
[6] If the check within the VM succeeded, but this step fails, check everything in note [5], plus: Ensure that thereās an HTTP service configured and force_https is not set to true; Flycast doesnāt work over HTTPS.
[7] A Flycast IP can be allocated on a different private network from the app it points to, if both networks belong to the same org. This lets your apps reach your service in a different 6PN, if the service is configured to be available over Flycast.
[8] If this fails (i.e. you donāt get the expected response from the service), then either (a) the service isnāt functioning the way you expect, (b) itās not bound to the port you pointed cURL at, or (c) itās not bound to its 6PN address, and wonāt be reachable via the private WireGuard network (including at .internal addresses).