Headscale in free plan (Newcommer!)


This morning, a VM my friend gave me roughly 10 years ago finally imploded (I blame GRUB - it’s always GRUB when systems I use stop working…) and now my Headscale VPN is hanging suspended mid-air untill my IP changes and the homeserver to remote server connection completely drops.

Now, all I want to do is host a Headscale instance, which technically should fit into the Free Plan just fine. But, I am a little puzzled by the various methods of how to get an app running…

Basically, I just need to:

  • Spin up a tiny maschine
  • Have SSH access
  • Install Headscale and Caddy
  • Configure users, generate preauth keys
  • Leave.
  • Come back once every few weeks to update!

Whilst I can remote-control Headscale for some part, the initial setup does require manual configuration, and an SSL cert (Let’s Encrypt should do nicely, which is what Caddy is to be used for).

Can you help me find a pointer so I can get started?

Also as an aside, the documentation reads “Up to 3 shared-cpu-1x 256mb VMs”. Does that mean I can have three free apps running, or does this amount depend on which type of maschine/VM I allocate?

Thank you and kind regards,

From the highish level I would probably write a dockerfile with FROM set to one of the headscale releases here and then write in that dockerfile as much as can be done to bootstrap the VM.

If you need a lot of manual intervention you could hop in via fly ssh console to complete any steps.

One reason it might be nice to really work on making it fully automated (or close to) is in case your VM OOMs or something, our orchestration can reboot it for you and try to keep it up. If it’s just that you need some data to be pre-setup you could attach a volume, then when that machine reboots it should re-attach to the volume and continue working as expected.

But once that Dockerfile is close to something you’d want to run you can fly launch to create your app, pick a region etc. At this point you’d setup and configure your volume with your fly.toml if you wanted to do that, then fly deploy to boot the dockerfile on the VM.

We don’t care if it’s one app or 3 but there’s a little detail that’s probably worth calling out. At the moment we sometimes ask for a credit card to create more than an app or two but that doesn’t mean we’ll charge you necessarily - it’s an abuse prevention mechanism more than anything.

1 Like

Also, fly.io can provision an SSL cert for you, so you don’t need Caddy

1 Like

I just attempted to create the Headscale app, trying to make sure that it would only spawn exactly one instance with one volume. In fact, the 1GB volume is actually overkill, as Headscale only needs jusr around 20MB for logs, config and SQLite.

So, I came up with this - using what flyctl launch gave me and modifying it a little.

# fly.toml app configuration file generated for drachennetz on 2023-05-09T14:50:41+02:00
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.

app = "drachennetz"
kill_signal = "SIGINT"
kill_timeout = 5
primary_region = "cdg"
processes = []

  image = "headscale/headscale:latest"


  auto_rollback = true

  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
    hard_limit = 1
    soft_limit = 1
    type = "connections"

    force_https = true
    handlers = ["http"]
    port = 80

    handlers = ["tls", "http"]
    port = 443

    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"


The mount destination is chosen from the Headscale docs.

There’s two problems I am facing now:

  1. This is literally my first app, aside from the delicate-flower - which seems to be my Docker builder - I have nothing on that account. And yet, I am immediately asked for my credit card; but I haven’t even be able to copy my config file over. Headscale needs a config file to work.
  2. I can’t pre-populate a volume. I only need to do two things; copy a config file, and create an empty file which will serve as the SQLite DB.

I did see that in fly.toml one can also add a Dockerfile. That had me wonder: Can I specify a local docker file, that then just copies that config into the volume if it doesn’t exist yet?

Honestly, I have very basic experience with Docker - and even mainly with Docker Compose for my home server needs. So I might be overlooking something here…

Got an idea what I can do here?


Yep we automatically create a builder app (it’s included for accounts) so you can build the app without physically installing docker on your own machine.

This can happen for a few reasons. You won’t necessarily get charged but some things will often trip this earlier for some folks: How We Use Credit Cards · Fly Docs. Here’s some detail about our included allowances, so again, you won’t necessarily see a bill.

Yea there are a couple things here to consider. I would definitely specify your own dockerfile and just FROM headscale/headscale:latest

If you need that config to be in the volume, you could copy it as part of the CMD, just like a first step in a bash script or something. Does it need to change a lot and persist across VM restarts though? If not, you could just COPY the config in and let it be part of the image itself. You’d need to COPY it for the CMD approach too because it’ll need to be on image when your boot script runs.

It sounds like you’d need that SQLite to persist though so I’ll show you what I meant by a wrapped command init:

# Dockerfile
FROM headscale/headscale:latest


COPY init.sh .

CMD ./init.sh

# init.sh
#!/usr/bin/env bash

# Make sure DB exists
touch /etc/headscale/headscale.db


Or at least I think that’d work? Here’s where I got that headscale was the command: Docker - Then you need to chmod +x init.sh as well.

If you decided to use this init script to pull in the config, you’d do a similar COPY and add something like cp /app/config /etc/headscale/config to that init.sh