From 454039fd1819d0b43d5d288600527dc243e5e25f Mon Sep 17 00:00:00 2001 From: Nick Yeoman Date: Thu, 17 Sep 2026 21:01:50 -0700 Subject: [PATCH] headscale start --- headscale_dev/README.md | 6 ++- headscale_dev/compose.yaml | 1 - headscale_dev/index.html | 101 ------------------------------------- headscale_dev/sample.env | 2 +- 4 files changed, 6 insertions(+), 104 deletions(-) delete mode 100644 headscale_dev/index.html diff --git a/headscale_dev/README.md b/headscale_dev/README.md index b473bf5..ce346eb 100644 --- a/headscale_dev/README.md +++ b/headscale_dev/README.md @@ -48,7 +48,7 @@ cp sample.env .env docker compose up -d ``` -Then point Nginx Proxy Manager at it (see Network Notes below) so `https://headscale.example.com` reaches the container. Verify with: +Then point Nginx Proxy Manager at the `headscale` container, port `8080` (see Network Notes below) so `https://headscale.example.com` reaches it. Verify with: ```bash curl https://headscale.example.com/health @@ -171,6 +171,10 @@ Back up `data/` and `config/` regularly for recovery. * Reverse proxy requirements (Nginx Proxy Manager), for `headscale.example.com`: * Forward hostname: `headscale`, forward port: `8080`, scheme: `http` * Enable: Websockets Support ✔, Block Common Exploits ✔, SSL (Let's Encrypt) ✔, disable caching ✔ +* Optional: to reach the `headscale-ui` admin panel from a browser, add a **second** proxy host on a separate subdomain (e.g. `headscale-admin.example.com`): + * Forward hostname: `headscale-ui`, forward port: `80`, scheme: `http` + * Enable: Block Common Exploits ✔, SSL (Let's Encrypt) ✔ + * The UI container already talks to Headscale internally via `HEADSCALE_URL=http://headscale:8080` (see compose.yaml) — no extra config needed Firewall considerations on the dedicated server: only 80/443 (reverse proxy) need to be open inbound. On the LAN node: allow UDP 41641 outbound/inbound for direct WireGuard connections (Tailscale falls back to DERP relays if blocked, just slower). Do **not** forward 8096 (Jellyfin) or 8080 (Headscale) on any router. diff --git a/headscale_dev/compose.yaml b/headscale_dev/compose.yaml index 3f230ab..5af5006 100644 --- a/headscale_dev/compose.yaml +++ b/headscale_dev/compose.yaml @@ -13,7 +13,6 @@ services: - proxy - internal command: - - headscale - serve headscale-ui: diff --git a/headscale_dev/index.html b/headscale_dev/index.html deleted file mode 100644 index 07d93aa..0000000 --- a/headscale_dev/index.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - -Headscale Quick Start — Zero to Jellyfin in 15 Minutes - - - - -

Headscale Quick Start

-

Goal: reach Jellyfin (and other containers) on your home LAN from anywhere, -without exposing anything to the internet. Zero to working in about 15 minutes.

- -

The setup

-
-[Phone / Laptop]
-        |
-   Tailscale client
-        |
-[Dedicated Server]   ← public IP, runs Headscale (control plane only)
-        |
-   Tailscale network (WireGuard mesh)
-        |
-[LAN Node]           ← Docker host at 192.168.x.x, runs Jellyfin
-
-

The dedicated server only coordinates the mesh. Your media streams directly -between your device and the LAN node over encrypted WireGuard.

- -

Checklist

-
    -
  1. ☐ Install Headscale on the dedicated server
  2. -
  3. ☐ Create a user
  4. -
  5. ☐ Generate an auth key
  6. -
  7. ☐ Join the LAN node (and your phone/laptop)
  8. -
  9. ☐ Open Jellyfin at http://jellyfin:8096 or the Tailscale IP
  10. -
- -

1. Install Headscale (dedicated server)

-

From this repo's headscale_dev/ directory:

-
mkdir -p /data/headscale/config
-cp config.yaml /data/headscale/config/config.yaml
-nano /data/headscale/config/config.yaml    # set server_url: https://headscale.example.com (YOUR domain)
-
-cp sample.env .env
-docker compose up -d
-

Point your reverse proxy (Nginx Proxy Manager) at container headscale, -port 8080, with SSL and websockets enabled. Then verify:

-
curl https://headscale.example.com/health
- -

2. Create a user

-
docker compose exec headscale headscale users create homelab
- -

3. Generate an auth key

-
docker compose exec headscale headscale preauthkeys create --user homelab --expiration 1h
-

Copy the key it prints.

- -

4. Join the LAN node

-

On the LAN node (your Docker host running Jellyfin):

-
curl -fsSL https://tailscale.com/install.sh | sh
-sudo tailscale up --login-server=https://headscale.example.com --authkey <YOUR-PREAUTH-KEY>
-

On your phone: install the Tailscale app, choose custom / alternate coordination server, -and enter https://headscale.example.com. On a laptop, run the same -tailscale up command with a fresh key.

-

Verify from your laptop:

-
tailscale status
-tailscale ping <lan-node-name>
- -

5. Open Jellyfin

-

With Tailscale connected on your device, open:

- - -
Optional — reach the rest of your LAN: on the LAN node run -sudo tailscale up --login-server=https://headscale.example.com --advertise-routes=192.168.1.0/24, -enable IP forwarding, then approve the route with -headscale nodes approve-routes on the server. See the README for details.
- -
Firewall: only 80/443 open on the dedicated server. Never forward -port 8096 (Jellyfin) or 8080 (Headscale) on your router.
-Lost a device? Cut it off instantly: -docker compose exec headscale headscale nodes delete -i <NODE-ID>
- -

Full walkthrough, subnet routing, and gotchas: see README.md in this directory.

- - - diff --git a/headscale_dev/sample.env b/headscale_dev/sample.env index 5bc2e54..47b69e0 100644 --- a/headscale_dev/sample.env +++ b/headscale_dev/sample.env @@ -1,7 +1,7 @@ # Compose VOL_PATH=/data HEADSCALE_IMAGE=headscale/headscale:latest -HEADSCALE_UI_IMAGE=goodieshq/headscale-admin:0.26 +HEADSCALE_UI_IMAGE=goodieshq/headscale-admin:0.28 HEADSCALE_RESTART=unless-stopped HEADSCALE_UI_RESTART=unless-stopped