Coder Social home page Coder Social logo

headplane's Introduction

Headplane

An advanced UI for juanfont/headscale

Preview

Headscale is a self-hosted version of the Tailscale control server, however, it currently lacks a first-party web UI. Headplane aims to solve this issue by providing a GUI that can deeply integrate with the Headscale server. It's able to replicate nearly all of the functions of the official Tailscale SaaS UI, including:

  • Machine/Node expiry, network routing, name, and owner management
  • Access Control List (ACL) and tagging configuration
  • Support for OpenID Connect (OIDC) as a login provider
  • DNS and safe Headscale configuration management

Deployment

For more configuration options, refer to the Configuration guide.

For fully-featured deployments, see the Advanced Deployment guide. This includes automatic management of ACLs, DNS settings, and Headscale configuration. This is the closest experience to the Tailscale UI that can be achieved with Headscale and Headplane. If you aren't sure which one to pick, we recommend this.

If your environment is not able to support the advanced deployment, you can still use the basic deployment. For basic deployments, see the Basic Deployment guide. It does not include automatic management of ACLs, DNS settings, or the Headscale configuration, instead requiring manual editing and reloading when making changes.

Contributing

If you would like to contribute, please install a relatively modern version of Node.js and PNPM. Clone this repository, run pnpm install, and then run pnpm dev to start the development server.

Copyright (c) 2024 Aarnav Tale

headplane's People

Contributors

tale avatar

Stargazers

Sven Greb avatar  avatar José Peña avatar Even Holthe avatar jon ⚝ avatar Salem Harrache avatar Shi Hao avatar njzy avatar Grzegorz Szwyngiel avatar Izac Joof Forsgren avatar  avatar Niklas avatar Hendrik Brombeer avatar Gage Orsburn avatar Python.Swift avatar Hover avatar  avatar Suri avatar  avatar Rubikoid avatar Pavel Genov avatar Benjamin Staffin avatar Sandro avatar Alessandro Digilio avatar zhtyytg avatar T@T avatar bannert avatar MSTCL avatar yimy avatar  avatar  avatar Snuupy avatar  avatar  avatar DiuDiu avatar Maurice Hansen avatar Leopere avatar Sergio Teixeira avatar  avatar bri avatar  avatar BlazeDev avatar 懒猫 avatar DaRK AnGeL avatar  avatar Ben Mehlman avatar  avatar Matthieu Borgognon avatar

Watchers

Ben Mehlman avatar  avatar  avatar

Forkers

gageorsburn

headplane's Issues

Syntax highlighting in ACL Editor

Small syntax highlighting issue in the ACL editor I noticed, commented out ACLs are still highlighted.

image

No functional impact, but I could see it being confusing if you rely on the editor to make changes.

ACL Documentation - ?add headscale link

I'm just getting started out with ACLs and it's great to have a link to the Tailscale webpage on this to click on easily from the headplane webui, but I wondered whether it's worthwhile to add a second link to the headscale documentation on the topic here?

Unable to parse newly created API key from Headscale

Overview:

When attempting to connect to a newly instantiated instance of headscale, I am attempting to generate a new API key, as per the instructions from the /admin interface. However, when I paste the newly created API key, I am getting an error saying it is unable to be parsed. I have tried using older versions, as well, but that does not seem to fix the issue.

docker-compose.yaml

version: '3.8'
services:
  headscale:
    image: 'headscale/headscale:0.23.0-alpha11'
    container_name: 'headscale'
    restart: 'unless-stopped'
    command: 'serve'
    volumes:
      - './data:/var/lib/headscale'
      - './config:/etc/headscale'
    ports:
      - '8081:8080'
      - '9090:9090'
      - '50443:50443'
    environment:
      TZ: 'America/Chicago'

  headplane:
    container_name: headplane
    image: ghcr.io/tale/headplane:latest
    restart: unless-stopped
    volumes:
      - './data:/var/lib/headscale'
      - './config:/etc/headscale'
      - '/var/run/docker.sock:/var/run/docker.sock:ro'
    ports:
      - '8888:3000'
    environment:
      HEADSCALE_URL: 'http://headscale:8080'
      COOKIE_SECRET: '<redacted>'
      API_KEY: '<redacted>'


      # These are the default values
      HOST: '0.0.0.0'
      PORT: '3000'

