From 6fa48300066a710b6d599b139b6651739ee6147e Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Wed, 29 Apr 2026 22:00:25 +0000 Subject: [PATCH 1/7] Rewrite Flycast blueprint to drop GPU/Ollama example GPU Machines are deprecated as of 2026-08-01, so the Ollama walkthrough needed to go. Reframed the guide around a generic private HTTP service using the public nginxdemos/hello image and the modern fly launch --flycast flag, so no external example repo is needed. Also swapped the Fly Postgres mention for Managed Postgres and refreshed related reading to drop the GPU/Ollama blog posts. --- .../private-applications-flycast.html.md | 102 +++++------------- 1 file changed, 28 insertions(+), 74 deletions(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index 932efdacda..b968b72b31 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -6,18 +6,16 @@ nav: guides author: xe categories: - networking -date: 2024-06-17 +date: 2026-04-29 --- -

- ## Overview A lot of the time your applications are made to be public and shared with the world. Sometimes you need to be more careful. When you deploy your apps on Fly.io, you get a private network for your organization. This lets your applications in other continents contact each other like they were in the same room. Sometimes you need a middle ground between fully public apps and fully private apps. [Flycast](/docs/networking/flycast/) addresses are private but global IPv6 addresses inside your private network that go through the Fly Proxy, so you get all of the load management and Machine waking powers that you get for free with public apps. -This blueprint covers what Flycast is, when and why you’d want to use it, and shows you how to create an instance of Ollama that you can connect to over Flycast. +This blueprint covers what Flycast is, when and why you’d want to use it, and shows you how to deploy a small private HTTP service that you can connect to over Flycast. ## What is Flycast? @@ -37,17 +35,13 @@ When you want to connect to an app via Flycast, you connect to `appname.flycast` Just a heads-up. In general, it’s a bad idea to assume that network access barriers like Flycast or NAT are security layers. At best, this is an obfuscation layer that makes it more difficult for attackers to get into private applications. Flycast is not a replacement for authentication in your private applications. With Flycast, you don’t know _who_ a request is coming from, but you do know that it’s coming from _something_ or _someone_ in your private network. -One of the biggest platform features that uses Flycast out of the box is Fly Postgres. Even though Flycast addresses are local to your private network, Fly Postgres still configures usernames and passwords for your database. +One of the biggest platform features that uses Flycast out of the box is [Managed Postgres](/docs/mpg/). Even though Flycast addresses are local to your private network, Managed Postgres still configures usernames and passwords for your database. ## Goal -We'll show Flycast off by setting up an instance of [Ollama](https://ollama.com+external). - -Ollama is a program that wraps large language models and gives you an interface like Docker so that you can run open-weights large language models privately on your own device. Large language models are computationally expensive to run, so being able to offload them to a GPU-powered Fly Machine means you can hack all you want without burning up your precious battery life. +We'll show Flycast off by deploying a small HTTP service that's only reachable from inside your organization's private network. The classic example is an internal admin panel: a service you and your apps need to reach, but that should never be exposed to the public internet. Flycast also lets the platform turn the service off when nobody's using it, so you're not paying to keep an idle admin panel running. -Ollama doesn’t ship with authentication by default. When you create an instance of Ollama, anyone can access it without entering in a username, password, or API key. This is fine for running your models on your own computer; but it means that if you expose it to the internet, anyone can use it and run models whenever they want. This could rack up your bill infinitely. - -This is where Flycast comes in. Flycast lets you run a copy of Ollama on your private network so that you and your apps can access it, but nobody else. Flycast also lets you have the platform turn off your Ollama server when you’re not using it, which will save you money. This fits into that middle ground case that Flycast covers perfectly. +For this walkthrough we'll use the public [`nginxdemos/hello`](https://hub.docker.com/r/nginxdemos/hello+external) image as a stand-in for any private HTTP service. It's a tiny container that responds to HTTP requests with the server's hostname and address, which makes it easy to confirm that traffic is reaching the right Machine over Flycast. ## Prerequisites @@ -56,41 +50,29 @@ To get started, you need to do the following: - [sign up or sign in](/docs/getting-started/sign-up-sign-in/) to Fly.io - [install flyctl](/docs/flyctl/install/) (the Fly CLI) -If you want to interact with your Flycast apps—like an Ollama instance—from your computer, you’ll need to [jack into your private network with WireGuard](/docs/blueprints/connect-private-network-wireguard/). +If you want to interact with your Flycast apps from your computer, you’ll need to [jack into your private network with WireGuard](/docs/blueprints/connect-private-network-wireguard/). ## Steps -Create a new folder on your computer called `ollama`. This is where we’ll put the Ollama configuration. Open a terminal in that folder and run the fly launch command: - -``` -fly launch --from https://github.com/fly-apps/ollama-demo --no-deploy -``` - -This command creates a new fly app from the [`ollama-demo` template](https://github.com/fly-apps/ollama-demo+external) and tells the flyctl command to not deploy it after you create the app. If we don’t do this, then the platform will create public IPv4 and IPv6 addresses, which will make this a public app. The name you choose when you create your app will be used to connect to your app over Flycast. - -Next, allocate a Flycast address for your app with the `fly ips allocate-v6` command: +Create a new folder on your computer called `flycast-demo` and open a terminal in it. We don't need any source code for this walkthrough — we'll launch the app directly from a public Docker image with the `--flycast` flag, which tells Fly Launch to allocate a private IPv6 address instead of public ones: ``` -$ fly ips allocate-v6 --private +fly launch --image nginxdemos/hello --flycast ``` -Now you can deploy the app with the `fly deploy` command: - -``` -$ fly deploy -``` +The name you choose for your app will be the hostname you use to reach it over Flycast (`.flycast`). When `fly launch` asks if you want to tweak the settings, you can accept the defaults. -After that finishes, you can see the list of IP addresses associated to an app with `fly ips list`: +After deploy finishes, you can see the list of IP addresses associated to an app with `fly ips list`: ``` $ fly ips list VERSION IP TYPE REGION CREATED AT v6 fdaa:3:9018:0:1::7 private global 23h12m ago +``` Learn more about [Fly.io public, private, shared and dedicated IP addresses](/docs/reference/services/#ip-addresses). -``` -This app only has one IP address: a private Flycast IPv6 address. If had public IP addresses, it'd look like this: +This app only has one IP address: a private Flycast IPv6 address. If it had public IP addresses, it'd look like this: ``` $ fly ips list -a recipeficator @@ -112,51 +94,49 @@ The Ubuntu image we chose is very minimal, so we need to install a few tools suc # apt update && apt install -y curl iputils-ping dnsutils ``` -My app is named`xe-ollama`, so let’s look up its `.flycast` address with `nslookup xe-ollama.flycast`: +Say my app is named `flycast-demo`. Let’s look up its `.flycast` address with `nslookup flycast-demo.flycast`: ``` -# nslookup xe-ollama.flycast +# nslookup flycast-demo.flycast Server: fdaa::3 Address: fdaa::3#53 -Name: xe-ollama.flycast +Name: flycast-demo.flycast Address: fdaa:3:9018:0:1::7 ``` It matches that IP address from earlier. Now let’s see what happens when we ping it: ``` -# ping xe-ollama.flycast -c2 -PING xe-ollama.flycast (fdaa:3:9018:0:1::7) 56 data bytes +# ping flycast-demo.flycast -c2 +PING flycast-demo.flycast (fdaa:3:9018:0:1::7) 56 data bytes 64 bytes from fdaa:3:9018:0:1::7: icmp_seq=1 ttl=63 time=0.138 ms 64 bytes from fdaa:3:9018:0:1::7: icmp_seq=2 ttl=63 time=0.223 ms ---- xe-ollama.flycast ping statistics --- +--- flycast-demo.flycast ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1009ms rtt min/avg/max/mdev = 0.138/0.180/0.223/0.042 ms ``` -Perfect, now let’s make a request to the Ollama app with curl: +Now let’s make a request to the app with curl: ``` -# curl http://xe-ollama.flycast +# curl http://flycast-demo.flycast ``` -It took a moment for Ollama to spin up, and now we get a happy “Ollama is running” message. Wait a few moments so your Ollama app goes to sleep and run the `time` command to see how long the first request takes: +You should get back an HTML page with the server's hostname and address. Wait a few moments so your app goes to sleep, then run the `time` command to see how long the first request takes: ``` -# time curl http://xe-ollama.flycast -Ollama is running -real 0m9.144s +# time curl -o /dev/null -s http://flycast-demo.flycast +real 0m2.411s user 0m0.003s sys 0m0.003s ``` -It took a few seconds for the platform to wake up Ollama and make sure it was ready for your requests. The next request is a lot faster: +It took a couple of seconds for the platform to wake the Machine up and make sure it was ready for your request. The next request is a lot faster: ``` -# time curl http://xe-ollama.flycast -Ollama is running +# time curl -o /dev/null -s http://flycast-demo.flycast real 0m0.043s user 0m0.003s sys 0m0.003s @@ -164,36 +144,10 @@ sys 0m0.003s And if you wait a few moments, it’ll spin back down. -### Running Llama 3 - -Now that we’ve set up Ollama and demonstrated the platform turning it off and on for you, let’s run Llama 3. Exit out of that shell Machine with control-D so we can make a new one with the Ollama client installed. - -Create an Ollama shell using `fly machine run`: - -``` -$ fly machine run --shell ollama/ollama -``` - -Once that starts up, point the Ollama client to your Flycast app by setting the `OLLAMA_HOST` environment variable: - -``` -# export OLLAMA_HOST=http://xe-ollama.flycast -``` - -Then you can ask Llama 3 anything you want: - -```javascript -# ollama run llama3 "Why is the sky blue?" -``` - -It took a moment for Ollama to get ready and download the image, then it downloaded it and answered your question. Once it’s been idle for a moment, the platform will turn Ollama back off. - -And there we go! We’ve covered what Flycast is, why you’d want to use it, and set up an instance of Ollama to show it off. +And there we go! We’ve covered what Flycast is, why you’d want to use it, and walked through deploying a private HTTP service to show it off. The same pattern works for any internal app: admin panels, internal APIs, dashboards, or anything else you'd rather keep off the public internet. ## Related reading -We've talked about Flycast in some past blog posts and blueprints: - - [Autostart and autostop private apps](/docs/blueprints/autostart-internal-apps/) -- [Deploy Your Own (Not) Midjourney Bot on Fly GPUs](https://fly.io/blog/not-midjourney-bot/) -- [Scaling Large Language Models to zero with Ollama](https://fly.io/blog/scaling-llm-ollama/) +- [Flycast — private Fly.io services](/docs/networking/flycast/) +- [Private networking](/docs/networking/private-networking/) From 06fef088e57bcbc96e888e76fb29f3fef7e2766f Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Wed, 29 Apr 2026 22:04:54 +0000 Subject: [PATCH 2/7] Fix broken IP addresses reference link The link pointed at /docs/reference/services/#ip-addresses, which no longer exists. The relevant content lives at /docs/networking/services/#anycast-ip-addresses. --- blueprints/private-applications-flycast.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index b968b72b31..35848e7b18 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -70,7 +70,7 @@ VERSION IP TYPE REGION CREATED AT v6 fdaa:3:9018:0:1::7 private global 23h12m ago ``` -Learn more about [Fly.io public, private, shared and dedicated IP addresses](/docs/reference/services/#ip-addresses). +Learn more about [Fly.io public, private, shared and dedicated IP addresses](/docs/networking/services/#anycast-ip-addresses). This app only has one IP address: a private Flycast IPv6 address. If it had public IP addresses, it'd look like this: From 7bd8d0b1ee996f2f6945580d134bbc5215fd10be Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Fri, 15 May 2026 18:19:29 +0000 Subject: [PATCH 3/7] Set internal port to 80 for nginxdemos/hello The image listens on port 80, but fly launch defaults the internal port to 8080, which leaves the app unreachable over Flycast. Pass --internal-port 80 explicitly and explain why. --- blueprints/private-applications-flycast.html.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index 35848e7b18..9e81bc1201 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -57,11 +57,13 @@ If you want to interact with your Flycast apps from your computer, you’ll need Create a new folder on your computer called `flycast-demo` and open a terminal in it. We don't need any source code for this walkthrough — we'll launch the app directly from a public Docker image with the `--flycast` flag, which tells Fly Launch to allocate a private IPv6 address instead of public ones: ``` -fly launch --image nginxdemos/hello --flycast +fly launch --image nginxdemos/hello --flycast --internal-port 80 ``` The name you choose for your app will be the hostname you use to reach it over Flycast (`.flycast`). When `fly launch` asks if you want to tweak the settings, you can accept the defaults. +The `--internal-port 80` flag tells Fly Launch that our app listens on port 80 (the default for the `nginxdemos/hello` image). Fly Launch defaults to port 8080, so without this flag the Fly Proxy wouldn't be able to reach the app. + After deploy finishes, you can see the list of IP addresses associated to an app with `fly ips list`: ``` From 1f30b49c875ea42178b1f1ce8282f310e709604b Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Fri, 15 May 2026 18:43:20 +0000 Subject: [PATCH 4/7] Disable force_https for Flycast-only app in walkthrough fly launch enables force_https in [http_service] by default, which makes the proxy redirect plain HTTP to HTTPS. Flycast addresses don't have public TLS certs, so the redirect breaks the curl example. Add --no-deploy to the launch step, instruct the reader to flip force_https to false, then deploy. --- .../private-applications-flycast.html.md | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index 9e81bc1201..1aced6e4d2 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -54,16 +54,32 @@ If you want to interact with your Flycast apps from your computer, you’ll need ## Steps -Create a new folder on your computer called `flycast-demo` and open a terminal in it. We don't need any source code for this walkthrough — we'll launch the app directly from a public Docker image with the `--flycast` flag, which tells Fly Launch to allocate a private IPv6 address instead of public ones: +Create a new folder on your computer called `flycast-demo` and open a terminal in it. We don't need any source code for this walkthrough — we'll launch the app directly from a public Docker image with the `--flycast` flag, which tells Fly Launch to allocate a private IPv6 address instead of public ones. We'll also pass `--no-deploy` so we can adjust one setting before the first deploy: ``` -fly launch --image nginxdemos/hello --flycast --internal-port 80 +fly launch --image nginxdemos/hello --flycast --internal-port 80 --no-deploy ``` The name you choose for your app will be the hostname you use to reach it over Flycast (`.flycast`). When `fly launch` asks if you want to tweak the settings, you can accept the defaults. The `--internal-port 80` flag tells Fly Launch that our app listens on port 80 (the default for the `nginxdemos/hello` image). Fly Launch defaults to port 8080, so without this flag the Fly Proxy wouldn't be able to reach the app. +Open the generated `fly.toml` in your editor, find the `[http_service]` block, and change `force_https` to `false`: + +```toml +[http_service] + internal_port = 80 + force_https = false +``` + +Fly Launch enables `force_https` by default, which makes the proxy return a 301 redirect from HTTP to HTTPS. That's a good default for public apps, but Flycast addresses don't have public TLS certificates, so the redirect would just break plain HTTP requests from inside your private network. + +Now deploy the app: + +``` +fly deploy +``` + After deploy finishes, you can see the list of IP addresses associated to an app with `fly ips list`: ``` From 0ec9f2ce0d8c34a34a5b26c7734d689eb9c34c18 Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Fri, 15 May 2026 18:47:29 +0000 Subject: [PATCH 5/7] Bump shell Machine memory to 1GB for apt install The default 256MB shell Machine gets OOM-killed midway through 'apt install curl iputils-ping dnsutils'. 1GB has plenty of headroom and avoids a confusing 'Killed' message that makes readers think the walkthrough is broken. --- blueprints/private-applications-flycast.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index 1aced6e4d2..672f6573ca 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -99,10 +99,10 @@ v6 2a09:8280:1::37:7312:0 public (dedicated) global May 30 2024 13:51 v4 66.241.124.113 public (shared) Jan 1 0001 00:00 ``` -Now that we've proven it's private, let’s open an interactive shell Machine to play around with Flycast. Create the shell Machine with `fly machine run`: +Now that we've proven it's private, let’s open an interactive shell Machine to play around with Flycast. Create the shell Machine with `fly machine run`, giving it enough memory to install a few packages with `apt`: ``` -$ fly machine run --shell ubuntu +$ fly machine run --shell --vm-memory 1024 ubuntu root@e784127b51e083:/# ``` From c8531334ed50cd034a50ebc33a47045755a605f2 Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Sat, 16 May 2026 02:13:41 +0000 Subject: [PATCH 6/7] Replace estimated curl timings with measured values --- blueprints/private-applications-flycast.html.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/blueprints/private-applications-flycast.html.md b/blueprints/private-applications-flycast.html.md index 672f6573ca..4dc66464c5 100644 --- a/blueprints/private-applications-flycast.html.md +++ b/blueprints/private-applications-flycast.html.md @@ -146,18 +146,18 @@ You should get back an HTML page with the server's hostname and address. Wait a ``` # time curl -o /dev/null -s http://flycast-demo.flycast -real 0m2.411s -user 0m0.003s -sys 0m0.003s +real 0m1.539s +user 0m0.004s +sys 0m0.012s ``` It took a couple of seconds for the platform to wake the Machine up and make sure it was ready for your request. The next request is a lot faster: ``` # time curl -o /dev/null -s http://flycast-demo.flycast -real 0m0.043s +real 0m0.018s user 0m0.003s -sys 0m0.003s +sys 0m0.008s ``` And if you wait a few moments, it’ll spin back down. From cc546a31b29249a4a3ca381462d5bf3339e4187a Mon Sep 17 00:00:00 2001 From: Kristin Martin Date: Sat, 16 May 2026 02:14:30 +0000 Subject: [PATCH 7/7] Add walkthrough to Vale accept list --- styles/config/vocabularies/fly-terms/accept.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/config/vocabularies/fly-terms/accept.txt b/styles/config/vocabularies/fly-terms/accept.txt index f7aeee2ef9..81bb456740 100644 --- a/styles/config/vocabularies/fly-terms/accept.txt +++ b/styles/config/vocabularies/fly-terms/accept.txt @@ -177,6 +177,7 @@ Vite VSCode Vue (?i)webpack +walkthrough websockets?\b WireGuard