> ## Documentation Index
> Fetch the complete documentation index at: https://docs.masker.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Customer environment variables for self-hosted Masker

> The customer-facing environment variables you configure when running Masker in your own VPC — covering encryption keys, key rotation, and CLI auth.

If you are running Masker in your own VPC or on-premises, a small set of environment variables controls how Masker handles encryption keys and authenticates CLI commands against your server. Hosted SaaS customers on `masker-voice.fly.dev` do not configure these directly — they are managed by Masker's infrastructure. This page covers only the variables that you, as a self-hosted operator, are responsible for setting.

<Note>
  For deployment configuration (server address, database URL, upstream LLM endpoint, and so on), see the [deployment guide](/configuration/deployment), which includes annotated Docker and Kubernetes examples.
</Note>

## Encryption keys

Masker uses symmetric 256-bit keys for tokenization and AEAD operations. Each key is identified by a **key ID** (`kid`) that matches a corresponding entry in your mask policy. The environment variable name is always `MASKER_KEY_<KID>`, where `<KID>` is the key ID in uppercase.

| Variable                      | Example value      | Description                                                                                         |
| ----------------------------- | ------------------ | --------------------------------------------------------------------------------------------------- |
| `MASKER_KEY_K_HEALTHCARE`     | `base64(32 bytes)` | Active encryption key for the `K_HEALTHCARE` kid. Required if your policy uses `kid: K_HEALTHCARE`. |
| `MASKER_KEY_K_HEALTHCARE_OLD` | `base64(32 bytes)` | Previous key, kept during rotation so that tokens minted under the old key can still be rehydrated. |

Generate a key with:

```bash theme={null}
openssl rand -base64 32
```

The value must be a base64-encoded 32-byte (256-bit) secret. Masker will refuse to start if a `kid` referenced in the policy has no matching key variable.

<Warning>
  Never put raw key values in source control, Dockerfiles, or unencrypted config files. Inject them from your secret store (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Kubernetes `Secret`, or `flyctl secrets set`).
</Warning>

## Key rotation

Masker supports zero-downtime key rotation. The process is:

<Steps>
  <Step title="Generate a new key">
    ```bash theme={null}
    NEW_KEY=$(openssl rand -base64 32)
    ```
  </Step>

  <Step title="Set both the new and old keys">
    Add the new key as `MASKER_KEY_K_HEALTHCARE` and move the current key to `MASKER_KEY_K_HEALTHCARE_OLD`. Both variables must be present during the grace period.

    ```bash theme={null}
    # Example using flyctl secrets
    flyctl secrets set \
      MASKER_KEY_K_HEALTHCARE="$NEW_KEY" \
      MASKER_KEY_K_HEALTHCARE_OLD="$CURRENT_KEY"
    ```
  </Step>

  <Step title="Restart Masker">
    Masker picks up the new key at boot. New tokens are minted under the new key. Rehydration of existing tokens falls back to `_OLD` automatically.
  </Step>

  <Step title="Re-encrypt the vault (optional)">
    If you are using `vault-deterministic` tokenization, you can re-encrypt all stored tokens under the new key:

    ```bash theme={null}
    masker vault rotate-key --new-kid K_HEALTHCARE
    ```

    This is optional — the `_OLD` key handles rehydration of legacy tokens for as long as you keep it set.
  </Step>

  <Step title="Remove the old key after the grace period">
    Once you are confident no sessions are holding unrehydrated tokens from the old key, remove `MASKER_KEY_K_HEALTHCARE_OLD`. After this point, tokens minted under the old key can no longer be rehydrated.
  </Step>
</Steps>

<Tip>
  The default grace period Masker tracks internally is 30 days. Any token older than that is unlikely to be waiting for rehydration in an active session.
</Tip>

## CLI authentication

The `masker` CLI can talk to a remote Masker server for commands like `masker sessions list`, `masker report`, and `masker policy reload`. These commands require a session credential.

| Variable         | Description                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| `MASKER_SESSION` | Session cookie for authenticating CLI commands against a remote server. |

To obtain the value, sign in to your Masker portal, open your browser's developer tools, and copy the value of the `masker_session` cookie.

```bash theme={null}
export MASKER_SESSION=ey...

# Then use any remote command:
masker sessions list --server https://masker.your-vpc.example
masker report --server https://masker.your-vpc.example --since 7d --output weekly.pdf
```

<Note>
  A scoped, long-lived CLI token that does not require copying a browser cookie is on the May 30 roadmap. Until then, `MASKER_SESSION` is the supported authentication mechanism for remote CLI commands.
</Note>

## Config file path

| Variable        | Default         | Description                                                                          |
| --------------- | --------------- | ------------------------------------------------------------------------------------ |
| `MASKER_CONFIG` | `./masker.toml` | Path to the `masker.toml` CLI configuration file. Overrides the default search path. |

The CLI resolves its config file in this order:

1. `--config <path>` flag
2. `MASKER_CONFIG` environment variable
3. `./masker.toml` in the current directory
4. `~/.config/masker/config.toml`

See the [CLI reference](/configuration/cli) for the full `masker.toml` format.

## Setting variables in common environments

<Tabs>
  <Tab title="Docker">
    Pass secrets via an env file rather than inline flags to avoid values appearing in `ps` output or shell history:

    ```bash theme={null}
    # masker.secrets.env (never commit this file)
    MASKER_KEY_K_HEALTHCARE=<base64 key>
    MASKER_KEY_K_HEALTHCARE_OLD=<base64 previous key>
    MASKER_SESSION=<portal cookie>
    ```

    ```bash theme={null}
    docker run -d \
      --env-file ./masker.secrets.env \
      ghcr.io/masker-dev/masker:latest
    ```
  </Tab>

  <Tab title="Kubernetes">
    Store keys in a Kubernetes `Secret` and mount them as environment variables:

    ```yaml theme={null}
    apiVersion: v1
    kind: Secret
    metadata:
      name: masker-keys
    stringData:
      MASKER_KEY_K_HEALTHCARE: "<base64 key>"
      MASKER_KEY_K_HEALTHCARE_OLD: "<base64 previous key>"
    ```

    ```yaml theme={null}
    # In your Deployment spec
    envFrom:
      - secretRef:
          name: masker-keys
    ```
  </Tab>

  <Tab title="Fly.io">
    Use `flyctl secrets set` — values are encrypted at rest and injected at runtime:

    ```bash theme={null}
    flyctl secrets set \
      MASKER_KEY_K_HEALTHCARE=$(openssl rand -base64 32) \
      MASKER_SESSION=ey...
    ```
  </Tab>
</Tabs>
