> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/discordplace/discord.place/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Environment Variables

> Configure the discord.place Express.js server with these environment variables.

Create a `.env` file in the `server/` directory. Use `server/.example.env` as your starting template.

## Required secrets

<Note>
  You should use 256-bit secret keys for `BOT_API_KEY_ENCRYPT_SECRET`, `USER_TOKEN_ENCRYPT_SECRET`, and `PAYMENTS_CUSTOM_DATA_ENCRYPT_SECRET_KEY`. You can generate a 256-bit key in hexadecimal format using a tool like [this one](https://asecuritysite.com/encryption/plain).
</Note>

<ParamField path="COOKIE_SECRET" type="string" required>
  Secret key used to sign and encrypt session cookies. Use a long, random string.
</ParamField>

<ParamField path="BOT_API_KEY_ENCRYPT_SECRET" type="string" required>
  256-bit secret key used to encrypt bot API keys stored in the database.
</ParamField>

<ParamField path="USER_TOKEN_ENCRYPT_SECRET" type="string" required>
  256-bit secret key used to encrypt Discord user access tokens at rest.
</ParamField>

<ParamField path="PAYMENTS_CUSTOM_DATA_ENCRYPT_SECRET_KEY" type="string" required>
  256-bit secret key used to encrypt custom metadata attached to payment records.
</ParamField>

<ParamField path="JWT_SECRET" type="string" required>
  Secret key used to sign and verify JSON Web Tokens issued by the server.
</ParamField>

<ParamField path="CLIENT_SECRET" type="string" required>
  Shared secret used to authenticate requests from the Next.js client's server-side rendering.

  <Warning>
    This value **must match** the `CLIENT_SECRET` variable set in the client's `.env` file. If these differ, server-side rendering requests will be rejected.
  </Warning>
</ParamField>

## Discord credentials

<ParamField path="DISCORD_CLIENT_TOKEN" type="string" required>
  The bot token for your Discord application. Found in the Discord Developer Portal under **Bot > Token**.
</ParamField>

<ParamField path="DISCORD_CLIENT_SECRET" type="string" required>
  The OAuth2 client secret for your Discord application. Found in the Developer Portal under **OAuth2 > Client Secret**.
</ParamField>

<ParamField path="DISCORD_CLIENT_ID" type="string" required>
  The application (client) ID for your Discord application. Found in the Developer Portal under **General Information**.
</ParamField>

<ParamField path="DISCORD_PORTAL_CHANNEL_WEBHOOK_URL" type="string">
  A Discord webhook URL used to post notifications to an internal portal channel (e.g. new bot approved, new emoji published). This webhook must be created by the bot itself so that interactive components (link buttons) are included in the messages.

  Must follow the format `https://discord.com/api/webhooks/XXX/XXX`. Safe to leave empty.
</ParamField>

## Database

<ParamField path="MONGO_URL" type="string" required>
  MongoDB connection string. Accepts both local instances (`mongodb://localhost:27017/discordplace`) and cloud-hosted services like [MongoDB Atlas](https://docs.mongodb.com/manual/reference/connection-string/).
</ParamField>

## S3 storage

All `S3_*` variables (excluding the database backup set) are required. discord.place uses S3-compatible object storage to serve emoji images and sound files. [Cloudflare R2](https://developers.cloudflare.com/r2/) is recommended but any S3-compatible provider works.

<ParamField path="S3_BUCKET_NAME" type="string" required>
  Name of the S3 bucket used for storing emoji and sound assets.
</ParamField>

<ParamField path="S3_ACCESS_KEY_ID" type="string" required>
  Access key ID for authenticating with the S3 provider.
</ParamField>

<ParamField path="S3_SECRET_ACCESS_KEY" type="string" required>
  Secret access key for authenticating with the S3 provider.
</ParamField>

<ParamField path="S3_REGION" type="string" required>
  Region where the bucket is hosted (e.g. `us-east-1`, `auto` for Cloudflare R2).
</ParamField>

<ParamField path="S3_ENDPOINT" type="string" required>
  Custom endpoint URL for S3-compatible providers. For Cloudflare R2 this looks like `https://<account-id>.r2.cloudflarestorage.com`.
</ParamField>

<ParamField path="CDN_URL" type="string" required>
  Public base URL of the CDN from which assets are served. Must be a valid URL with no trailing slash, e.g. `https://cdn.yourdomain.com`. This value should match `NEXT_PUBLIC_CDN_URL` on the client.
</ParamField>

## S3 database backups (optional)

These variables configure a separate S3 bucket for daily database backups. If left empty the server will still start but will print warnings and skip backups entirely.

<ParamField path="S3_DATABASE_BACKUP_BUCKET_NAME" type="string">
  Name of the S3 bucket used for database backup archives.
</ParamField>

<ParamField path="S3_DATABASE_BACKUP_ACCESS_KEY_ID" type="string">
  Access key ID for the backup bucket.
</ParamField>

<ParamField path="S3_DATABASE_BACKUP_SECRET_ACCESS_KEY" type="string">
  Secret access key for the backup bucket.
</ParamField>

<ParamField path="S3_DATABASE_BACKUP_REGION" type="string">
  Region for the backup bucket.
</ParamField>

<ParamField path="S3_DATABASE_BACKUP_ENDPOINT" type="string">
  Endpoint URL for the backup bucket's S3-compatible provider.
</ParamField>

## Bot protection

<ParamField path="CLOUDFLARE_TURNSTILE_SECRET_KEY" type="string" required>
  Your Cloudflare Turnstile **secret key**, used server-side to verify Turnstile tokens submitted by users. Obtain this from the [Cloudflare Turnstile dashboard](https://developers.cloudflare.com/turnstile/get-started/#get-a-sitekey-and-secret-key).
</ParamField>

## Payments — Lemon Squeezy (optional)

<ParamField path="LEMON_SQUEEZY_WEBHOOK_SECRET" type="string">
  Webhook signing secret used to verify that incoming events are from Lemon Squeezy. See the [Lemon Squeezy webhook docs](https://docs.lemonsqueezy.com/help/webhooks) for setup instructions.
</ParamField>

<ParamField path="LEMON_SQUEEZY_API_KEY" type="string">
  API key for making authenticated requests to the Lemon Squeezy API. See the [Lemon Squeezy Developer Guide](https://docs.lemonsqueezy.com/guides/developer-guide/getting-started#create-an-api-key) to create one.
</ParamField>

## Uptime monitoring (optional)

<ParamField path="HEARTBEAT_ID_DAILY_DATABASE_BACKUP" type="string">
  Heartbeat ID from [Better Stack Uptime](https://betterstack.com/uptime). A ping is sent to this heartbeat after each successful daily database backup.
</ParamField>

<ParamField path="HEARTBEAT_ID_S3_BUCKET_AVAILABILITY" type="string">
  Heartbeat ID for monitoring S3 bucket availability. A ping is sent after each successful S3 health check.
</ParamField>

## Bot guild count API (optional)

<ParamField path="DISCORD_BOT_GET_APPROXIMATE_GUILD_COUNT_API_URL" type="string">
  Base URL of a private API used to look up the approximate guild count for a bot. If omitted, bots will not be able to update `server_count` via the public API.
</ParamField>

<ParamField path="DISCORD_BOT_GET_APPROXIMATE_GUILD_COUNT_API_SECRET" type="string">
  Secret key for authenticating requests to the guild count API above.
</ParamField>

## Webhook proxy (optional)

If you route outgoing webhook requests through a proxy server, set these variables. Leave all of them empty to send webhooks directly.

<ParamField path="WEBHOOKS_PROXY_SERVER_PROTOCOL" type="string">
  Protocol for the proxy server, e.g. `http` or `https`.
</ParamField>

<ParamField path="WEBHOOKS_PROXY_SERVER_HOST" type="string">
  Hostname or IP address of the proxy server.
</ParamField>

<ParamField path="WEBHOOKS_PROXY_SERVER_PORT" type="string">
  Port number the proxy server listens on.
</ParamField>

<ParamField path="WEBHOOKS_PROXY_SERVER_USERNAME" type="string">
  Username for proxy authentication. Leave empty if not required.
</ParamField>

<ParamField path="WEBHOOKS_PROXY_SERVER_PASSWORD" type="string">
  Password for proxy authentication. Leave empty if not required.
</ParamField>

## Error tracking — Sentry (optional)

<ParamField path="SENTRY_DSN" type="string">
  Sentry Data Source Name (DSN) for error and performance monitoring. Obtain this from your [Sentry](https://docs.sentry.io) project settings. Leave empty to disable Sentry.
</ParamField>

## GitHub translator sync (optional)

<ParamField path="GITHUB_AUTO_SYNC_TRANSLATORS_SECRET" type="string">
  Secret key used to authenticate the GitHub webhook that triggers automatic syncing of translator roles in the base guild. When configured, a push to the `main` branch will sync role assignments based on the `client/locales/translators.json` file.
</ParamField>
