# Any Ubuntu server

> Install Grovs on a fresh Ubuntu server from any provider, using the steps every VM guide shares.

Source: https://docs.grovs.io/docs/self-hosting/clouds/cloud-vm

## When to use

Your provider has no dedicated guide, or you want the shared VM steps that the [DigitalOcean](https://docs.grovs.io/docs/self-hosting/clouds/digitalocean), [Hetzner](https://docs.grovs.io/docs/self-hosting/clouds/hetzner), [Vultr](https://docs.grovs.io/docs/self-hosting/clouds/vultr), [Akamai / Linode](https://docs.grovs.io/docs/self-hosting/clouds/akamai) and [Scaleway](https://docs.grovs.io/docs/self-hosting/clouds/scaleway) guides link to. The installer runs the full Compose stack on one server under `/opt/grovs`.

## Prerequisites

| Requirement | Value                                                                                                           |
| ----------- | --------------------------------------------------------------------------------------------------------------- |
| Image       | Fresh **Ubuntu 24.04 x86_64**                                                                                  |
| Size        | At least **4 vCPU, 8 GB RAM, 80 GB SSD**. See [Sizing](https://docs.grovs.io/docs/self-hosting/operate/sizing). |
| Network     | Public IPv4 address                                                                                             |
| Access      | An SSH key                                                                                                      |
| Domain      | A domain you control                                                                                            |

The provider bills your account for the server, storage and traffic.

## 1. Prepare DNS and firewall

In the provider's firewall, allow inbound TCP 80 and 443 from the internet and TCP 22 from your public IP only, plus outbound DNS, HTTPS and package downloads. [Firewall](https://docs.grovs.io/docs/self-hosting/operate/security#firewall) explains each rule. If a host firewall is already active, allow web traffic there too.

Point the [DNS records](https://docs.grovs.io/docs/self-hosting/get-started/deployment#dns) at the server's public IPv4. For `grovs.example.com` this includes `dashboard.grovs.example.com`, `api.grovs.example.com`, the other fixed hosts, `*.grovs.example.com` and `*.test.grovs.example.com`. If you use Cloudflare, keep these records DNS-only. Caddy handles HTTPS; the DNS guide also covers certificates for mobile app links.

## 2. Create the server

Create the server in your provider's console with the prerequisites above, then connect over SSH.

## 3. Install Grovs

### Over SSH

On the new server, download the reviewed bootstrap script and inspect it:

```bash
curl -fsSL https://raw.githubusercontent.com/grovs-io/self-host/d9f291fb7a943adc8b712696342180ea63438cfd/deploy/vm/bootstrap.sh \
  -o /tmp/grovs-bootstrap.sh
less /tmp/grovs-bootstrap.sh
```

Run it with your domain and email. It installs packages and creates the installation under `/opt/grovs`:

```bash
sudo env GROVS_DOMAIN=grovs.example.com \
  GROVS_ADMIN_EMAIL=admin@example.com \
  GROVS_VERSION=2.3.1 \
  GROVS_STACK_REF=d9f291fb7a943adc8b712696342180ea63438cfd \
  bash /tmp/grovs-bootstrap.sh < /dev/null
```

`GROVS_VERSION` selects the published image version for both backend and dashboard. `GROVS_STACK_REF` selects the source commit for the Compose and setup files. Generated credentials stay in `/opt/grovs/.env`; the bootstrap does not print them into cloud logs.

### With cloud-init at first boot

Providers that accept startup data (cloud-init) can install Grovs on first boot instead. On your workstation, generate the file with your domain and administrator email:

```bash
git clone https://github.com/grovs-io/self-host.git
cd self-host
python3 scripts/generate-cloud-init.py \
  --domain grovs.example.com \
  --email admin@example.com > /tmp/grovs-cloud-init.yaml
```

The file installs Docker and the full Compose stack on first boot. It pins the stack source to a reviewed commit and defaults to image release `2.3.1`. Use `--version X.Y.Z` to select another published release. Passwords are generated on the server; the file contains no generated credentials.

Paste the complete file, including `#cloud-config`, into the provider's startup data field when you create the server.

## 4. Deploy and verify

Connect with your SSH key and check provisioning:

```bash
sudo cloud-init status --wait          # cloud-init installs only
sudo systemctl status grovs --no-pager
sudo journalctl -u grovs --no-pager -n 100
sudo tail -100 /var/log/cloud-init-output.log   # cloud-init installs only
sudo cat /opt/grovs/.env
```

Read `BOOTSTRAP_ADMIN_EMAIL` and `BOOTSTRAP_ADMIN_PASSWORD` from `.env` and keep the file private. Open `https://dashboard.grovs.example.com`, log in, create a project and a link, then open the link and check analytics.

## Upgrades

The stack and configuration live in `/opt/grovs`. Databases and uploads use Docker volumes on the server disk. `grovs.service` starts the existing stack after a reboot.

Run every [Operate](https://docs.grovs.io/docs/self-hosting/operate) procedure from `/opt/grovs` as root: [Upgrades](https://docs.grovs.io/docs/self-hosting/operate/upgrades), [Backups](https://docs.grovs.io/docs/self-hosting/operate/backups), [Monitoring](https://docs.grovs.io/docs/self-hosting/operate/monitoring) and [Security](https://docs.grovs.io/docs/self-hosting/operate/security). Before real traffic, work through the [production checklist](https://docs.grovs.io/docs/self-hosting/operate/production-checklist).

## Gotchas

- If startup fails, fix the reported error and rerun the install: the SSH command with the same environment variables, or `sudo bash /root/grovs-bootstrap.sh` for cloud-init installs. The bootstrap preserves an existing `.env`.
- If the dashboard is not ready, check `sudo docker compose --project-directory /opt/grovs ps -a` and the `migrate` service logs.
- Before you remove the server, see [Before you remove a server](https://docs.grovs.io/docs/self-hosting/operate/backups#before-you-remove-a-server).
