diff --git a/docs/Advanced-Integration.md b/docs/Advanced-Integration.md
index 09a110a..c25eb9b 100644
--- a/docs/Advanced-Integration.md
+++ b/docs/Advanced-Integration.md
@@ -1,5 +1,11 @@
# Advanced Integration
+The advanced integration methods unlock the full capabilities of Headplane.
+This is the closest you can get to the SaaS experience if you were paying for
+Tailscale.
+
+### Configuration Management
+
-With the advanced integration it's possible to control Access Control Lists (ACLs) and the Headscale configuration via the Headplane UI.
-Every single aspect of this integration is optional, meaning you can only use what you want.
-Additionally, with an integration provider, you can automatically reload the configuration or ACLs when they are changed.
+The advanced integration allows you to manage the Headscale configuration via
+the Headplane UI. When the configuration is available for editing, the `DNS`
+and `Settings` tabs will become available. When using the Docker or Kubernetes
+integration, changes to the configuration file will be automatically applied
+to Headscale.
-## Configuration Editing
+> By default, the configuration file is read from `/etc/headscale/config.yaml`.
+This can be overridden by setting the `CONFIG_FILE` environment variable. Any
+variables including `HEADSCALE_URL`, `OIDC_CLIENT_ID`, `OIDC_ISSUER`, and
+`OIDC_CLIENT_SECRET` will take priority over the configuration file.
-When the configuration file is available to Headplane, the `DNS` and `Settings` tabs will become functional.
-Similar to the Tailscale UI, you'll be able to edit the configuration without needing to manually edit the file.
-Headscale will read the file from the path given in the `CONFIG_FILE` environment variable.
-By default this is set to `/etc/headscale/config.yaml`.
-
-> One important think to note is that environment variables always take priority over the configuration file.
-> The `HEADSCALE_URL`, `OIDC_CLIENT_ID`, `OIDFC_ISSUER`, and `OIDC_CLIENT_SECRET` will be preferred over the configuration file if available.
-
-## Access Control Lists (ACLs)
+### Access Control Lists (ACLs)
-Headplane will enable the `Access Controls` tab if it is able to read an ACL file from Headscale.
-The ACL file path is read from the following sources in order of priority:
+The advanced integration allows you to manage the ACLs via the Headplane UI.
+When the ACL file is available for editing, the `Access Controls` tab will
+become available. All of the integrations support automatic reloading of the
+ACLs when the file is changed.
-- **Environment Variable**: If you set the `ACL_FILE` environment variable, Headplane will read the file from that path.
-- **Configuration Integration**: If you've set this up, then Headplane will read the `acl_policy_path` key from the configuration file.
+> By default, the ACL file is read from `/etc/headscale/acl_policy.json`. This
+can be overridden by setting the `ACL_FILE` environment variable and is also
+overriden by the `acl_policy_path` key in the configuration file if set.
-## Automatic Configuration Reload
-
-When the configuration file is changed, Headscale will need to be restarted to apply the changes.
-Similarly, when the ACL file is changed, Headscale will need to be sent a `SIGHUP` signal to reload the ACLs.
-Currently there are 2 integration providers that can do this for you:
-
-### Docker Integration
-
-To enable the Docker integration, set `HEADSCALE_INTEGRATION=docker` in the environment variables.
-Additionally, you'll need to pass in the `HEADSCALE_CONTAINER` environment variable.
-This should be either the name or ID of the Headscale container (you can retrieve this using `docker ps`).
-If the other integrations aren't setup, then Headplane will automatically disable the Docker integration.
-
-By default the integration will check for `/var/run/docker.sock`, however you can override this by
-setting the `DOCKER_SOCK` environment variable if you use a different configuration than the default.
-When setting `DOCKER_SOCK`, you'll need to include the protocol (e.g., `unix://` or `tcp://`).
-Headplane currently does not support the HTTPS protocol for the Docker socket.
-
-#### Example Docker Deployment
+## Deployment
Requirements:
- Headscale 0.23 alpha or later
- Headscale and Headplane need a Reverse Proxy (NGINX, Traefik, Caddy, etc)
-- Headscale needs to be running in a docker container
-Here's a good Docker Compose example:
-```yaml
-version: '3.8'
-services:
- headscale:
- image: 'headscale/headscale:0.23.0-alpha5'
- container_name: 'headscale'
- restart: 'unless-stopped'
- command: 'serve'
- volumes:
- - './data:/var/lib/headscale'
- - './configs:/etc/headscale'
- ports:
- - '8080:8080'
- environment:
- TZ: 'America/New_York'
- headplane:
- container_name: headplane
- image: ghcr.io/tale/headplane:latest
- restart: unless-stopped
- volumes:
- - './data:/var/lib/headscale'
- - './configs:/etc/headscale'
- - '/var/run/docker.sock:/var/run/docker.sock:ro'
- ports:
- - '3000:3000'
- environment:
- # This is always required for Headplane to work
- COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'
+Currently there are 3 integration providers that can do this for you:
+- [Docker Integration](/docs/integration/Docker.md)
+- [Kubernetes Integration](/docs/integration/Kubernetes.md)
+- [Native Linux Integration](/docs/integration/Native.md)
- HEADSCALE_INTEGRATION: 'docker'
- HEADSCALE_CONTAINER: 'headscale'
- DISABLE_API_KEY_LOGIN: 'true'
- HOST: '0.0.0.0'
- PORT: '3000'
-
- # Overrides the configuration file values if they are set in config.yaml
- # If you want to share the same OIDC configuration you do not need this
- OIDC_CLIENT_ID: 'headscale'
- OIDC_ISSUER: 'https://sso.example.com'
- OIDC_CLIENT_SECRET: 'super_secret_client_secret'
-
- # This NEEDS to be set with OIDC, regardless of what's in the config
- # This needs to be a very long-lived (999 day) API key used to create
- # shorter ones for OIDC and allow the OIDC functionality to work
- ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz'
-```
-
-> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide.
-> It explains what each variable does, how to configure them, and what the default values are.
-
-You may also choose to run it natively with the distributed binaries on the releases page.
-You'll need to manage running this yourself, and I would recommend making a `systemd` unit.
-
-### Native Linux Integration (Beta)
-
-The native integration for Linux relies on the `/proc` directory to locate the Headscale process.
-To enable it, set the `HEADSCALE_INTEGRATION=proc` value in the environment variables.
-Because of the way this integration works, it only supports automatically reloading ACLs.
-It's still very experimental and may not work in all environments.
-
-## Configuration Scenarios
-
-Since the configuration is fairly modular you can have a variety of different setups.
-This mostly applies to the Docker integration since the native integration isn't fully featured yet.
-Here are a few examples to inspire you and show you what can work and what can't:
-
-#### Full Integration
-Headscale runs in a container, Headplane can run in either a container or natively.
-Headplane is able to manage the configuration file and ACLs that Headscale uses.
-When changes happen, the Docker integration will automatically reload the configuration and ACLs.
-
-> Note that the full integration currently isn't possible if Headscale isn't running in a container.
-
-#### Configuration Only
-Headscale and Headplane can either run in containers or natively.
-Headplane is able to manage the configuration file and ACLs that Headscale uses.
-When changes are made, Headscale will need to be manually restarted to apply the changes.
-
-#### ACL Only
-Headscale and Headplane can either run in containers or natively.
-Headplane is able to manage the ACLs that Headscale uses.
-When changes are made, Headscale will need to be sent a `SIGHUP` to reload the ACLs.
-In this scenario, Headplane does not have access to the configuration file.
-
-#### Read-Only Configuration or ACLs
-If the configuration or ACLs are read-only, Headplane will not be able to manage them.
-Instead you'll only be able to view the configurations on the UI and need to edit them manually.
-
-#### No Integration
-If no integration is setup, Headplane will not be able to manage the configuration or ACLs.
-This is the simplest setup by far, however it also heavily reduces the capabilities of Headplane.
diff --git a/docs/Basic-Integration.md b/docs/Basic-Integration.md
index 51858eb..c07cbf0 100644
--- a/docs/Basic-Integration.md
+++ b/docs/Basic-Integration.md
@@ -1,12 +1,17 @@
# Basic Integration
-The basic integration is not able to offer advanced features such as:
-- Automatic management of Access Control Lists (ACLs)
-- Management of DNS settings for your tailnet
-- Management of the Headscale configuration
+The basic integration is the simplest way to get started with Headplane.
+It's more of a preview and is heavily limited in the features it can offer
+when compared to the [Advanced Integration](/docs/Advanced-Integration.md).
-In order to support these features please refer to the [Advanced Integration](./docs/Advanced-Integration.md) guide.
-Note that in order to use this deployment strategy you need to run Headscale in a Docker container.
+> Note that the Advanced integration is the recommend way to run
+Headplane in a production environment.
+
+## Limitations
+- No automatic management of Access Control Lists (ACLs)
+- No management of DNS settings for your tailnet
+- No capability to edit the configuration
+- Limited support for OIDC authentication
## Deployment
@@ -14,11 +19,13 @@ Requirements:
- Headscale 0.23 alpha or later
- Headscale and Headplane need a Reverse Proxy (NGINX, Traefik, Caddy, etc)
-Headplane is currently best run in a Docker container due to the easy configuration.
-Here's a very basic `docker-compose.yaml` file that utilizes each configuration variable.
+Docker heavily simplifies the deployment process, but this process can be
+adopted to run natively. Follow the first section of the deployment guide
+in the [Native Integration](/docs/integration/Native.md#deployment) for a
+bare-metal or virtual machine deployment.
+Here is a simple Docker Compose deployment:
```yaml
-version: '3.8'
services:
headplane:
container_name: headplane
@@ -42,12 +49,7 @@ services:
PORT: '3000'
```
-> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide.
-> It explains what each variable does, how to configure them, and what the default values are.
-
-You may also choose to run it natively with the distributed binaries on the releases page.
-You'll need to manage running this yourself, and I would recommend making a `systemd` unit.
-
-## ACL Configuration
-If you would like to get the web ACL configuration working, you'll need to pass the `ACL_FILE` environment variable.
-This should point to the path of the ACL file on the Headscale server (ie. `ACL_FILE=/etc/headscale/acl_policy.json`).
+> For a breakdown of each configuration variable, please refer to the
+[Configuration](/docs/Configuration.md) guide.
+> It explains what each variable does, how to configure them, and what the
+default values are.
diff --git a/docs/integration/Docker.md b/docs/integration/Docker.md
new file mode 100644
index 0000000..d7ceaa1
--- /dev/null
+++ b/docs/integration/Docker.md
@@ -0,0 +1,86 @@
+## Docker Integration
+
+The Docker integration allows you to run Headplane and Headscale separately
+in a dockerized environment. It allows you to unlock full functionality such as
+automatic reloading of ACLs, DNS management, and Headscale configuration
+management.
+
+### Deployment
+
+> When running with the Docker integration, it's assumed that both Headscale and
+Headplane will run as containers. If you are running Headscale natively, then
+refer to the [Native Integration](/docs/integration/Native.md) guide.
+
+To enable the Docker integration, set the `HEADSCALE_INTEGRATION` environment
+variable to `docker`. You'll also need to supply `HEADSCALE_CONTAINER` with the
+name or ID of the Headscale container.
+
+By default Headplane uses `unix:///var/run/docker.sock` to connect to Docker.
+This can be overridden by setting the `DOCKER_SOCK` environment variable. For
+example, a remote socket would be `tcp://:2375`. When setting
+the variable, you'll need to specify the protocol (`unix://` or `tcp://`).
+
+> The `DOCKER_SOCK` variable does not support the HTTPS protocol.
+
+To enable the Docker integration, set `HEADSCALE_INTEGRATION=docker` in the environment variables.
+Additionally, you'll need to pass in the `HEADSCALE_CONTAINER` environment variable.
+This should be either the name or ID of the Headscale container (you can retrieve this using `docker ps`).
+If the other integrations aren't setup, then Headplane will automatically disable the Docker integration.
+
+By default the integration will check for `/var/run/docker.sock`, however you can override this by
+setting the `DOCKER_SOCK` environment variable if you use a different configuration than the default.
+When setting `DOCKER_SOCK`, you'll need to include the protocol (e.g., `unix://` or `tcp://`).
+Headplane currently does not support the HTTPS protocol for the Docker socket.
+
+Here's an example deployment using Docker Compose (recommended). Keep in mind
+that you'll NEED to setup a reverse proxy and this is incomplete:
+```yaml
+services:
+ headscale:
+ image: 'headscale/headscale:0.23.0-alpha12'
+ container_name: 'headscale'
+ restart: 'unless-stopped'
+ command: 'serve'
+ volumes:
+ - './data:/var/lib/headscale'
+ - './configs:/etc/headscale'
+ ports:
+ - '8080:8080'
+ environment:
+ TZ: 'America/New_York'
+ headplane:
+ container_name: headplane
+ image: ghcr.io/tale/headplane:latest
+ restart: unless-stopped
+ volumes:
+ - './data:/var/lib/headscale'
+ - './configs:/etc/headscale'
+ - '/var/run/docker.sock:/var/run/docker.sock:ro'
+ ports:
+ - '3000:3000'
+ environment:
+ # This is always required for Headplane to work
+ COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'
+
+ HEADSCALE_INTEGRATION: 'docker'
+ HEADSCALE_CONTAINER: 'headscale'
+ DISABLE_API_KEY_LOGIN: 'true'
+ HOST: '0.0.0.0'
+ PORT: '3000'
+
+ # Overrides the configuration file values if they are set in config.yaml
+ # If you want to share the same OIDC configuration you do not need this
+ OIDC_CLIENT_ID: 'headscale'
+ OIDC_ISSUER: 'https://sso.example.com'
+ OIDC_CLIENT_SECRET: 'super_secret_client_secret'
+
+ # This NEEDS to be set with OIDC, regardless of what's in the config
+ # This needs to be a very long-lived (999 day) API key used to create
+ # shorter ones for OIDC and allow the OIDC functionality to work
+ ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz'
+```
+
+> For a breakdown of each configuration variable, please refer to the
+[Configuration](/docs/Configuration.md) guide.
+> It explains what each variable does, how to configure them, and what the
+default values are.
diff --git a/docs/integration/Kubernetes.md b/docs/integration/Kubernetes.md
new file mode 100644
index 0000000..1eec3c1
--- /dev/null
+++ b/docs/integration/Kubernetes.md
@@ -0,0 +1,123 @@
+## Kubernetes Integration
+
+The Kubernetes integration allows you to run Headplane and Headscale together
+in a cluster. It allows you to unlock full functionality such as automatic
+reloading of ACLs, DNS management, and Headscale configuration management.
+
+Currently there are a few limitations to the Kubernetes integration:
+- Headplane and Headscale need to run in the same Pod and share the same
+ process space for the integration to work correctly due to a limitation in
+ the Kubernetes API.
+
+- The only supported methods of deploying the integration are through a
+ `Deployment` or `Pod` (more coming soon). You can still get around this with
+ the `HEADSCALE_INTEGRATION_UNSTRICT` variable, but it's not recommended.
+
+- The integration will assume that the Headscale container will always restart
+ because the integration relies on a system call that will exit the container.
+
+### Deployment
+
+In order to ensure Headplane can read Kubernetes resources, you'll need to
+grant additional RBAC permissions to the default `ServiceAccount` in the
+namespace. This can be done with the following:
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: headplane-agent
+ namespace: default # Adjust namespace as needed
+rules:
+- apiGroups: ['']
+ resources: ['pods']
+ verbs: ['get', 'list']
+- apiGroups: ['apps']
+ resources: ['deployments']
+ verbs: ['get', 'list']
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: headplane-agent
+ namespace: default # Adjust namespace as needed
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: headplane-agent
+subjects:
+- kind: ServiceAccount
+ name: default # If you use a different service account, change this
+ namespace: default # Adjust namespace as needed
+```
+
+Keep in mind you'll need to make `PersistentVolumeClaim`s for the data and that
+they need to be either `ReadWriteOnce` or `ReadWriteMany` depending on your
+topology. Additionally, you can abstract environment variables and configuration
+away into a `ConfigMap` or `Secret` for easier management.
+
+The important parts of this deployment are the `HEADSCALE_INTEGRATION` and
+`DEPLOYMENT_NAME` environment variables. The `HEADSCALE_INTEGRATION` variable
+should be set to `kubernetes` and the `DEPLOYMENT_NAME` variable should be set
+to the name of the deployment (done using the Downward API below).
+
+A basic deployment of the integration would look like this. Keep in mind that
+you are responsible for setting up a reverse-proxy via an `Ingress` or `Service`
+otherwise Headplane will not work:
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: headplane
+ namespace: default # Adjust namespace as needed
+ labels:
+ app: headplane
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: headplane
+ template:
+ metadata:
+ labels:
+ app: headplane
+ spec:
+ serviceAccountName: default
+ containers:
+ - name: headplane
+ image: ghcr.io/tale/headplane:latest
+ env:
+ - name: COOKIE_SECRET
+ value: 'abcdefghijklmnopqrstuvwxyz'
+ - name: HEADSCALE_INTEGRATION
+ value: 'kubernetes'
+ - name: DEPLOYMENT_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ volumeMounts:
+ - name: headscale-config
+ mountPath: /etc/headscale
+
+ - name: headscale
+ image: headscale/headscale:0.23.0-alpha12
+ command: ['serve']
+ env:
+ - name: TZ
+ value: 'America/New_York'
+ volumeMounts:
+ - name: headscale-data
+ mountPath: /var/lib/headscale
+ - name: headscale-config
+ mountPath: /etc/headscale
+
+ volumes:
+ - name: headscale-data
+ persistentVolumeClaim:
+ claimName: headscale-data
+ - name: headscale-config
+ persistentVolumeClaim:
+ claimName: headscale-config
+```
+
+> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide.
+> It explains what each variable does, how to configure them, and what the default values are.
diff --git a/docs/integration/Native.md b/docs/integration/Native.md
new file mode 100644
index 0000000..06ef23b
--- /dev/null
+++ b/docs/integration/Native.md
@@ -0,0 +1,28 @@
+## Native Integration
+
+The Native integration allows you to run both Headplane and Headscale on
+bare-metal servers or virtual machines. This integration is best suited for
+environments where Docker or Kubernetes are not available or not desired.
+
+Currently the Native integration only supports automatic reloading of ACLs. It
+cannot handle configuration changes as killing the `headscale` process can lead
+to undefined behavior or the service not restarting.
+
+### Deployment
+
+Follow the instructions to install Headscale from the
+[Linux Installation Guide](https://headscale.net/running-headscale-linux/). As
+of now, Headplane requires Node.js 20 to be installed on the system. Once you
+are ready, clone the repository (`git clone https://github.com/tale/headplane`),
+install dependencies (`npm install`), build the project (`npm run build`), and
+start the server (`npm start`).
+
+> If you'd like, you can turn this into a `systemd` unit to manage the service.
+> I plan to provide packages and unit files to make this easier in the future.
+
+When running Headplane, you'll need to set environment variables to configure
+the application. The `HEADSCALE_INTEGRATION` variable should be set to `proc`.
+
+> For a breakdown of each configuration variable, please refer to the
+[Configuration](/docs/Configuration.md) guide.
+> It explains what each variable does, how to configure them, and what the default values are.