# How to self-host Grafana with Docker Compose

> Grafana Docker Compose setup in 10 minutes: a pinned image, persistent storage, admin password from .env, plugins, HTTPS reverse proxy, backups and upgrades.

## Key facts

| Fact | Value |
|---|---|
| App | Grafana (https://appsgit.com/apps/grafana) |
| Difficulty | beginner |
| Time | about 10 minutes |
| Requirements | 1 vCPU / 512 MB RAM (1 GB+ for many dashboards); Docker + Docker Compose v2; A data source such as Prometheus, InfluxDB or Loki; A domain name (optional, for HTTPS) |
| Last updated | 2026-10-06 |

## What is Grafana?

Grafana is the open source standard for dashboards and observability. It connects to data sources such as Prometheus, Loki, InfluxDB, PostgreSQL, MySQL and Elasticsearch, and turns their data into dashboards, alerts and reports. Homelab users run it to graph server load, network traffic, Home Assistant sensors and power use. Grafana is open source under the AGPL-3.0 license.

## Requirements

- A Linux server with Docker Engine and Docker Compose v2. Grafana alone is light: 1 vCPU and 512 MB of RAM are enough to start.
- At least one data source. If you have none yet, follow our [Prometheus guide](https://appsgit.com/guides/prometheus) to collect server metrics first.
- A domain name if you want HTTPS access.

## Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the [official Docker Engine guide](https://docs.docker.com/engine/install/ubuntu/).

```bash
mkdir -p ~/grafana && cd ~/grafana
```

## Step 2: Create the Docker Compose file

Save this as `docker-compose.yml`:

```yaml
services:
  grafana:
    image: grafana/grafana:13.2.3
    container_name: grafana
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      GF_SERVER_ROOT_URL: ${GF_SERVER_ROOT_URL}
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD}
      GF_USERS_ALLOW_SIGN_UP: "false"
      GF_ANALYTICS_REPORTING_ENABLED: "false"
      GF_PLUGINS_PREINSTALL: grafana-clock-panel
    volumes:
      - grafana_storage:/var/lib/grafana

volumes:
  grafana_storage: {}
```

Then create `.env` next to it:

```bash
GF_SERVER_ROOT_URL=https://grafana.example.com/
GF_ADMIN_PASSWORD=CHANGE_ME
```

Replace `CHANGE_ME` with the output of `openssl rand -hex 32`. The admin password variable only applies when the database is first created; after that, change it in the UI. Pinning `13.2.3` means upgrades only happen when you edit the tag.

Grafana's data lives in a named volume, which avoids permission problems: the container runs as user ID 472, so a bind-mounted folder must be owned by that user (`sudo chown -R 472:0 ./data`). If you want to keep a stack with metrics too, add Grafana to the same Compose file as Prometheus so it can reach `http://prometheus:9090` by service name.

## Step 3: Start and open the app

```bash
docker compose up -d
docker compose logs -f grafana
```

The port is bound to localhost, so either finish Step 4 first or use an SSH tunnel for a quick look: `ssh -L 3000:127.0.0.1:3000 user@YOUR_SERVER_IP`, then open `http://localhost:3000`. Sign in as `admin` with the password from `.env`.

Go to Connections, Data sources, Add data source, pick Prometheus (or your source), enter its URL and click **Save & test**. Then import a ready-made dashboard: Dashboards, New, Import, and enter dashboard ID `1860` (Node Exporter Full) from grafana.com.

## Step 4: Put it behind HTTPS

With [Caddy](https://caddyserver.com/docs/) on the host:

```caddyfile
grafana.example.com {
    reverse_proxy 127.0.0.1:3000
}
```

Caddy gets a Let's Encrypt certificate automatically and passes WebSockets, which Grafana Live uses. Make sure `GF_SERVER_ROOT_URL` matches the public URL, or login redirects and links in alert notifications point to the wrong place. The localhost binding matters: Docker-published ports bypass `ufw`, so `"3000:3000"` would expose plain HTTP even with the firewall enabled.

## Backups and upgrades

Everything Grafana stores (dashboards, users, data source settings, alert rules) is in the SQLite database `grafana.db` inside the volume. Back it up with:

```bash
docker compose stop grafana
docker run --rm -v grafana_grafana_storage:/data -v "$PWD":/backup alpine \
  tar czf /backup/grafana-$(date +%F).tgz -C /data .
docker compose start grafana
```

For an extra safety net, keep important dashboards as JSON in Git (Dashboard, Export). To upgrade, change the tag to the new version, read the "What's new" and breaking changes notes for major releases, then:

```bash
docker compose pull && docker compose up -d
```

## Troubleshooting

- **"GF_PATHS_DATA is not writable":** a bind mount is owned by the wrong user. Run `sudo chown -R 472:0` on the folder or use a named volume.
- **Admin password from .env does not work:** the database already existed when you set it. Reset it with `docker compose exec grafana grafana cli admin reset-admin-password NEW_PASSWORD`.
- **"Origin not allowed" or redirect loops behind the proxy:** `GF_SERVER_ROOT_URL` does not match the domain in the browser.
- **Data source test fails with "connection refused":** inside the container, `localhost` is Grafana itself. Use the service name or the host's LAN IP.

## Next steps

Set up alerting with a contact point such as email or Slack, add Loki for logs, provision data sources and dashboards from files so the setup is reproducible, and enable single sign-on through Authentik or another OAuth provider.

## FAQ

### What port does Grafana use?

Grafana listens on port 3000. Open http://SERVER_IP:3000, or your own domain once a reverse proxy terminates HTTPS in front of it.

### What is the default Grafana login?

The default username and password are both admin, and Grafana asks you to change the password at first login. In Docker you can set a different initial password with the GF_SECURITY_ADMIN_PASSWORD environment variable, as this guide does.

### Is Grafana free?

Yes. Grafana OSS is free and open source under the AGPL-3.0 license. Grafana Enterprise adds paid features such as enterprise data source plugins and reporting, and Grafana Cloud is a hosted service with a free tier.

### Should I use grafana/grafana or grafana/grafana-enterprise?

grafana/grafana is the open source build. The Grafana docs recommend the Enterprise image as the default because it runs with the same features as OSS until you add a license, which makes a later upgrade easier. Pick grafana/grafana if you want a purely open source stack.

### How do I install Grafana plugins in Docker?

Set GF_PLUGINS_PREINSTALL to a comma-separated list of plugin IDs. Grafana installs them on startup and stores them in the data volume.

### Grafana vs Kibana?

Grafana is built for metrics dashboards across many data sources, including Prometheus, Loki, InfluxDB and SQL databases. Kibana is the dashboard layer for Elasticsearch and is strongest at searching and analysing logs stored there.

Prefer not to do it yourself? [appsgit installation help](https://appsgit.com/services/install) installs it on your server for a fixed quote.

---

Canonical page: https://appsgit.com/guides/grafana
Source: appsgit (https://appsgit.com), the app store for github. Data from the GitHub API, refreshed nightly.
Machine access: JSON API https://appsgit.com/api/v1/apps (OpenAPI: https://appsgit.com/openapi.json), MCP server https://mcp.appsgit.com/mcp, full index https://appsgit.com/llms-full.txt.
