# Configuration

Beacon is configured via environment variables. The complete template is `.env.example` in the Compose bundle and Composer project (download from your license portal or [apexcode.dev/beacon/env.example](https://apexcode.dev/beacon/env.example)). This page documents each variable, whether it is required, and what it does.

For Twilio credentials and OAuth-style per-team secrets see [Webhooks](./webhooks.md) and the first-run setup wizard — those are stored encrypted in the database, not in the environment.

## Required

| Variable               | Purpose                                                                                                                                                                                                                 |
|------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `APP_KEY`              | Laravel encryption key. Generate with `php artisan key:generate`, or leave empty in Docker and let first boot persist one. Compose interpolates this from host `.env` into the containers.                             |
| `APP_URL`              | Public URL Beacon is reachable at. Used to build webhook callback URLs and dashboard links.                                                                                                                             |
| `LICENSE_PUBLIC_KEY`   | The ECDSA P-256 public key used to verify your license file. Matches `config/licensing.php` and `.env.example`. Do not change it unless you are running a forked distribution.                                          |

## Application

| Variable                 | Default      | Notes                                                          |
|--------------------------|--------------|----------------------------------------------------------------|
| `APP_NAME`               | `beacon`     | Cosmetic.                                                      |
| `APP_ENV`                | `production` | Use `local` for development to enable nicer error pages.       |
| `APP_DEBUG`              | `false`      | **Never enable in production.** Leaks stack traces and config. |
| `APP_LOCALE`             | `en`         |                                                                |
| `APP_FALLBACK_LOCALE`    | `en`         |                                                                |
| `APP_MAINTENANCE_DRIVER` | `file`       | Switch to `database` for multi-server installs.                |
| `BCRYPT_ROUNDS`          | `12`         |                                                                |

## Logging

| Variable                   | Default  | Notes                                                                                        |
|----------------------------|----------|----------------------------------------------------------------------------------------------|
| `LOG_CHANNEL`              | `stack`  | In Docker the compose file overrides this to `stderr` so logs flow to `docker compose logs`. |
| `LOG_STACK`                | `single` |                                                                                              |
| `LOG_LEVEL`                | `info`   | Use `debug` while developing; `info` or `warning` in production.                             |
| `LOG_DEPRECATIONS_CHANNEL` | `null`   |                                                                                              |

## Database

| Variable        | Default                    | Notes                                                                    |
|-----------------|----------------------------|--------------------------------------------------------------------------|
| `DB_CONNECTION` | `sqlite`                   | `sqlite` or `mysql`.                                                     |
| `DB_DATABASE`   | `database/database.sqlite` | For MySQL, the database name.                                            |
| `DB_HOST`       | —                          | MySQL only.                                                              |
| `DB_PORT`       | `3306`                     | MySQL only.                                                              |
| `DB_USERNAME`   | —                          | MySQL only.                                                              |
| `DB_PASSWORD`   | —                          | MySQL only. **Override the `secret` default before exposing the stack.** |

The PHP container ships with both `pdo_sqlite` and `pdo_mysql`, so switching is just an env change.

## Optional MySQL profile

When you run `docker compose --profile mysql up`, the bundled MySQL container reads:

| Variable              | Default  | Notes         |
|-----------------------|----------|---------------|
| `MYSQL_DATABASE`      | `beacon` |               |
| `MYSQL_USER`          | `beacon` |               |
| `MYSQL_PASSWORD`      | `secret` | **Override.** |
| `MYSQL_ROOT_PASSWORD` | `root`   | **Override.** |

## Sessions

| Variable           | Default    | Notes                                        |
|--------------------|------------|----------------------------------------------|
| `SESSION_DRIVER`   | `database` |                                              |
| `SESSION_LIFETIME` | `120`      | Minutes.                                     |
| `SESSION_ENCRYPT`  | `false`    |                                              |
| `SESSION_PATH`     | `/`        |                                              |
| `SESSION_DOMAIN`   | `null`     | Set when sharing sessions across subdomains. |

## Cache and queue

| Variable               | Default    | Notes                                                                |
|------------------------|------------|----------------------------------------------------------------------|
| `CACHE_STORE`          | `database` |                                                                      |
| `QUEUE_CONNECTION`     | `redis`    | Beacon ships Horizon — keep `redis` unless you have a strong reason. |
| `BROADCAST_CONNECTION` | `log`      |                                                                      |
| `FILESYSTEM_DISK`      | `local`    |                                                                      |

## Redis

| Variable         | Default     | Notes                                    |
|------------------|-------------|------------------------------------------|
| `REDIS_CLIENT`   | `phpredis`  |                                          |
| `REDIS_HOST`     | `127.0.0.1` | In Docker this is overridden to `redis`. |
| `REDIS_PORT`     | `6379`      |                                          |
| `REDIS_PASSWORD` | `null`      |                                          |

## Mail

Used for license delivery confirmations and (eventually) operator notifications. Optional for the messaging product itself.

| Variable            | Default             | Notes                                                    |
|---------------------|---------------------|----------------------------------------------------------|
| `MAIL_MAILER`       | `log`               | Set to `smtp` (or `ses`, `mailgun`, etc.) in production. |
| `MAIL_HOST`         | `127.0.0.1`         |                                                          |
| `MAIL_PORT`         | `2525`              |                                                          |
| `MAIL_USERNAME`     | `null`              |                                                          |
| `MAIL_PASSWORD`     | `null`              |                                                          |
| `MAIL_FROM_ADDRESS` | `turbine@apexcode.dev` |                                                          |
| `MAIL_FROM_NAME`    | `${APP_NAME}`       |                                                          |

## AWS / S3 (optional)

Only needed if you point `FILESYSTEM_DISK` at S3.

| Variable                      |
|-------------------------------|
| `AWS_ACCESS_KEY_ID`           |
| `AWS_SECRET_ACCESS_KEY`       |
| `AWS_DEFAULT_REGION`          |
| `AWS_BUCKET`                  |
| `AWS_USE_PATH_STYLE_ENDPOINT` |

## Webhooks

| Variable                | Default | Notes                                                                                                                                                         |
|-------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `WEBHOOK_CLIENT_SECRET` | —       | Twilio Auth Token for the team that owns the receiving number. Beacon validates Twilio's `X-Twilio-Signature` against this. See [webhooks.md](./webhooks.md). |

## Licensing

| Variable                          | Default         | Notes                                                                                 |
|-----------------------------------|-----------------|---------------------------------------------------------------------------------------|
| `LICENSE_PUBLIC_KEY`              | (shipped value) | ECDSA P-256 key used to verify license files.                                         |
| `LICENSE_ENABLED`                 | `true`          | Set to `false` only in development.                                                   |
| `LICENSE_GRACE_PERIOD_DAYS`       | `14`            | How long Beacon keeps serving requests after a license expires.                       |
| `LICENSE_VALIDATION_FREQUENCY`    | `daily`         | `daily`, `hourly`, or `always`.                                                       |
| `LICENSE_HARDWARE_FINGERPRINTING` | `false`         | Bind the license to one machine. Off by default for self-hosted users.                |
| `LICENSE_AUDIT_LOGGING`           | `true`          |                                                                                       |
| `LICENSE_VERSION_CHECK`           | `false`         | When `true`, refuses to run a major version above what the license was purchased for. |
| `PRODUCT_VERSION`                 | —               | Override for the version-check comparison.                                            |

See [licensing.md](./licensing.md) for installation and test mode.

## Sanctum

| Variable                   | Default                | Notes                                                                        |
|----------------------------|------------------------|------------------------------------------------------------------------------|
| `SANCTUM_STATEFUL_DOMAINS` | derived from `APP_URL` | Only set this if you serve the dashboard from a different host than the API. |

## Tooling

| Variable            | Default  | Notes                                                                               |
|---------------------|----------|-------------------------------------------------------------------------------------|
| `TELESCOPE_ENABLED` | `false`  | Laravel Telescope is installed but disabled by default. Enable only in development. |
| `VITE_APP_NAME`     | `beacon` |                                                                                     |

## Docker-only knobs

Set in `docker-compose.yml` rather than Laravel config. `BEACON_IMAGE` and `BEACON_PORT` are Compose substitution variables in `.env`.

| Variable           | Default                                    | Notes                 |
|--------------------|--------------------------------------------|-----------------------|
| `BEACON_IMAGE`     | `ghcr.io/apxcde/beacon:0.3.3-beta`         | Published image.      |
| `BEACON_PORT`      | `8000`                                     | Host port mapped to Nginx `:80`. Set `APP_URL` to match. |
| `RUN_MIGRATIONS`   | `1` on the `app` container, `0` on workers | First-boot bootstrap. |
| `RUN_STORAGE_LINK` | `1` on `app`, `0` on workers               | First-boot bootstrap. |

---

## Twilio is not configured here

Beacon stores Twilio credentials **per team**, encrypted in the `team_credentials` table. They are entered through the first-run setup wizard, not via env vars. This keeps multi-team installs clean and lets each team rotate independently.

The one Twilio-adjacent env var is `WEBHOOK_CLIENT_SECRET`, which is used purely for inbound webhook signature verification.
