Deploying headscale to Fly.io for homelab setupFebruary 19, 2023 -
This time I took my local headscale setup and deployed to Fly.io, to allow nodes from different locations to connect into my homelab mesh network.
This builds on top of work done in previous TIL, but moves away from local testing using Docker and some VMs to real internetz deployment.
▶️ Also made a recording of this that you can watch on YouTube here.
1. Adjusting existing configuration
Decided to do some adjustments to
headscale.yml configuration file in order
to make it easier for me to configure Fly's mount volumes:
-private_key_path: /var/lib/headscale/private.key +private_key_path: /data/private.key
- private_key_path: /var/lib/headscale/noise_private.key + private_key_path: /data/noise_private.key
-db_path: /var/lib/headscale/headscale.sqlite3 +db_path: /data/headscale.sqlite3
2. Create an application in Fly
--generate-name for testing, but you should give a good, memorable
name for your application 😉:
$ flyctl apps create --generate-name New app created: dark-fire-450
And create the volume that we will use to store headscale's database:
$ flyctl volumes create --app dark-fire-450 --region cdg --size 1 headscale_data ID: vol_2n0l9vllx58v635d Name: headscale_data App: dark-fire-450 Region: cdg Zone: 0e8c Size GB: 1 Encrypted: true Created at: 19 Feb 23 12:23 UTC
3. Adjust configuration
flyctl apps create command didn't generate a configuration file, so
we are going to manually create it:
app = "dark-fire-450" kill_signal = "SIGINT" kill_timeout = 5 [metrics] port = 9090 path = "/metrics" [experimental] auto_rollback = true [[services]] internal_port = 8080 protocol = "tcp" [services.concurrency] hard_limit = 25 soft_limit = 20 type = "connections" [[services.ports]] force_https = true handlers = ["http"] port = 80 [[services.ports]] handlers = ["tls", "http"] port = 443 [[services.tcp_checks]] grace_period = "1s" interval = "15s" restart_limit = 0 timeout = "2s" [mounts] source = "headscale_data" destination = "/data"
app indicates the name of the application we just created (
source mountpoint uses the name of the volume we created after.
4. Deploying and updating our configuration
We are ready to deploy our new application:
$ flyctl deploy --region cdg ==> Verifying app config --> Verified app config ==> Building image Remote builder fly-builder-old-fire-5640 ready ==> Creating build context --> Creating build context done ==> Building image with Docker ... ==> Creating release --> release v2 created --> You can detach the terminal anytime without stopping the deployment ==> Monitoring deployment Logs: https://fly.io/apps/dark-fire-450/monitoring 1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 critical]
Note that used
cdg for this application since is the closest region to my
location, but you could use other. See
flyctl platform regions for
After a few seconds, we should be able to SSH into our headscale deployment
$ flyctl ssh console Connecting to fdaa:0:5fde:a7b:5b66:5:4cd:2... complete
And we can create our homelab network and keys to use with our nodes:
/ # headscale users create homelab User created / # headscale --user homelab preauthkeys create --reusable --expiration 24h df72670243f0f635bc2b5d73e5a42f1c40564d9c954dfd78
This time I used preauthorized keys so I could apply the same key to multiple nodes without having to approve each node manually.
Then, tested against a remote servers and connected them to the mesh network, using the same key:
$ tailscale up --login-server https://dark-fire-450.fly.dev:443 --authkey df72670243f0f635bc2b5d73e5a42f1c40564d9c954dfd78
5. What's next?
Now we have some data out there, what would be our backup strategy? How could we avoid losing all the configuration of our nodes and mesh network?
More of that in future posts! 😊