# Access control

###### Protect a Public URL on LocalCan's servers with the `policy` endpoint key.

Access control enforces a password page, a secret link, or IP and user-agent rules for a Public URL, and it keeps working while your machine is asleep. This page documents the YAML. For what it does and when to use it, see [Public URLs → Access control](/docs/public-urls/access-control).

The `policy` key belongs on Public URL endpoints (`provider: localcan`) and requires an active subscription plan. It takes two forms.

#### Named policy

A string attaches a team policy by name. Team policies are created in the desktop app and shared across the team:

```yaml title="~/.localcan/projects/my-app.yml"
services:
  web:
    target: http://localhost:3000
    endpoints:
      - provider: localcan
        url: my-app-12.localcan.dev
        policy: client-review
```

> [!NOTE]
> Named team policies require the Teams plan. An inline policy works on any subscription plan.

#### Inline policy

A map defines a one-off policy for that URL alone. This is also how you use Access from the CLI on Linux:

```yaml
endpoints:
  - provider: localcan
    url: my-app-12.localcan.dev
    policy:
      access:
        who: password              # anyone | link | password
        password: "hunter2"
        ip:
          allow: ["203.0.113.0/24"]
          deny: ["198.51.100.7"]
        user_agent:
          deny: ["*GPTBot*"]
```

| Key | Type | Notes |
| --- | --- | --- |
| `access.who` | string | `anyone` (default), `link`, or `password`. |
| `access.password` | string | Required with `who: password`. 1 to 128 characters. |
| `access.ip.allow` / `access.ip.deny` | list | IPs or CIDR ranges, up to 128 entries per list. A non-empty allow list blocks everyone not on it. |
| `access.user_agent.allow` / `access.user_agent.deny` | list | `*`-wildcard patterns, up to 64 per list. |

Deny rules always win, even over a correct password.

After editing, run `localcan reload` and the policy is pushed to LocalCan's servers. With `who: link`, the secret link is generated by LocalCan and never stored in the file: copy it from the **Access Control** screen in the desktop app.

> [!TIP]
> Access is independent from [`basic_auth`](/docs/configuration/basic-auth) and [`headers`](/docs/configuration/headers), which are applied by LocalCan on your machine and work on every plan.

