How to Deploy Grafana on a VPS
Updated Aug 2026
Self-host Grafana on your own VPS — the standard open-source dashboarding layer for metrics, logs, and traces, querying Prometheus, Loki, InfluxDB, and dozens of other data sources.
- A VPS with 1+ GB RAM
- A metrics or logs data source (e.g. Prometheus) — or use Grafana's built-in SQL sources
- A fresh Ubuntu 24.04 or 26.04 server with root/sudo SSH access
What Grafana is
Grafana is the standard open-source dashboarding layer for metrics, logs, and traces. It doesn't collect data itself — it connects: Prometheus for metrics, Loki for logs, InfluxDB, Postgres, and dozens of other sources plug in as data sources, and Grafana turns them into unified dashboards and alerting in one pane of glass.
The appeal of self-hosting it is control and breadth: no per-user SaaS seat costs, your queries and dashboards live on your own box, and one Grafana instance can visualize everything from server health to application business metrics. It's a Go backend with a TypeScript frontend, rated 2 / 5 to deploy, and comfortable on 1 GB of RAM — a light, reliable service that runs on a modest VPS for years.
Server sizing — Grafana is light, the data sources aren't
Grafana itself needs surprisingly little. It stores dashboards and users in an embedded database and spends most of its time serving queries over the network.
Standalone sizing:
- 1 GB RAM — plenty for dashboards, users, and alerting on a small setup
- 2 GB RAM — if you're running many concurrent dashboard users or large queries against heavy data sources
Running data sources on the same box: add the backends on top. A Prometheus server wants another 1–2 GB, Loki similar, so a combined observability VPS is happier at 2–4 GB total. A Hetzner CX22 (2 vCPU / 4 GB) runs Grafana plus Prometheus and Loki comfortably.
Prepare the server
Start from a fresh Ubuntu 24.04 or 26.04 server. Update and create a non-root user:
apt update && apt upgrade -y
adduser deploy
usermod -aG sudo deploy
Lock down the firewall:
ufw allow OpenSSH
ufw allow 80
ufw allow 443
ufw enable
Install Docker:
curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy
Log out and back in as deploy so the docker group takes effect.
Install Grafana
Create a working directory:
mkdir ~/grafana && cd ~/grafana
Create a compose file:
services:
grafana:
image: grafana/grafana-oss:latest
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
volumes:
- grafana_data:/var/lib/grafana
volumes:
grafana_data:
The 127.0.0.1 bind keeps Grafana private — a reverse proxy handles public
access, which also protects you from an open, default-admin dashboard on the
open internet.
Start it:
docker compose up -d
Grafana listens on port 3000.
Connect a data source
Grafana is only as useful as the data behind it. Add a first source via Connections → Data sources → Add data source. The classic pairing is Prometheus; if you don't have one yet, the quick container version in its own directory:
mkdir ~/prometheus && cd ~/prometheus
cat > compose.yaml <<EOF
services:
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
ports:
- "127.0.0.1:9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
volumes:
prometheus_data:
EOF
Then reload Prometheus from your host as needed (or keep it static with a few
scrape targets in prometheus.yml), start it, and add it as a data source in
Grafana at http://127.0.0.1:9090. Grafana queries the data source over the
Docker network or host network, so the URL must resolve from Grafana's
container — on the same server, http://host.docker.internal:9090 is the
reliable pick.
HTTPS + domain
Grafana carries login credentials and, increasingly, alerts — it needs HTTPS in
production. Point a reverse proxy at 127.0.0.1:3000 and terminate TLS on 443.
The simplest path is Automatic HTTPS with Caddy.
Point an A record for your hostname (say monitor.example.com) at the server's
public IP, then have Caddy reverse-proxy that hostname to 127.0.0.1:3000.
If you use the Caddy container approach, put Grafana and Caddy in the same compose file and proxy to the Grafana service name:
reverse_proxy grafana:3000
First login and hardening
Load https://monitor.example.com. On a fresh install, the default credentials
are admin / admin — Grafana forces a password change on first login.
Change it immediately. An unauthenticated Grafana is a read of all your metrics and, with alerting enabled, a foothold. After that:
- Set the admin email under Administration → Users → Main admin, so password resets reach you.
- Create a data source and a first dashboard to confirm the chain works.
- Turn off anonymous access unless you want public dashboards (Configuration → Users → Anonymous).
Backups
The important data — dashboards, users, and data-source configs — lives in the Grafana volume:
docker run --rm -v grafana_data:/data -v $(pwd):/backup alpine \
tar czf /backup/grafana-$(date +%F).tar.gz -C /data .
This backs up everything you've configured. Restore it to a fresh Grafana instance and your dashboards come back. For an even simpler safety net, use a provider's daily snapshot (a Hetzner CX22 at $4.59/mo includes backups) — but note snapshots restore the whole box, not just Grafana.
Upgrades
Pull the newer image and recreate:
docker compose pull
docker compose up -d
Grafana runs migrations automatically on startup. Check the Grafana releases page before a major version bump, since plugin and dashboard schema changes occasionally need attention.
Troubleshooting
Dashboard loads but no data. The data source isn't reachable from the
Grafana container. Verify the URL resolves from inside the container — on the
same host, prefer http://host.docker.internal:PORT over 127.0.0.1, which
would point at the container itself.
Can't log in / forgotten admin password. Grafana resets the admin password
from the GF_SECURITY_ADMIN_PASSWORD environment variable on startup; set it in
the compose file, recreate the container, log in, then change it in the UI.
Alerts not firing. Check that alerting is enabled for the data source and that the alert's evaluation interval is set. Test with a query you know returns data.
Page loads slowly. Usually a heavy query against a remote data source. Add Grafana's caching or point it at a closer/leaner backend before sizing up the VPS.
Verification + next steps
You're done when you can: load the dashboard over HTTPS, log in with a strong password, add a data source, build a dashboard that shows live data, and create an alert. You're ready to use it as the one window over your whole fleet.
From here, add Loki for logs, Prometheus node_exporter agents on your other servers, or the Netdata agent — Grafana vs Netdata explains how the two fit together. For a monitoring-first VPS, see Best VPS for Monitoring & Uptime for the ranked picks.