Configuration reference
The secrets file for wrangler secret bulk
The short version
Garrul runs as one Cloudflare Worker, and exactly two credentials are required: a Turnstile site key and a Turnstile secret key. Everything else on this page is optional and stays off until you set it. Two more required secrets are generated for you, so you never type them.
1. Filling in and uploading the file
The repository ships secrets.example.env, a template with every secret listed, commented out, each with a note on where to get it. You copy it, uncomment what you need, upload it in one call, and delete it.
- Copy the template with owner-only permissions.
- Uncomment the two Turnstile lines and fill in the values. Uncomment anything optional you want.
- Upload every secret at once.
- Delete the file.
install -m 600 secrets.example.env secrets.env
# edit secrets.env
npx wrangler secret bulk secrets.env
rm secrets.env
If you would rather not edit a file, npm run setup asks for the same values, generates the random secrets, uploads everything in one call, and puts a working instance on a *.workers.dev URL. No DNS is needed to try Garrul.
2. Required: two credentials
Create a Turnstile widget in the Cloudflare dashboard. It gives you the pair below. Nothing else is required to deploy.
| Variable | What it does | Where to get it |
|---|---|---|
TURNSTILE_SITE_KEY | The public half of the bot challenge on the comment form. | Cloudflare dashboard → Turnstile |
TURNSTILE_SECRET | The private half; the Worker uses it to verify each challenge. | Cloudflare dashboard → Turnstile |
Two further secrets are required but not in the file: JWT_SECRET and IP_HASH_SECRET. npm run setup generates them with openssl rand and streams them straight to Cloudflare, so they are never written to disk. If you deploy by hand, generate them the same way: openssl rand -base64 32 | npx wrangler secret put JWT_SECRET.
3. Optional, by feature
Leave every line in this section commented out unless you want the feature. An unset secret simply means that feature is off.
Email notifications
| Variable | What it does | Where to get it |
|---|---|---|
RESEND_API_KEY | Sends reply notifications and moderator email. Unset, no email is sent. Also set the plain settings EMAIL_PROVIDER and EMAIL_FROM; the sending domain must be verified in Resend. | resend.com/api-keys |
Webhooks
| Variable | What it does | Where to get it |
|---|---|---|
WEBHOOK_URL | Legacy single-URL webhook. New setups should use the /admin/webhooks endpoints instead. | Your receiving service |
Telegram
| Variable | What it does | Where to get it |
|---|---|---|
TELEGRAM_BOT_TOKEN | Outbound notifications to a Telegram bot. | BotFather in Telegram |
TELEGRAM_WEBHOOK_SECRET | Shared secret for the bot webhook. Only needed if you want inbound commands. | You choose it |
Sign-in providers
Each provider is independent, and an ID is useless without its secret, so set both or neither. You can enable one provider or all five.
| Variable | What it does | Where to get it |
|---|---|---|
GH_CLIENT_ID | GitHub sign-in (ID). | github.com/settings/developers |
GH_CLIENT_SECRET | GitHub sign-in (secret). | github.com/settings/developers |
GOOGLE_CLIENT_ID | Google sign-in (ID). | Google Cloud console → OAuth credentials |
GOOGLE_CLIENT_SECRET | Google sign-in (secret). | Google Cloud console → OAuth credentials |
FACEBOOK_CLIENT_ID | Facebook sign-in (ID). | developers.facebook.com → Facebook Login |
FACEBOOK_CLIENT_SECRET | Facebook sign-in (secret). | developers.facebook.com → Facebook Login |
TWITTER_CLIENT_ID | X/Twitter sign-in (ID). X returns no email address. | developer.x.com → OAuth 2.0 |
TWITTER_CLIENT_SECRET | X/Twitter sign-in (secret). | developer.x.com → OAuth 2.0 |
DISCORD_CLIENT_ID | Discord sign-in (ID). | discord.com/developers → OAuth2 |
DISCORD_CLIENT_SECRET | Discord sign-in (secret). | discord.com/developers → OAuth2 |
Anti-spam
| Variable | What it does | Where to get it |
|---|---|---|
AKISMET_API_KEY | Akismet spam checks. Needed only when SPAM_PROVIDER is akismet. | akismet.com |
AKISMET_SITE_URL | The public site URL registered with Akismet. | Your Akismet account |
SPAM_FORM_TS_SECRET | HMAC key for signed form-timestamp tokens (the fast-submit check). | You choose it; openssl rand -base64 32 |
Usage dashboard and update checks
| Variable | What it does | Where to get it |
|---|---|---|
CF_API_TOKEN | Turns on the usage dashboard at /admin/usage, together with the plain setting CF_ACCOUNT_ID. Analytics-read scope only. | Cloudflare dashboard → API tokens |
GITHUB_TOKEN | Optional update-check token with no permissions. It only raises GitHub's 60 requests/hour limit. | github.com/settings/tokens |
4. Plain settings are not in this file
This file holds only secrets. Everything else, such as feature switches, page sizes and retention periods, is a plain variable in wrangler.toml under [vars]. Three of them ship with a placeholder that you must replace before you deploy:
ALLOWED_ORIGINS: the origins allowed to embed the widget and call the API.PUBLIC_BASE_URL: the public URL of your Worker.OAUTH_CALLBACK_BASE: usually the same URL; it must match the redirect URI you register with each provider.
The full list, with defaults and examples, is the configuration table in the operations guide on GitHub. The INSTALL guide walks through the whole deploy.
5. Handling the file safely
- Leave unused lines commented.
wrangler secret bulktreats an empty value as a real, empty secret. An uncommentedRESEND_API_KEY=would overwrite a live key with nothing. - Delete the file after the upload. It holds plaintext credentials. It is gitignored, but it is still on your disk.
- There is no form on this site that builds the file for you, on purpose. Pasting API keys into any web page is a habit worth not teaching, even when the page runs only in your browser. The template and the setup script keep your credentials on your own machine.
The template is secrets.example.env in the repository. It is generated from a single registry of every variable Garrul reads, so it does not drift from the code. If something on this page is wrong, tell us at [email protected].