profile picture

Expose home VM to the internet using Fly's Private Network and WireGuard

January 07, 2023 - fly wireguard caddy homelab

I wanted to host applications on private servers and have them accessible on the internet.

But wanted to avoid having to punch holes on internet routers, exposing my home/office IP or having to figure out more complex stuff.

With this in mind, thought about using Fly's Private Network (also known as 6PN) with a custom node and connect the Fly org network with it.

Then, deploy an app to Fly that routes traffic back to this private instance.

▶️ I also made a recording of this that you can watch on YouTube here.

1. Have a VM, server and web server running 😉

For this I used a small Alpine Linux VM with nginx, running on port 80. Nothing special on this, set it up using QEMU to avoid impacting my local setup.

2. Create a WireGuard tunnel with Fly

Follow Fly's Private Network VPN instructions and generate a WireGuard profile for your setup.

$ flyctl wireguard create personal cdg alpine-small-vm

personal is my Fly Organization, cdg is Paris region and alpine-small-vm is the name for the tunnel.

When asked, give a name to store the wireguard configuration (Eg. the one you used for the VM, alpine-small-vm.conf).

Transfer this file to the VM or the machine that will connect to Fly's 6PN

$ scp alpine-small-vm.conf [email protected]:.

3. Connect the VM to Fly using WireGuard

Setup WireGuard on the machine:

$ apk add -U wireguard-tools bind-tools

$ mv ~/alpine-small-vm.conf /etc/wireguard/

And connect using wg-quick up alpine-small-vm.

You can verify using dig for apps and see other peers, getting their IPs:

$ dig +short txt _apps.internal

$ dig +short txt _peer.internal

4. Deploy the Fly app that proxy the connection

We will use Caddy since provides the simplest reverse proxy

Create a Caddyfile configuration:

:8080 {
    reverse_proxy alpine-small-vm._peer.internal:80

This indicates to use port 8080 and to proxy all the requests to our VM, using port 80.

Now, create a Dockerfile for the app:

FROM caddy:2.6.2

COPY Caddyfile /etc/caddy/Caddyfile

With that in place, use flyctl to setup your application:

$ flyctl launch
Scanning source code
Detected a Dockerfile app
Wrote config file fly.toml
? Would you like to deploy now? No
Your app is ready! Deploy with `flyctl deploy`

Remember to answer no to the deploy question so we can adjust the generated configuration.

Update fly.toml to enable the private_network experimental feature (this could be obsolete information, need to confirm).

  private_network = true

Now you can deploy:

$ flyctl deploy

Once deploy completes, visiting the app URL should automatically proxy web traffic to your internal VM.

5. That's all!

Now that you can route web traffic to your VM, you could setup different domain names and have those routed to different machines in the private network or into more complex configurations.

Enjoy! ❤️