Grafana Docker Compose Example
This example is a small, working docker-compose.yml for Grafana, the open-source dashboarding platform. Copy it and Grafana runs on port 3000, with its database, users and dashboards on a persistent volume at /var/lib/grafana.
The stack includes:
- A Grafana container with a persistent volume
- An admin password set from the environment
- An optional Prometheus service, wired in as a data source from a file
- Local-only port binding for security
- Simple reverse-proxy instructions (Caddy example)
1. docker-compose.yml
Create a folder and add:
services:
grafana:
image: grafana/grafana:latest
restart: always
ports:
- "127.0.0.1:3000:3000"
environment:
- GF_SERVER_DOMAIN=grafana.example.com
- GF_SERVER_ROOT_URL=https://grafana.example.com
volumes:
- grafana_data:/var/lib/grafana
volumes:
grafana_data:
Start the stack:
docker compose up -d
Grafana will be available locally at:
http://localhost:3000
Default login:
Username: admin
Password: admin
You will be prompted to change the password on first login.
To skip the default password, set it in the environment before the first start:
environment:
- GF_SECURITY_ADMIN_PASSWORD=change-me
Grafana reads this value only when it creates its database. If the volume already exists, changing it does nothing. Reset the password from the CLI instead:
docker compose exec grafana grafana cli admin reset-admin-password new-password
Add Prometheus as a data source
Grafana shows data; it does not collect it. The most common pair is Grafana with Prometheus. Add a Prometheus service to the same file, and let Grafana load the data source from a provisioning file, so you never click through the UI:
services:
grafana:
image: grafana/grafana:latest
restart: always
ports:
- "127.0.0.1:3000:3000"
volumes:
- grafana_data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning
depends_on:
- prometheus
prometheus:
image: prom/prometheus:latest
restart: always
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
volumes:
grafana_data:
prometheus_data:
provisioning/datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
prometheus.yml (Prometheus scrapes itself, so you have data at once):
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ["localhost:9090"]
The data source URL uses the service name prometheus, not localhost. Inside the Grafana container, localhost is Grafana itself. See Docker Compose networks for how service names resolve.
Install plugins
Set GF_PLUGINS_PREINSTALL to a comma-separated list of plugin IDs. Grafana installs them in the background on each start, into /var/lib/grafana/plugins:
environment:
- GF_PLUGINS_PREINSTALL=grafana-clock-panel,grafana-polystat-panel
Bind mount instead of a named volume
The Grafana image runs as user ID 472, not root. If you swap the named volume for a host folder such as ./grafana-data:/var/lib/grafana, Grafana fails to start with a permission error on that folder. Give the folder to that user first:
mkdir -p grafana-data && sudo chown -R 472:0 grafana-data
2. Add a Reverse Proxy (Caddy example)
To expose Grafana with HTTPS, use a simple Caddyfile:
grafana.example.com {
reverse_proxy localhost:3000
}
Reload Caddy:
systemctl reload caddy
Caddy will automatically request and renew the TLS certificate.
3. Optional: Auto-Start with systemd
# /etc/systemd/system/grafana.service
[Unit]
Description=Grafana (Docker Compose)
After=network.target
[Service]
Type=oneshot
WorkingDirectory=/root/grafana
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Enable the service:
systemctl enable grafana
systemctl start grafana
4. Deploy on Hostim.dev Instead
If you don’t want to manage servers, proxies, or systemd:
- Create a project on Hostim.dev
- Choose Paste Docker Compose
- Insert the YAML from this example
Hostim.dev automatically configures HTTPS, domains, restarts, logs, and persistent storage.
FAQ
Frequently asked questions
What is the default Grafana port in Docker?
Grafana listens on port 3000 inside the container. The example publishes it as 127.0.0.1:3000:3000, so it is reachable only from the host, and a reverse proxy such as Caddy serves it on HTTPS.
What is the default Grafana login?
The username is admin and the password is admin. Grafana asks you to change it on first login. To set it in advance, add GF_SECURITY_ADMIN_PASSWORD to the environment before the first start.
Where does Grafana store its data in Docker?
In /var/lib/grafana inside the container. That folder holds the SQLite database with users, dashboards and data sources, plus installed plugins. Mount a named volume there, or your dashboards are lost when the container is removed.
Why does changing GF_SECURITY_ADMIN_PASSWORD not change my password?
Grafana reads it only when it creates its database on the first start. After that the password lives in the database on the volume. Reset it with: docker compose exec grafana grafana cli admin reset-admin-password new-password.
How do I connect Grafana to Prometheus in Docker Compose?
Run both services in the same Compose file and use http://prometheus:9090 as the data source URL. The service name resolves on the Compose network. Do not use localhost, because inside the Grafana container localhost is Grafana itself.
Why does Grafana fail with a permission error on a bind mount?
The Grafana image runs as user ID 472, so it cannot write to a host folder owned by root. Run sudo chown -R 472:0 on the folder, or use a named Docker volume, which Docker creates with the right owner.