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
| Variable | What it does |
|---|---|
DASHBOARD_HOST | Hostname of the dashboard UI. |
API_HOST | Dashboard / REST API host. Also serves storage blobs (proxy mode). |
SDK_HOST | Mobile + server SDK host — this exact value is the SDK baseURL. |
MCP_HOST | MCP (Model Context Protocol) OAuth/API host. |
GO_HOST | Short-link helper host. |
LINKS_PROD_HOST | Production links host (under DOMAIN_LIVE). |
LINKS_TEST_HOST | Test links host (under DOMAIN_TEST). |
PREVIEW_HOST | Link-preview host. |
ACME_EMAIL | Email Let's Encrypt uses for cert-expiry notices. |
Self-hosted flags
| Variable | What it does |
|---|---|
GROVS_SELF_HOSTED | Master 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_EE | Enterprise edition (in-app-purchase / revenue features). Leave false unless licensed. |
Domains
| Variable | What it does |
|---|---|
DOMAIN_LIVE | Production base / registrable domain (e.g. example.com) — not a subdomain. All reserved hosts and per-project prod link subdomains are children of it. |
DOMAIN_TEST | Test 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_HOST | Protocol + host the backend uses to build absolute URLs — your API host. |
REACT_HOST_PROTOCOL / REACT_HOST | Protocol + host for dashboard links (e.g. in emails) — your dashboard host. |
PREVIEW_BASE_URL | Full URL of the preview host. |
MCP_CONSENT_URL | OAuth consent URL for MCP — your dashboard's /mcp/authorize. |
Database & cache
| Variable | What it does |
|---|---|
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB | Credentials + name for the bundled PostgreSQL. |
POSTGRES_MAX_CONNECTIONS | Server-side connection ceiling. Keep ≥ (web replicas × RAILS_DB_POOL) + worker pools. |
DATABASE_URL | Connection string Rails uses. Password must match POSTGRES_PASSWORD. Point at managed Postgres for a custom deployment. |
REDIS_URL | Redis connection — queues, caches, dedup, fingerprints. |
Process sizing
Raise these as you add CPU/RAM.
| Variable | What it does |
|---|---|
WEB_CONCURRENCY | Puma worker processes per web container. |
RAILS_MAX_THREADS | Threads per Puma worker. |
RAILS_DB_POOL | DB connection pool per process. |
SIDEKIQ_EVENTS_CONCURRENCY | Threads for the events worker. |
Object storage
| Variable | What it does |
|---|---|
MINIO_ROOT_USER / MINIO_ROOT_PASSWORD | Admin credentials for the bundled MinIO. |
AWS_S3_KEY_ID / AWS_S3_ACCESS_KEY | S3 credentials — must equal the MinIO creds for the bundled setup (or your AWS keys). |
AWS_S3_REGION / AWS_S3_BUCKET | Region + bucket name. |
S3_ENDPOINT | http://minio:9000 for bundled MinIO; leave empty for real AWS S3. |
S3_FORCE_PATH_STYLE | true for MinIO. |
S3_ASSET_PREFIX | Public 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.
| Variable | What it does |
|---|---|
SECRET_KEY_BASE | Rails session/signing secret. Keep stable. |
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY, _DETERMINISTIC_KEY, _KEY_DERIVATION_SALT | At-rest encryption keys. Never change after data exists — rotating them makes encrypted columns unreadable. |
ADMIN_API_KEY / DIAGNOSTICS_API_KEY / SENT_QUOTAS_WEBHOOK_KEY | Keys guarding internal admin / diagnostics / webhook endpoints. |
RAILS_ENV / RAILS_LOG_TO_STDOUT / RAILS_SERVE_STATIC_FILES | production / true / true. |
PUBLIC_GO_PROJECT_IDENTIFIER | Identifier for the built-in go redirect project (seeded automatically). |
OAuth & dashboard
| Variable | What it does |
|---|---|
OAUTH_CLIENT_UID / OAUTH_CLIENT_SECRET | Doorkeeper "React" app credentials; the seed upserts the app to these. |
NEXT_PUBLIC_CLIENT_ID | Must equal OAUTH_CLIENT_UID. Baked into the dashboard at build time. |
CLIENT_SECRET | Must equal OAUTH_CLIENT_SECRET. Used by the dashboard's server-side token route. |
NEXT_PUBLIC_API_URL | https://<API_HOST> — where the dashboard calls the API. |
NEXT_PUBLIC_API_PATH | API path prefix, /api/v1. |
NEXT_PUBLIC_SELF_HOSTED | true — 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
| Variable | What it does |
|---|---|
BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD | The seed creates this admin so you can log in with no SMTP/SSO. After login you're prompted to create your first project. |
Branding & link images
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:
| Variable | Used for |
|---|---|
DEFAULT_LOGO_URL | App icon on the link landing page when a project has no app-store icon. |
DEFAULT_SOCIAL_PREVIEW_URL | OG / Twitter card image when a link has no custom preview image. |
DEFAULT_LINK_TITLE | Default og:title for link previews. |
DEFAULT_LINK_SUBTITLE | Default 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.
| Variable | What it does |
|---|---|
MAILER_DELIVERY_METHOD | Leave empty to disable email. Set to smtp to enable. |
SMTP_ADDRESS / SMTP_PORT / SMTP_DOMAIN | SMTP server address, port, HELO domain. |
SMTP_USERNAME / SMTP_PASSWORD | SMTP authentication. |
SMTP_AUTHENTICATION | plain, login, or cram_md5. |
SMTP_ENABLE_STARTTLS_AUTO | true to use STARTTLS when available. |
MAILER_FROM | From address for outgoing email. |