| read_when |
|
|---|
clickclack serve resolves config in this order. Later sources override
earlier ones for any given key:
- Hard-coded defaults (
Addr=":8080",Data="./data"). - JSON config file passed via
--config. - Environment variables.
- CLI flags that were explicitly set.
An explicitly present dev_bootstrap value in the config file is the one
exception: it is not replaced by CLICKCLACK_DEV_BOOTSTRAP. This prevents a
stale process environment from silently enabling development authentication
against a deployment file that explicitly disables it.
Source: apps/api/internal/config/config.go and the applyFlagOverrides
hook in cmd/clickclack/main.go.
| Flag | Env | Default | Notes |
|---|---|---|---|
--addr |
CLICKCLACK_ADDR |
:8080 |
HTTP listen address. |
--data |
CLICKCLACK_DATA |
./data |
Data root for DB, uploads, logs. |
--db |
CLICKCLACK_DB |
derived | DB URL. Defaults to sqlite://<data>/clickclack.db. |
--uploads |
CLICKCLACK_UPLOADS |
derived | Upload storage URL. Defaults to file://<data>/uploads; use r2://bucket/prefix for Cloudflare R2. |
--environment |
CLICKCLACK_ENVIRONMENT |
unset | Low-cardinality deployment label used only by opt-in metrics. |
--metrics-enabled |
CLICKCLACK_METRICS_ENABLED |
false |
Expose metadata-only Prometheus metrics at /metrics; keep private. |
--config |
— | unset | JSON config file. |
--dev-bootstrap |
CLICKCLACK_DEV_BOOTSTRAP |
false |
serve only. Creates a default user/workspace/channel and enables local dev auth fallbacks when explicitly set to true. |
| — | CLICKCLACK_PUBLIC_URL |
unset | Canonical external origin. Required for GitHub OAuth and namespaced cookies. |
| — | CLICKCLACK_PUBLIC_API_URL |
public URL | Canonical external API base. May use a different origin and a normalized base path. |
--embed-frame-ancestors |
CLICKCLACK_EMBED_FRAME_ANCESTORS |
unset | Comma- or whitespace-separated exact origins allowed to frame /embed/*; see Embedded threads. |
--access-team-domain |
CLICKCLACK_ACCESS_TEAM_DOMAIN |
unset | Cloudflare Access team HTTPS origin. Must be configured together with the Access audience. |
--access-aud |
CLICKCLACK_ACCESS_AUD |
unset | Expected Cloudflare Access application audience tag. Must be non-empty when the team domain is set. |
| — | CLICKCLACK_COOKIE_NAMESPACE |
unset | Stable lowercase cookie namespace for multiple trusted ClickClack instances on one hostname. |
| — | CLICKCLACK_GITHUB_CLIENT_ID |
unset | GitHub OAuth app client ID. |
| — | CLICKCLACK_GITHUB_CLIENT_SECRET |
unset | GitHub OAuth app client secret. |
| — | CLICKCLACK_GITHUB_ALLOWED_ORG |
unset | Optional GitHub org login gate. Requires read:org scope. |
| — | CLICKCLACK_GITHUB_MODERATOR_ORG |
unset | Optional GitHub org whose members become guest-workspace moderators. Requires read:org scope. |
| — | CLICKCLACK_PUSHOVER_API_TOKEN |
unset | Pushover application API token. Users still opt in with their own Pushover user key in account settings. |
| — | CLICKCLACK_R2_ACCOUNT_ID |
unset | Cloudflare account ID for r2:// uploads. |
| — | CLICKCLACK_R2_ACCESS_KEY_ID |
unset | R2 API token access key ID. |
| — | CLICKCLACK_R2_SECRET_ACCESS_KEY |
unset | R2 API token secret access key. |
| — | CLICKCLACK_R2_ENDPOINT |
derived | Optional S3-compatible endpoint override for tests or non-standard R2 endpoints. |
Pass with --config /etc/clickclack/config.json. Values from the file
are overridden by environment variables; CLI flags override both when
explicitly set. The dev_bootstrap exception is described above.
The Access team domain is an HTTPS origin without credentials, a path, query,
or fragment. access_team_domain and access_aud are an all-or-nothing pair;
when both are absent, trusted-proxy authentication is disabled. See
Trusted proxy (Cloudflare Access)
for verification, provisioning, and session behavior.
CLICKCLACK_PUBLIC_URL is an origin, not an application base path. It must:
- use HTTPS for every non-loopback host
- contain a host and optional non-default port
- contain no credentials, path, query, fragment, or trailing-dot hostname
For example, https://chat.example.com and http://127.0.0.1:8080 are valid.
http://chat.example.com, https://chat.example.com/clickclack, and
https://user@chat.example.com fail startup validation. GitHub OAuth
credentials also fail startup validation unless the public URL is set.
CLICKCLACK_PUBLIC_API_URL is the canonical address browsers and installers
use for API calls. It defaults to CLICKCLACK_PUBLIC_URL, so existing
same-origin deployments require no change. Set it only when the API has a
different public origin or a public base path:
CLICKCLACK_PUBLIC_URL=https://chat.example.com
CLICKCLACK_PUBLIC_API_URL=https://api.example.com/services/clickclackThe API URL follows the same scheme, host, credential, query, and fragment
rules. It may additionally contain a normalized base path made from ordinary
URL path segments; trailing slashes are removed. Dot segments, doubled
slashes, encoded separators, whitespace, and backslashes fail startup
validation. A path-mounted ingress must route
/services/clickclack/api/* to the Go server's /api/* routes by stripping
the configured prefix.
Loopback split origins must both use HTTP and exactly the same hostname; only their ports may differ. This keeps local session cookies same-site. Remote origins must use HTTPS.
When both URLs are configured, ClickClack injects the canonical API base into the SPA HTML it serves. A separate frontend ingress should proxy the SPA and asset routes to the ClickClack server while browsers call the configured API origin directly. A separately hosted static build must inject the equivalent value before the app modules run:
<script>window.__CLICKCLACK_CONFIG__ = { apiBaseUrl: "https://api.example.com/services/clickclack" };</script>That value is browser routing only. The server remains authoritative for setup claim URLs and returns only URLs derived from validated administrator configuration.
The default cookie names remain cc_session and cc_oauth_binding. Set
CLICKCLACK_COOKIE_NAMESPACE only when multiple trusted ClickClack instances
must share one hostname:
CLICKCLACK_PUBLIC_URL=https://chat.example.com:8443
CLICKCLACK_COOKIE_NAMESPACE=productionThe namespace must be at most 32 characters and contain lowercase letters,
digits, and interior hyphens. HTTPS deployments receive __Host- cookie names,
such as __Host-cc-production-session; path-mounted APIs use the path-compatible
__Secure- prefix and scope cookies to the configured API base path. Loopback HTTP uses
cc-production-session.
Treat the namespace as durable deployment identity:
- Every replica serving the same public origin and database must use the same namespace.
- Different instances on the same hostname must use different namespaces.
- Changing it signs browsers out and strands in-progress OAuth browser state until that state expires.
Cookies are scoped to hostnames, not ports. Namespaces prevent accidental same-name collisions; they are not a security boundary between mutually untrusted services. Put untrusted instances on separate hostnames. Use separate registrable domains when compromise of one deployment must not affect another.
SQLite forms:
sqlite://./data/clickclack.db
./data/clickclack.db
Both end up at the same place — the sqlite:// prefix is stripped. The
parent directory is created on open.
Postgres forms:
postgres://user:pass@host:5432/clickclack?sslmode=require
postgresql://user:pass@host:5432/clickclack?sslmode=require
serve, migrate, and admin commands all accept --db or
CLICKCLACK_DB. Postgres stores durable chat state in the external database.
Local disk is the default:
CLICKCLACK_UPLOADS=file:///var/lib/clickclack/uploadsCloudflare R2 uses the S3-compatible API:
CLICKCLACK_UPLOADS=r2://clickclack-uploads/prod
CLICKCLACK_R2_ACCOUNT_ID=91b59577e757131d68d55a471fe32aca
CLICKCLACK_R2_ACCESS_KEY_ID=...
CLICKCLACK_R2_SECRET_ACCESS_KEY=...The database still stores upload metadata and auth visibility. The upload
backend stores the bytes and streams them back through /api/uploads/{id} after
the normal ClickClack permission checks.
For non-local deployments:
clickclack serve \
--dev-bootstrap=false \
--config /etc/clickclack/config.jsonCombine with real auth (CLI-created magic links or GitHub OAuth) so the
"first-user-in-DB" dev auth fallback never kicks in. In containers, this is
already the default; CLICKCLACK_DEV_BOOTSTRAP=false is only an explicit guard.
{ "addr": ":8080", "data": "./data", "db": "sqlite:///var/lib/clickclack/clickclack.db", "uploads": "file:///var/lib/clickclack/uploads", "environment": "staging", "metrics_enabled": false, "dev_bootstrap": false, "public_url": "https://chat.example.com", "public_api_url": "https://api.example.com/services/clickclack", "embed_frame_ancestors": ["https://control.example.com"], "access_team_domain": "https://openclaw.cloudflareaccess.com", "access_aud": "<application-audience-tag>", "cookie_namespace": "production", "github_client_id": "Iv1.xxxxxxxxxxxx", "github_client_secret": "...", "github_allowed_org": "openclaw", "github_moderator_org": "openclaw", "pushover_api_token": "azGDORePK8gMaC0QOYAMyEEuzJnyUi", "r2_account_id": "91b59577e757131d68d55a471fe32aca", "r2_access_key_id": "...", "r2_secret_access_key": "..." }