If you have multiple PCs in different places and want to pull them into one private network for things like:
- SSH access
- internal apps
- service sharing
- a distributed homelab
then a very practical approach is:
- one
AWS EC2 t3.micro HeadscaleTailscaleclients on each machine
And if you want to expose selected web apps publicly, you can put Nginx in front as a reverse proxy.
Quick conclusion
If you want the short version:
- use a
t3.microas a small coordination server forHeadscale - install
Tailscaleon each PC and join them into the same private network - treat those machines as a private “cluster” for SSH, apps, monitoring, or self-hosting
- if needed, add
Nginxto reverse proxy or selectively expose public web apps
The problem this setup solves
You may have:
- one PC at home
- one mini PC at the office
- one test machine
- one dev laptop
- one small VPS or EC2 instance
These machines are not on the same LAN, and many may sit behind NAT or CGNAT, but you still want them to behave like one connected private environment.
That is where Headscale + Tailscale becomes very practical.
Why choose AWS t3.micro?
According to AWS, T3 instances are burstable general-purpose instances designed for moderate workloads with occasional short spikes.
Source:
For roles such as:
- a small coordination server
- lightweight control plane
- basic reverse proxy
- simple DNS / ACL / management tasks
t3.micro is often a reasonable starting point if your node count is still modest and your relay traffic is not heavy.
In short:
- low cost
- easy to launch
- enough to get started
But it is also important to understand:
- this is not the right size for heavy relay traffic
- if you enable extra services or embedded DERP and grow the setup, you must watch resource usage
What is Headscale?
Headscale is a self-hosted coordination server compatible with Tailscale clients.
According to the official Headscale docs, nodes must register with Headscale in order to use it as their coordination server instead of the default control plane.
Source:
In practical terms:
Tailscaleruns on the client machinesHeadscaleis the server you host and control
This is especially useful when you want to:
- self-host the control plane
- group your own machines into one private network
- manage users, nodes, preauth keys, and routes on your own terms
What does “cluster” mean in this article?
Here, “cluster” is used in the practical homelab sense:
- multiple machines inside the same private mesh network
- they can reach each other by internal IP or DNS
- you can split roles across app, storage, monitoring, and backup nodes
It does not mean you must start with Kubernetes.
You can begin with something much simpler:
- one machine for apps
- one machine for storage
- one machine for testing
- one cloud host for coordination and proxying
A simple architecture
The easiest model is:
- create one EC2
t3.micro - install Ubuntu on it
- install
Headscaleon that EC2 instance - install
Tailscaleon each PC client - join each client to Headscale with
--login-server - if needed, install
Nginxon the EC2 instance or another node
The result:
- one control node on AWS
- multiple PCs in different places
- one private cross-NAT network
Important ports to remember
At minimum, you should care about:
80/tcp443/tcp
If Headscale is placed behind a reverse proxy, the usual pattern is:
Nginxlistens on80/443Headscalelistens internally on something like8080
According to the official Headscale reverse proxy docs:
- the reverse proxy must support WebSockets
Source:
If you enable Headscale’s embedded DERP server, the docs also state that you need:
3478/udpfor STUN
Source:
Installing Headscale on EC2
According to the official docs, the recommended path on Ubuntu/Debian is the official .deb package.
Source:
If you prefer a cleaner homelab workflow, you can also run Headscale in a container.
Container docs:
For a t3.micro, both approaches are valid.
If you already use Docker heavily, the container path is often easier to back up and move.
What should a minimal Headscale config include?
At minimum:
server_urlshould be the public domain of your Headscale instancelisten_addrshould define the internal service port- if
Nginxterminates TLS, you can disable TLS directly in Headscale
The reverse proxy docs show a pattern like:
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
tls_cert_path: ""
tls_key_path: ""
The idea is:
- Headscale listens on an internal port
- Nginx handles public HTTPS
Installing Nginx to reverse proxy Headscale
This is a strong option if you want:
- a clean public domain
- multiple apps on the same EC2 instance
- the ability to expose selected web services later
According to the official reverse proxy docs, Nginx needs:
proxy_http_version 1.1UpgradeConnectionproxy_buffering off
because Headscale depends on WebSockets for correct client communication.
In short:
- if WebSockets are configured incorrectly, clients may fail
Using Tailscale clients to join Headscale
According to the official Headscale getting started docs, on Linux/BSD clients you can use:
tailscale up --login-server <YOUR_HEADSCALE_URL>
Or if you want a non-interactive registration with a preauth key:
tailscale up --login-server <YOUR_HEADSCALE_URL> --authkey <YOUR_AUTH_KEY>
Source:
On the server side, you can:
- create users
- create preauth keys
- assign nodes to those users
Examples from the docs:
headscale users create <USER>
headscale preauthkeys create --user <USER_ID>
Turning multiple PCs into one private cluster-like network
Once multiple machines have joined, you have a private mesh network that can be used for:
- SSH between nodes
- internal API calls
- service-to-service traffic
- monitoring
- role separation between nodes
For example:
- PC 1: Docker app host
- PC 2: storage or backup node
- PC 3: test environment
- EC2: control plane + reverse proxy
Even this simple setup already gives you a very useful homelab “cluster.”
What is Nginx doing in this architecture?
There are two very natural uses:
1. Reverse proxy for Headscale itself
Goal:
- expose
headscale.example.com - keep Headscale on an internal port
- let Nginx handle TLS
This is the common pattern if you want a clean domain.
2. Public reverse proxy for selected web apps
For example, you may have:
- Grafana on one PC inside the tailnet
- an internal dashboard on another node
- a personal web tool on a third node
You can use Nginx to:
- map subdomains
- route requests to the right node or service
- selectively expose only the apps you actually want public
But it is important to separate:
- private mesh traffic inside Tailscale / Headscale
- public HTTP traffic through Nginx
Those are not the same layer.
Pros of the t3.micro + Headscale + Tailscale + Nginx model
1. Great for a distributed homelab
Your machines do not need to be in the same place.
As long as they have outbound internet access and can join the tailnet, they can become part of one shared network.
2. Self-hosted control plane
This matters if you want more control over the coordination layer.
3. No need to open ports on every PC
You do not have to forward router ports for every home or office machine just to make them reachable internally.
4. Easy to expand gradually
You can start with:
- two machines
- three machines
- a few small apps
and grow over time.
Cons and caveats
1. t3.micro is a starting point, not a forever-scale answer
T3 is burstable. If you have:
- many nodes
- more control-plane load
- extra services on the same box
- significant relay traffic
then t3.micro can become the bottleneck.
2. Headscale behind reverse proxy must be configured correctly for WebSockets
According to the official docs, this is mandatory.
Get it wrong and client connectivity may break.
3. If you use embedded DERP, you need extra UDP exposure
The official docs explicitly call out 3478/udp for STUN when embedded DERP is enabled.
4. Do not publish every internal app through Nginx
This architecture makes it tempting to expose every internal dashboard publicly.
You should clearly separate:
- what stays private inside the tailnet
- what truly needs to be public
When is this architecture especially worth doing?
This model is especially strong if you:
- have multiple PCs in different places
- want them pulled into one private network
- want to learn self-hosting and homelab in a serious way
- want a small cloud-based coordination point
- want the option to expose selected web apps through Nginx
Quick implementation checklist
If you want a fast implementation path:
- create an EC2
t3.micro - attach a stable public IP or domain
- install Headscale
- configure a domain like
headscale.example.com - place Nginx in front
- create users and preauth keys
- install Tailscale on each PC
- join each node with
--login-server - verify ping / SSH / internal service reachability
- expose only the web apps that truly need public access
Conclusion
An AWS EC2 t3.micro can absolutely be a strong starting host for:
Headscale- a private
Tailscalenetwork across multiple PCs - a distributed homelab cluster
- and
Nginxfor reverse proxy or public web exposure when needed
This architecture is practical because:
- the starting cost is low
- it is easy to learn
- it expands gradually
- it is useful both for lab work and for small real-world setups
The key idea is:
- use
Headscalefor private mesh coordination - use
Tailscaleto pull nodes into the network - use
Nginxfor selective public exposure
If you get those three layers right, you can build a surprisingly capable setup starting from just one t3.micro.