# Enrolling hosts with join keys

An [enrollment code](/docs/guides/managing-hosts/#how-enrollment-codes-work) enrolls one host, which you create ahead of time. A **join key** is a reusable enrollment code: any number of machines can enroll with it, and each one joins as a new [host](/docs/glossary/host/) with the key's network, [role](/docs/glossary/role/), and [tags](/docs/guides/configuring-hosts-with-tags/). Join keys suit machines that come and go without anyone creating a host for them first, like CI runners, autoscaling groups, and devices rolled out through mobile device management (MDM).

## Creating a join key

Go to [Settings > Host join keys](https://admin.defined.net/settings/join-keys) in the admin panel and add a key. Fill in:

- **Name**: identifies the key, and names hosts that don't report a hostname (see [How enrolled hosts are named](#how-enrolled-hosts-are-named)). It may contain only lowercase letters, digits, and hyphens, and can't start or end with a hyphen.
- **Network**: the network every enrolled host joins.
- **Role** (optional): the role every enrolled host gets.
- **Tags** (optional): the tags every enrolled host gets.
- **Also assign an IPv4 address to enrolled hosts**: shown for dual-stack networks. Check it to give each host an IPv4 address as well as an IPv6 one.
- **Expiration**: when the key stops enrolling hosts. Hosts it already enrolled stay enrolled.

After you save, the admin panel shows the key's token, which starts with `dnjoin-`. **The token is shown only once**, so copy it somewhere safe before leaving the page.

The network, role, tags, and IPv4 setting can't be changed after the key is created. Only the name and expiration can be edited. To enroll hosts with a different configuration, create a new key.

## Enrolling a machine

[Install DNClient](/docs/get-started/dnclient-server/install/) on the machine, then enroll it with the join key's token the same way you would with a single-use enrollment code:

```bash
sudo dnclient enroll -code dnjoin-XXXX
```

With the DNClient Docker image, pass the token in the `DN_ENROLLMENT_CODE` environment variable:

```bash
docker run \
    --name dnclient \
    --network host \
    --cap-add NET_ADMIN \
    --volume defined:/etc/defined \
    --env DN_ENROLLMENT_CODE="dnjoin-XXXX" \
    --rm \
    definednet/dnclient
```

The token is only needed on the first run, since the volume keeps the host's configuration across restarts. Without the volume, every run enrolls as a new host. Nothing removes the earlier hosts, so they keep their IP addresses and count against your host limit.

## How enrolled hosts are named

A host enrolled with a join key is named after the machine's hostname, converted to lowercase letters, digits, hyphens, and dots. If another host on the network already has that name, a random suffix is added, like `runner-a1b2c3`.

If the machine doesn't report a usable hostname, the host is named after the key instead, with a random suffix: a key named `ci-runner` enrolls hosts like `ci-runner-k3x9q2ab`.

## Revoking and expiring join keys

To stop a key from enrolling more machines, open it from the [Host join keys](https://admin.defined.net/settings/join-keys) page and revoke it. A key also stops working once it passes its expiration date.

Either way, hosts the key already enrolled stay enrolled. To remove them from your network, [delete](/docs/guides/managing-hosts/#delete-a-host) or [block](/docs/guides/blocking-and-unblocking-hosts/) them like any other host.

A network or role can't be deleted while a join key still references it. Revoke the key first.

## Keeping tokens safe

Treat a join key token like a password: anyone who has it can add machines to your network. Store it where your tooling keeps other secrets, such as your CI provider's secret store or your MDM's configuration payload, and avoid committing it to source control or baking it into images that are shared outside your organization. Setting an expiration limits how long a leaked token is useful.

To rotate a join key:

1. Create a new join key with the same network, role, and tags.
1. Update your CI secrets, MDM payloads, or launch templates with the new token.
1. Revoke the old key.

## Join keys in the audit log

When a machine enrolls with a join key, the [audit log](/docs/guides/using-audit-logs/) records the new host with the join key as the actor, so you can trace each host back to the key that enrolled it. Creating, editing, and revoking join keys are recorded too.

## Managing join keys with the API

Join keys can also be managed with an API key. Grant it the [`join-keys` scopes](/docs/api-key-scopes/#join-keys) it needs, for example `join-keys:create` for a script that creates keys. See [Create join key](/docs/api/operations/joinkeycreate/) and the other join key operations in the API reference.
