This guide uses Docker Compose to run Grafana with persistent storage and provisioning.
For Docker installation, see Docker.
mkdir -p /opt/grafana/{data,config/provisioning/dashboards,config/provisioning/datasources,dashboards}
cd /opt/grafana
Create config/grafana.ini:
[server]
protocol = http
http_port = 3000
domain = localhost
root_url = %(protocol)s://%(domain)s:%(http_port)s/
http_addr = 0.0.0.0
[database]
type = sqlite3
path = /var/lib/grafana/grafana.db
[security]
admin_user = admin
# Set password via environment variable
[log]
mode = console file
level = info
Create config/provisioning/datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
Create docker-compose.yml:
services:
grafana:
image: grafana/grafana-oss:12.3.2
container_name: grafana
user: "472"
ports:
- "3000:3000"
volumes:
- ./data:/var/lib/grafana
- ./config/grafana.ini:/etc/grafana/grafana.ini:ro
- ./config/provisioning:/etc/grafana/provisioning:ro
- ./dashboards:/etc/grafana/provisioning/dashboards:ro
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_ROOT_URL=http://localhost:3000
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-piechart-panel
restart: unless-stopped
networks:
- monitoring
networks:
monitoring:
driver: bridge
docker compose up -d
Check container status:
docker compose ps
View logs:
docker compose logs -f grafana
Access web UI at http://SERVER_IP:3000 with credentials:
adminadmin123 (change immediately!)curl http://localhost:3000/api/health
docker compose restart grafana
docker compose down
docker compose pull
docker compose up -d
docker compose logs -f grafana
./data volume preserves dashboards and usersGF_SECURITY_ADMIN_PASSWORD to a strong password./data directoryFor a complete monitoring stack, extend docker-compose.yml:
services:
prometheus:
image: prom/prometheus:v3.9.1
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=15d'
restart: unless-stopped
networks:
- monitoring
node_exporter:
image: prom/node-exporter:v1.9.0
container_name: node_exporter
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
restart: unless-stopped
networks:
- monitoring
grafana:
image: grafana/grafana-oss:12.3.2
container_name: grafana
user: "472"
ports:
- "3000:3000"
volumes:
- ./data:/var/lib/grafana
- ./config/provisioning:/etc/grafana/provisioning:ro
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_SERVER_ROOT_URL=http://localhost:3000
depends_on:
- prometheus
restart: unless-stopped
networks:
- monitoring
volumes:
prometheus_data:
networks:
monitoring:
driver: bridge
Create a basic prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['prometheus:9090']
- job_name: 'node'
static_configs:
- targets: ['node_exporter:9100']
Deploying Grafana in containers for production? Our consulting covers:
Get expert help: office@linux-server-admin.com | Contact Page