Docs
grovs.io Start for free

Deploy on a server

Set up DNS, run the one-command installer and log in on any Linux server with Docker.

This is the generic install. For a guided setup, see Platforms or Cloud VMs.

Prerequisites

RequirementValue
ServerLinux with Docker and Docker Compose v2, ports 80 and 443 open
Size4 vCPU, 8 GB RAM, 80 GB SSD for up to 100,000 users. See Sizing.
DomainOne domain you control, with DNS you can edit

DNS

Grovs uses up to three domains. The installer asks for them in this order. Press Enter to accept each default.

PromptVariableWhat lives thereDefault
App domainSERVER_HOSTdashboard., api., sdk., go., mcp., preview.local trial on lvh.me
Links domainDOMAIN_LIVEproduction links: <project>.<links domain>the app domain
Test links domainDOMAIN_TESTtest links: <project>.<test links domain>test.<links domain>

The usual setup is a branded short domain for links (acme.link) and the company domain for the app (acme.com). One domain for everything also works. The test links domain can be a sub-label of the links domain (the default) or a separate domain.

Create every record as an A record pointing at your server's IPv4. Add a matching AAAA if the server has IPv6.

DomainName (host)Serves
appdashboard, api, sdk, go, mcp, previewthe fixed hosts
links* (wildcard)per-project production links, for example a1b2c3d4.acme.link
linkslinksLINKS_PROD_HOST, with a pre-issued certificate
test links* (wildcard)per-project test links, for example a1b2c3d4.test.acme.link
test linkslinksLINKS_TEST_HOST, with a pre-issued certificate

With one domain for everything, that is the six fixed hosts plus * and *.test.

The * wildcards are mandatory. Every project gets its own random link subdomain. Without the wildcards those subdomains return 404 and cannot get a TLS certificate.

The standalone Caddy proxy issues certificates on demand for each new subdomain. The first request takes a few seconds. Apple's and Google's association fetchers can time out on that cold start and cache the failure for about an hour.

For reliable Universal Links and App Links, pre-issue wildcard certificates for the links and test links domains through your DNS provider's API. Behind Cloudflare, keep the link records DNS-only (grey cloud) so Caddy terminates TLS, or use a Cloudflare Origin certificate.

Install

Once DNS points at the server, run:

Bash
curl -fsSL https://github.com/grovs-io/self-host/releases/latest/download/install.sh | bash

The installer comes from the latest completed release and selects its matching GHCR images. It:

  1. Downloads the stack into ./grovs.
  2. Asks for your app domain, links domain, test links domain and admin email.
  3. Generates every secret and pulls the images.
  4. Starts the stack with the standalone proxy.

An exported GROVS_VERSION overrides its default version. Press Enter at the first prompt to start a local trial on lvh.me instead (see Try locally).

Manual install

Read install.sh first if you prefer. The manual equivalent:

Bash
git clone https://github.com/grovs-io/self-host.git grovs && cd grovs
GROVS_RELEASE_URL="$(curl -fsSL -o /dev/null -w '%{url_effective}' https://github.com/grovs-io/self-host/releases/latest)"
GROVS_VERSION="${GROVS_RELEASE_URL##*/}" ./scripts/setup.sh  # writes .env and prints your admin password
docker compose --profile standalone pull
docker compose --profile standalone up -d       # drop the profile on platforms with their own proxy

setup.sh writes every hostname from your domains. It generates the database and ClickHouse passwords, the Rails secrets, the OAuth pair and the admin password. It keeps an existing .env. Save the admin password it prints.

On first start, migrate runs the PostgreSQL and ClickHouse migrations and the seed (the OAuth app and your bootstrap admin). Then web and the workers start. Certificates are issued on the first request to each host.

First login

Open https://<DASHBOARD_HOST> and log in with the admin email and the password setup.sh printed. The bootstrap admin needs no SMTP or SSO.

Public sign-up is disabled. On first login the dashboard asks you to create your first project; there is no default project. Invite more members from the dashboard. Each invite produces a copyable link unless you configure SMTP.

A fresh install shows "Analytics temporarily unavailable" until the first rollup completes, about a minute after boot. Reload the page.

After you create a project, copy its API key for the SDKs. There is one key per environment, test and production.

Verify

Bash
# Backend health
curl -sS https://<API_HOST>/up            # -> 200

Then in the dashboard: log in, create a project, create a link and open it. Monitoring covers ongoing health checks.

Change settings

All settings live in .env in the install directory. Edit it, then apply:

Bash
docker compose --profile standalone up -d                                   # real domain
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d      # local trial

Compose restarts only the containers whose environment changed. The database, uploads and analytics stay.

  • Never change the generated secrets after the first start: SECRET_KEY_BASE, the ACTIVE_RECORD_ENCRYPTION_* keys, and the database and ClickHouse passwords. Existing data is bound to them.
  • If you change a domain, update DNS first.

Every variable is listed in Configuration. Before real traffic, work through the production checklist.

Last updated 2026-10-26
Was this page helpful?