> Source: https://meetrix.io/blogs/headscale-developer-guide/
> Markdown copy of that page. Cite the URL above, not this file.

Development

# Headscale - Developer Guide

[By Binuka Ranatunga](https://meetrix.io/blogs/authors/binuka-ranatunga/) • July 14, 2026 • 7 min read

Learn how to install and configure Headscale on AWS with our step-by-step deployment guide. This comprehensive resource walks you through provisioning your cloud environment, securely deploying Headscale, and operating it reliably at scale on AWS. Whether you're building a private mesh VPN for your team, connecting distributed infrastructure, or replacing a hosted coordination service with a self-managed one, this guide will help you set up and run Headscale efficiently in the cloud.

Welcome to the Headscale Deployment Guide for AWS Integration! Headscale is an open-source, self-hosted implementation of the Tailscale control server, giving you full ownership of your mesh network's coordination layer while continuing to use the official Tailscale client apps on every device. The AMI also bundles **Headplane**, a web-based admin panel for managing users, machines, DNS, and access control. Let's get started and take ownership of your private mesh VPN with Headscale on AWS.

Prerequisites

Before you get started with the Headscale AMI, ensure you have the following prerequisites:

-   Basic knowledge of AWS services, including EC2 instances and CloudFormation.
-   An active AWS account with appropriate permissions.
-   If you encounter a vCPU quota error when launching the stack, follow [https://meetrix.io/blogs/increase-aws-vcpu-quota/](https://meetrix.io/blogs/increase-aws-vcpu-quota/) to increase your vCPU limit.
-   The official Tailscale client installed on any device you plan to connect to your Headscale network.

## Launching the AMI

### Step 1: Find and Select Headscale AMI

1.  Log in to your AWS Management Console.
2.  Navigate to the '[Headscale](https://aws.amazon.com/marketplace/pp/prodview-6gvmv4nn335ei)' listing in AWS Marketplace.

### Step 2: Initial Setup & Configuration

1.  Click the **"Continue to Subscribe"** button.
2.  After subscribing, accept the terms and click **"Accept Terms"**.
3.  Wait a few minutes until processing completes, then click **"Continue to Configuration"**.
4.  Select **"CloudFormation script to deploy Headscale"** as the fulfillment option and choose your region. Click **"Continue to Launch"**.
5.  From the "Choose Action" dropdown, select **"Launch CloudFormation"** and click **"Launch"**.

## Create CloudFormation Stack

### Step 1: Create a stack

1.  Ensure the **"Template is ready"** option is selected under "Prepare template".
2.  Click "Next".

### Step 2: Specify stack options

1.  Provide a unique **"Stack name"**.
2.  Enter your email for **"AdminEmail"** - this is used for SSL certificate generation.
3.  **"AmiId"** is resolved automatically from an SSM parameter - leave it as the default.
4.  Enter a value for **"DeploymentName"**.
5.  Provide a public domain for **"DomainName"**. Headscale will automatically try to set up SSL if the domain is hosted on Route53. If unsuccessful, you must set up SSL manually.
6.  Choose an instance type **"InstanceType"** (Recommended: **t3a.small**, since Headscale is a lightweight coordination server).
7.  Select your preferred **"KeyName"**.
8.  Provide a unique **"S3Bucket"** name used internally by the deployment.
9.  Set **"SSHLocation"** to 0.0.0.0/0.
10.  Keep **"SubnetCidrBlock"** as 10.0.0.0/24.
11.  Keep **"VpcCidrBlock"** as 10.0.0.0/16.
12.  Click "Next".

![CloudFormation stack parameters for a Headscale deployment, including AdminEmail, DeploymentName, DomainName, InstanceType, KeyName, S3Bucket, SSHLocation, SubnetCidrBlock, and VpcCidrBlock](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-01.png)

### Step 3: Configure stack options

1.  Choose "Roll back all stack resources" and "Delete all newly created resources" under "Stack failure options".
2.  Click "Next".

### Step 4: Review

1.  Review and verify the details you've entered.
2.  Tick **"I acknowledge that AWS CloudFormation might create IAM resources with custom names"**.
3.  Click **"Submit"**.

![IAM capability acknowledgment checkbox in the CloudFormation review step](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-02.png)

Afterward, you'll be directed to the CloudFormation stacks page. Please wait for 5-10 minutes until the stack has been successfully created.

## Update DNS

### Step 1: Copy IP Address

Copy the public IP labeled **"PublicIp"** in the **"Outputs"** tab.

![CloudFormation Outputs tab with PublicIp, ServerUrl, and ServerUrlIp values for a Headscale stack](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-04.png)

### Step 2: Update DNS

1.  Go to AWS Route 53 and navigate to "Hosted Zones".
2.  Click **Create record**.
3.  Add a **record name** and paste the copied **PublicIp** into the **value** textbox.
4.  Click "Save".

![Creating an A record in AWS Route 53 pointing a subdomain to the Headscale instance's public IP](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-05.png)

## Access Headscale

The **"Outputs"** tab exposes two URLs: **"ServerUrl"** - the Headscale server URL your Tailscale clients connect to via `--login-server` - and **"ServerUrlIp"**, an HTTP fallback over the Elastic IP until SSL is configured.

Note

If you receive a "502 Bad Gateway" error, wait approximately **5 minutes** and refresh the page. The application may still be initializing.

![502 Bad Gateway error shown while the Headscale service is still starting up](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-24.png)

### Logging into the Headplane admin panel

Headplane authenticates with an API key rather than a username and password. Generate one on the server:

```plaintext
sudo headscale apikeys create
```

Running the command without **sudo** fails with a permission error on the Headscale socket, so make sure to prefix it.

![Generating a Headplane API key with sudo headscale apikeys create after a permission-denied error without sudo](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-14.png)

Navigate to **<ServerUrl>/admin/login** and paste the generated key into the API Key field.

![Headplane admin login screen prompting for an API key](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-06.png)

Once signed in, Headplane shows your registered Machines, Users, Access Control, and DNS settings.

![Headplane Machines dashboard listing a connected device](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-16.png)

## Registering Devices

Connect devices to your private mesh network using the official Tailscale client.

### Step 1: Create a user and generate a pre-auth key

Log in to the server via SSH and run:

```plaintext
sudo headscale users create <user-name>
sudo headscale users list   # get the numeric ID
sudo headscale preauthkeys create --user <user-id> --reusable --expiration 24h
```

![Creating a Headscale user, listing the numeric user ID, and generating a reusable pre-auth key](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-11.png)

### Step 2: Install the Tailscale client

Download and install the official Tailscale client on the device you want to connect from [tailscale.com/download](https://tailscale.com/download).

![Tailscale download page with client installers for macOS, iOS, Windows, Linux, and Android](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-10.png)

### Step 3: Register the device

On the device, run:

```plaintext
tailscale up --login-server=https://<your-domain> --authkey=<pre-auth-key>
```

![Running tailscale up with the login-server and authkey flags to register a Windows device against a Headscale server](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-12.png)

Once connected, the Tailscale client shows the assigned mesh IP and the Headscale server it's connected to.

![Tailscale client tray showing a device connected to a Headscale server with its assigned mesh IP](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-13.png)

## Generate SSL Manually

Headscale will automatically try to set up SSL when a Route53-hosted domain is provided. If it fails, follow these steps to generate SSL manually.

### Step 1: Copy IP Address

1.  Follow the **Update DNS** steps above, if not already done.
2.  Copy the Public IP indicated as **"PublicIp"** in the **"Outputs"** tab.

### Step 2: Log in to the server

1.  Open the terminal and go to the directory where your private key is located.
2.  Run: **ssh -i <your key name> ubuntu@<Public IP address>**
3.  Type "yes" and press Enter to confirm.

![Logging into the Headscale server via SSH for the first time](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-08.png)

### Step 3: Generate SSL

Run the following command and follow the prompts:

```plaintext
sudo /root/certificate_generate_standalone.sh
```

## Check Server Logs

Headscale itself runs as a systemd service on the instance, while the Headplane admin panel runs in Docker.

### Step 1: Log in to the server

```plaintext
ssh -i <your key name> ubuntu@<Public IP address>
```

![Logging into the Headscale server via SSH](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-09.png)

### Step 2: Check the Headscale service logs

```plaintext
sudo journalctl -u headscale
```

![Headscale systemd service logs showing the coordination server starting up and handling client requests](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-18.png)

### Step 3: Check the Headplane container logs

```plaintext
sudo docker ps

sudo docker logs headplane
```

![Docker ps output showing the Headplane admin panel container running](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-17.png)

## Shutting Down Headscale

1.  In CloudFormation, click the link labeled **"Instance"** in the **"Resources"** tab to open the EC2 instance.
![Navigating to the EC2 instance from the CloudFormation Resources tab](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-20.png)3.  Stop the Headscale instance from the **Instance state** dropdown. You can restart it later as needed.
![Stopping the Headscale EC2 instance from the Instance state dropdown](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-21.png)

## Remove Headscale

Delete the CloudFormation stack from the AWS Management Console under "CloudFormation Stacks" by clicking "Delete".

## Upgrades

When a new version is available in AWS Marketplace, remove the previous deployment after backing up necessary server data, and relaunch with the new version.

## Troubleshoot

### vCPU Quota Error

If you face vCPU quota limits, request an increase: [How to increase AWS quota](https://meetrix.io/blogs/increase-aws-vcpu-quota/).

![AWS vCPU quota limit error](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-22.png)

### Insufficient Capacity Error

If you face _insufficient capacity_ errors while creating the stack, try another region or time.

![CloudFormation stack rollback caused by an AWS insufficient instance capacity error](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-23.png)

### Dashboard Access Error

If you see a "502 Bad Gateway" error when accessing the Headplane dashboard, wait 5-10 minutes for the service to finish starting up and then try again.

![502 Bad Gateway error accessing the Headplane dashboard](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-24.png)

### Invalid API Key Error

If Headplane rejects your key with "API key is invalid (it may be incorrect or expired)", generate a new one with **sudo headscale apikeys create** and sign in again.

![Headplane login screen showing an invalid or expired API key error](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-15.png)

### Device Registration Failure

If devices fail to register, confirm the pre-auth key hasn't expired and that the client is pointed at the correct **\--login-server** URL.

### Storage Full Error

Check whether the instance storage is full.

-   Log into the server and run:

```plaintext
df -h
```

![Checking disk usage with df -h on the Headscale server](https://meetrix.io/blog-images/paas-dev-guides/headscale/headscale-19.png)

If the root volume is between 90-100%, resize the EBS volume (per AWS docs), then reboot and restart the service.

## Conclusion

The Meetrix Headscale Deployment Guide helps you integrate a self-hosted Tailscale control server into your AWS environment. Whether you're a DevOps engineer, network administrator, or IT leader, this guide provides step-by-step instructions for a secure and scalable setup.

## Technical Support

Reach out to Meetrix Support ([aws@meetrix.io](mailto:aws@meetrix.io)) for assistance with Headscale issues.

## Frequently Asked Questions

What is Headscale?

Headscale is an open-source, self-hosted implementation of the Tailscale control server. It lets you run your own coordination server for a private WireGuard-based mesh network, without depending on Tailscale's hosted infrastructure.

Do I still need the Tailscale client to connect to Headscale?

Yes. Devices continue to use the official Tailscale client apps, but you configure them to point at your own Headscale server's URL instead of Tailscale's hosted control plane.

What are the prerequisites for installing Headscale on AWS?

You need basic knowledge of AWS services (EC2, CloudFormation), an active AWS account with appropriate permissions, and a sufficient vCPU limit to launch the required instance type.

Which instance type is recommended?

t3a.small is recommended as a baseline for running Headscale on AWS, since the coordination server is lightweight compared to full application workloads.

How do I access the Headplane admin panel?

Headplane (the web UI bundled with the AMI) is served at your ServerUrl with /admin appended. It authenticates with an API key rather than a username and password - generate one on the server by running 'sudo headscale apikeys create' and pasting the result into the login screen.

How do I add new devices (nodes) to my Headscale network?

Create a user with 'headscale users create', generate a pre-auth key with 'headscale preauthkeys create', then run 'tailscale up --login-server=<your-domain> --authkey=<key>' on the device you want to connect.

How do I get technical support?

Reach out to Meetrix Support at [aws@meetrix.io](mailto:aws@meetrix.io) for assistance with Headscale issues.

## Ready to Deploy Your Own Headscale Instance?

Get started in minutes with our pre-configured AMI and take full control of your private mesh network.

[Deploy Headscale from AWS Marketplace](https://aws.amazon.com/marketplace/search/results?searchTerms=headscale+meetrix)

Meetrix Store

Headscale

Your own Tailscale control plane

[Deploy it](https://meetrix.io/store/headscale/)

Meetrix Store New

Deploy what this guide covers, pre-configured.

-    [Headscale Your own Tailscale control plane](https://meetrix.io/store/headscale/)
-    [OpenVPN Encrypted remote access, no per-user fees](https://meetrix.io/store/openvpn/)
-    [RustDesk Remote desktop AMI, a TeamViewer alternative](https://meetrix.io/store/rustdesk/)
-    [Jitsi Meet Self-hosted video calls for 50 to 500 users](https://meetrix.io/store/jitsi-meet/)
-    [Coturn TURN/STUN for WebRTC, no per-minute relay fees](https://meetrix.io/store/coturn/)
-    [Supabase Postgres, Auth, Storage and Realtime, self-hosted](https://meetrix.io/store/supabase/)

[Browse all products](https://meetrix.io/store/)
