Docs

Configuration

Every environment variable for a self-hosted Grovs deployment, plus branding / default images and optional email.

Everything is configured through .env (copy from .env.example). ./scripts/setup.sh generates all the secrets and the OAuth pair for you — you mainly fill in the hostnames and two domains. This page documents what every variable does.

Hostnames & TLS

VariableWhat it does
DASHBOARD_HOSTHostname of the dashboard UI.
API_HOSTDashboard / REST API host. Also serves storage blobs (proxy mode).
SDK_HOSTMobile + server SDK host — this exact value is the SDK baseURL.
MCP_HOSTMCP (Model Context Protocol) OAuth/API host.
GO_HOSTShort-link helper host.
LINKS_PROD_HOSTProduction links host (under DOMAIN_LIVE).
LINKS_TEST_HOSTTest links host (under DOMAIN_TEST).
PREVIEW_HOSTLink-preview host.
ACME_EMAILEmail Let's Encrypt uses for cert-expiry notices.

Self-hosted flags

VariableWhat it does
GROVS_SELF_HOSTEDMaster switch — must be true. Disables billing & public sign-ups, removes MAU quotas, turns member invites into copyable links (no SMTP), enables storage proxy mode.
GROVS_EEEnterprise edition (in-app-purchase / revenue features). Leave false unless licensed.

Domains

VariableWhat it does
DOMAIN_LIVEProduction base / registrable domain (e.g. example.com) — not a subdomain. All reserved hosts and per-project prod link subdomains are children of it.
DOMAIN_TESTTest base domain — a separate registrable domain (e.g. example-test.com). Must not be a sub-label of DOMAIN_LIVE, or test links won't route.
SERVER_HOST_PROTOCOL / SERVER_HOSTProtocol + host the backend uses to build absolute URLs — your API host.
REACT_HOST_PROTOCOL / REACT_HOSTProtocol + host for dashboard links (e.g. in emails) — your dashboard host.
PREVIEW_BASE_URLFull URL of the preview host.
MCP_CONSENT_URLOAuth consent URL for MCP — your dashboard's /mcp/authorize.

Database & cache

VariableWhat it does
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DBCredentials + name for the bundled PostgreSQL.
POSTGRES_MAX_CONNECTIONSServer-side connection ceiling. Keep ≥ (web replicas × RAILS_DB_POOL) + worker pools.
DATABASE_URLConnection string Rails uses. Password must match POSTGRES_PASSWORD. Point at managed Postgres for a custom deployment.
REDIS_URLRedis connection — queues, caches, dedup, fingerprints.

Process sizing

Raise these as you add CPU/RAM.

VariableWhat it does
WEB_CONCURRENCYPuma worker processes per web container.
RAILS_MAX_THREADSThreads per Puma worker.
RAILS_DB_POOLDB connection pool per process.
SIDEKIQ_EVENTS_CONCURRENCYThreads for the events worker.

Object storage

VariableWhat it does
MINIO_ROOT_USER / MINIO_ROOT_PASSWORDAdmin credentials for the bundled MinIO.
AWS_S3_KEY_ID / AWS_S3_ACCESS_KEYS3 credentials — must equal the MinIO creds for the bundled setup (or your AWS keys).
AWS_S3_REGION / AWS_S3_BUCKETRegion + bucket name.
S3_ENDPOINThttp://minio:9000 for bundled MinIO; leave empty for real AWS S3.
S3_FORCE_PATH_STYLEtrue for MinIO.
S3_ASSET_PREFIXPublic URL prefix for blobs — point at https://<API_HOST> (proxy mode serves them through the backend).

Rails core & secrets

Generated by setup.sh — you don't normally edit these.

VariableWhat it does
SECRET_KEY_BASERails session/signing secret. Keep stable.
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY, _DETERMINISTIC_KEY, _KEY_DERIVATION_SALTAt-rest encryption keys. Never change after data exists — rotating them makes encrypted columns unreadable.
ADMIN_API_KEY / DIAGNOSTICS_API_KEY / SENT_QUOTAS_WEBHOOK_KEYKeys guarding internal admin / diagnostics / webhook endpoints.
RAILS_ENV / RAILS_LOG_TO_STDOUT / RAILS_SERVE_STATIC_FILESproduction / true / true.
PUBLIC_GO_PROJECT_IDENTIFIERIdentifier for the built-in go redirect project (seeded automatically).

OAuth & dashboard

VariableWhat it does
OAUTH_CLIENT_UID / OAUTH_CLIENT_SECRETDoorkeeper "React" app credentials; the seed upserts the app to these.
NEXT_PUBLIC_CLIENT_IDMust equal OAUTH_CLIENT_UID. Baked into the dashboard at build time.
CLIENT_SECRETMust equal OAUTH_CLIENT_SECRET. Used by the dashboard's server-side token route.
NEXT_PUBLIC_API_URLhttps://<API_HOST> — where the dashboard calls the API.
NEXT_PUBLIC_API_PATHAPI path prefix, /api/v1.
NEXT_PUBLIC_SELF_HOSTEDtrue — hides SaaS-only/billing UI, enables the invite-link flow.

The NEXT_PUBLIC_* values are compiled into the dashboard image at build time — changing them later requires a rebuild.

First-run admin

VariableWhat it does
BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORDThe seed creates this admin so you can log in with no SMTP/SSO. After login you're prompted to create your first project.

Link landing pages and social previews pull images from two places: per-project / per-link images you set in the dashboard, and fallback defaults for when a link has none.

Default images

If a project has no app-store icon and a link has no custom preview image, Grovs falls back to these. They default to the Grovs assets, so links are never blank out of the box — set your own URLs to rebrand:

VariableUsed for
DEFAULT_LOGO_URLApp icon on the link landing page when a project has no app-store icon.
DEFAULT_SOCIAL_PREVIEW_URLOG / Twitter card image when a link has no custom preview image.
DEFAULT_LINK_TITLEDefault og:title for link previews.
DEFAULT_LINK_SUBTITLEDefault og:description for link previews.

Point DEFAULT_SOCIAL_PREVIEW_URL at a 1200×630 JPG/PNG for the best-looking social cards. A per-link image set in the dashboard overrides these defaults.

Uploaded images must be reachable

App icons and per-link preview images you upload in the dashboard are stored in object storage (MinIO/S3) and served back through the API host in proxy mode. For them to appear, S3_ASSET_PREFIX must point at your API host (https://<API_HOST>) and that host must be publicly reachable over HTTPS. A wrong S3_ASSET_PREFIX is the usual cause of "uploaded image doesn't show".

Facebook, LinkedIn, iMessage, etc. cache OG data aggressively. If a link you already shared still looks blank after you fix the image, re-scrape it (e.g. Facebook's Sharing Debugger) or test with a fresh link.

Email (optional)

Email is off by default — the bootstrap admin needs none, and member invites produce copyable links. Set these only if you want password-reset or data-export emails.

VariableWhat it does
MAILER_DELIVERY_METHODLeave empty to disable email. Set to smtp to enable.
SMTP_ADDRESS / SMTP_PORT / SMTP_DOMAINSMTP server address, port, HELO domain.
SMTP_USERNAME / SMTP_PASSWORDSMTP authentication.
SMTP_AUTHENTICATIONplain, login, or cram_md5.
SMTP_ENABLE_STARTTLS_AUTOtrue to use STARTTLS when available.
MAILER_FROMFrom address for outgoing email.

Next step

Point the SDKs at your self-hosted backend →