Generating API key from Headscale:

ash-4.4# docker-compose exec -it headscale headscale apikeys create
2024-05-27T09:55:17-05:00 TRC DNS configuration loaded dns_config={"Nameservers":["9.9.9.9"],"Proxied":true,"Resolvers":[{"Addr":"9.9.9.9"}]}
An updated version of Headscale has been found (0.23.0-alpha9 vs. your current v0.23.0-alpha11). Check it out https://github.com/juanfont/headscale/releases
m92-EDp_-w.ybA6119_PajJHvdZsrw9m6aGAlEdiOVJopDkeIni9w8

Attempting to use the API Key

headplane using new api key

docker-compose logs from headscale when attempting to use the API key

headscale  | 2024-05-27T09:56:11-05:00 ERR home/runner/work/headscale/headscale/hscontrol/app.go:398 > failed to validate token error="failed to parse ApiKey" client_address=172.22.0.3:39080
headplane  | HeadscaleError: Unauthorized
headplane  |     at pull (file:///app/build/server/index.js?t=1716401776000:896:11)
headplane  | GET /admin/machines?_data=routes%2F_data.machines._index 500 - - 10.767 ms
headplane  | GET /admin/login?_data=routes%2Flogin 200 - - 5.428 ms

Remove the requirement for `API_KEY` when not using OIDC.

The API_KEY environment variable exists solely to issue new shorter-lived API keys for each successful OIDC based login. This is not required if login is completed via the "Bring your own API key" option on the login page.

Currently, if this is not set the UI will crash. This is a relatively simple fix, just a few parts of the code actually use the API_KEY variable, otherwise it defaults to the session's stored key.

Headplane cannot resolve DNS queries at times.

Trying to set up headplane and getting this error in the log,

headplane  | GET /admin/ 302 - - 1.923 ms
headplane  | GET /admin/machines 302 - - 4.647 ms
headplane  | TypeError: Cannot read properties of undefined (reading 'issuer')
headplane  |     at getOidcConfig (file:///app/build/server/index.js?t=1715826667000:492:27)
headplane  |     at getContext (file:///app/build/server/index.js?t=1715826667000:480:19)
headplane  |     at loader$9 (file:///app/build/server/index.js?t=1715826667000:605:20)
headplane  |     at Object.callRouteLoader (/app/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/data.js:66:16)
headplane  |     at /app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:4266:21
headplane  |     at callLoaderOrAction (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:4328:16)
headplane  |     at async Promise.all (index 0)
headplane  |     at callDataStrategyImpl (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:4169:17)
headplane  |     at callDataStrategy (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:3503:19)
headplane  |     at loadRouteData (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:3447:19)
headplane  | GET /admin/login 500 - - 10.136 ms

Page shows "unexpected server error".

This is my docker-compose,

  headscale:
    image: headscale/headscale:0.23.0-alpha11
    container_name: headscale
    volumes:
      - ./headscale/config:/etc/headscale/
      - ./headscale/data:/var/lib/headscale
    #ports:
     # - 8080:8080
    command: serve
    restart: unless-stopped
    networks:
      reverseproxy-nw:

  headplane:
    container_name: headplane
    image: ghcr.io/tale/headplane:latest
    restart: unless-stopped
    volumes:
      - './headscale/data:/var/lib/headscale'
      - './headscale/config:/etc/headscale'
      - '/var/run/docker.sock:/var/run/docker.sock:ro'
    ports:
      - '3000:3000'
    networks:
      reverseproxy-nw:
    environment:
      # This is always required for Headplane to work
      COOKIE_SECRET: 'BunchFabulousGalvanizeHardcore'
      #CONFIG_FILE: './headscale/config/config.yaml'
      HEADSCALE_CONTAINER: 'headscale'
      DISABLE_API_KEY_LOGIN: 'true'
      HOST: '0.0.0.0'
      PORT: '3000'

Please let me know if you know what might be causing this, thank you.

DNS Page shows `Cannot read properties of undefined (reading 'map')`

Attempting to go to the DNS page throws an error message

Cannot read properties of undefined (reading 'map')

image

In the logs:

2024-05-05T19:47:52.908171962Z GET /admin/dns?_data=routes%2F_data.dns._index 200 - - 2.344 ms
2024-05-05T19:52:43.188919535Z TypeError: Cannot read properties of undefined (reading 'map')
2024-05-05T19:52:43.188950076Z     at Domains (file:///app/build/server/index.js?t=1714546338000:1970:30)
2024-05-05T19:52:43.188953207Z     at Uc (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:70:44)
2024-05-05T19:52:43.188954830Z     at Xc (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:72:253)
2024-05-05T19:52:43.188956575Z     at Z (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:78:89)
2024-05-05T19:52:43.188958039Z     at Yc (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:81:98)
2024-05-05T19:52:43.188959496Z     at $c (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:80:140)
2024-05-05T19:52:43.188960916Z     at Z (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:78:345)
2024-05-05T19:52:43.188962319Z     at Yc (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:81:98)
2024-05-05T19:52:43.188963810Z     at Xc (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:73:145)
2024-05-05T19:52:43.188965283Z     at Z (/app/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:78:89)
2024-05-05T19:52:43.194205849Z GET /admin/dns 500 - - 86.168 ms
2024-05-05T19:52:43.394923776Z Error: No route matches URL "/favicon.ico"
2024-05-05T19:52:43.394944376Z     at getInternalRouterError (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:4519:5)
2024-05-05T19:52:43.394946959Z     at Object.query (/app/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:2958:19)
2024-05-05T19:52:43.394948534Z     at handleDocumentRequestRR (/app/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:184:35)
2024-05-05T19:52:43.394950208Z     at requestHandler (/app/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:108:24)
2024-05-05T19:52:43.394951778Z     at /app/node_modules/.pnpm/@[email protected][email protected][email protected]/node_modules/@remix-run/express/dist/server.js:41:28
2024-05-05T19:52:43.396383575Z GET /favicon.ico 404 - - 54.286 ms

Now I have been editing my headscale config, although everything seems to be fine and working, so I'm going to nuke and pave and see if I can reproduce this on a fresh install and will report back, as it's entirely possible I've found some weird edge case as it was working fine previously.

I've rolled back both headscale to alpha9 and headplane to 0.1.1 and 0.1.2 without any change

User Permissions

It should limit users' Permissions. currently, everyone who can log in with OIDC can manage all the config.

Update ACL do not send SIGHUP signal to headscale container

When I update acl config in headplane editor, file are saved, but headplane do not send signal SIGHUP to headscale container

  headscale:
    image: ghcr.io/juanfont/headscale:sha-c8ebbed-debug@sha256:46683f33ebdcc3e61c7966bc7299d267c9f850318ebe0b44864cc0d2ce2163ac
    container_name: 'headscale'
    restart: 'unless-stopped'
    command: 'serve'
    volumes:
      - './data:/var/lib/headscale'
      - './configs:/etc/headscale'
    ports:
      - '8080:8080'
  headplane:
    container_name: headplane
    image: ghcr.io/tale/headplane:0.1.6@sha256:0a72d17a548b4b8dc7d4f81e35ee0d1f5c34261f5ec079f06df308d1c74eee86
    restart: unless-stopped
    volumes:
      - './data:/var/lib/headscale'
      - './configs:/etc/headscale'
      - '/var/run/docker.sock:/var/run/docker.sock'
    ports:
      - '3000:3000'
    environment:
      # This is always required for Headplane to work
      #HEADSCALE_URL: 'http://headscale:8080'
      COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'

      HEADSCALE_INTEGRATION: 'docker'
      HEADSCALE_CONTAINER: 'headscale'
      
      DISABLE_API_KEY_LOGIN: 'true'
      HOST: '0.0.0.0'
      PORT: '3000'

Deep integration without the need for Docker

I realize that using Docker is a non-starter for a lot of people, so the goal is to support the configuration and ACL changes when Headscale is running outside of Docker. For now this thread will mostly serve as a list of potential solutions and the work needed. This will also be what holds back a 1.0 release for now.

Work that'll need to be done:

  • Supporting multiple different "control methods"
  • Better error handling on misconfigurations
  • Automatic detection where we can
  • Robust process signaling with Node's process.kill

Docker API:

  • Better handling of access to /var/run/docker.sock
  • Support different socket URLs (not just socket files)
  • Is it possible to detect the container automatically?
  • Support Docker API versions below v1.30

systemd Driver:

  • Use systemctl show --property MainPID --value headscale
  • Handle errors when invalid units or values or provided
  • Validate the responses from systemctl for pids

pidof/pgrep Method:

  • Ensure that pidof/pgrep is actually available on all systems
  • Not resorting to regex to parse the pid out of the output
  • Apparently it's actually unreliable?

DIY Method:

  • Support setting up raw bash scripts to run on trigger
  • Sanity checks, is the script executable, do we have permission?

Edit ACL tags not editiable

Edit ACL tags is not editable

I see in code that edit acl tags has no action

<Menu.Item className='opacity-50 hover:bg-transparent'>
	Edit ACL tags
</Menu.Item>

I see that this project is great because looks like Real tailscale but there is some issue and features to deployment. Do you need a contributors?

Expiry information

Hey @tale,

thank you for your work on this nice looking admin ui for the latest alpha of headscale!

I am recreating my network using preauth keys with a 5 years expiration

docker compose exec headscale headscale preauthkey create --user <username> --expiration 5y --reusable

After registering the node I have a fully connected node with the given expiration of 0001-01-01 00:00:00 and Expired no.
2024-05-18_14-43-01

But the UI shows an expired tag.
2024-05-18_14-44-33

Maybe the API also sends the expired column?

Keep up your work its awesome!

[Suggestion] Routes & Tags Visible in Machine Info?

I think it might be useful to see the routes & tags assigned to a machine when viewing the detailed info like below
image

And also perhaps helpful to see routes in the overview screen

image

Currently routes are only available when explicitly choosing to edit route settings in the overview page, extrapolating that, exit node status may be worthy of consideration for some sort of indicator?

DNS page should have split DNS configuration.

Right now only the main DNS configuration is allowed to be configured, however headscale supports split DNS configuration.

dns_config:
  # Whether to prefer using Headscale provided DNS or use local.
  override_local_dns: true

  # List of DNS servers to expose to clients.
  nameservers:
    - 1.1.1.1

  restricted_nameservers:
    foo.bar.io:
      - 100.64.0.1

Contributing Error

[vite] Internal server error: Failed to load url ./magic (resolved id: ./magic) in /root/Headplane/app/routes/_data.dns._index/route.tsx. Does the file exist?
at loadAndTransform (file:///root/Headplane/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-BBHrJRja.js:53848:21)
at async instantiateModule (file:///root/Headplane/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-BBHrJRja.js:54902:10)

Handle orphaned machines on user deletion.

Currently, it's possible to delete a user and their machines go into a void (or something). A possible solution is to prevent user deletion if they own/inherit more than 1 machine. Additionally, creating a bank of unassigned/voided machines to assign to users could be a simpler idea.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.