This guide installs Grafana on a Debian or Ubuntu VPS from Grafanaโs official APT repository. It also covers a persistent Docker alternative, private first access, the current data source menu, backups, and the checks to run after an update.
Grafana is the visualization and alerting layer. Prometheus, Loki, Tempo, InfluxDB, or another data source usually stores the telemetry. Size the VPS for the Grafana server and its query workload, then budget data-source capacity separately. See the Grafana VPS requirements guide before choosing a plan.
Before You Install
Prepare the following:
- A currently supported Debian or Ubuntu release
- A non-root SSH account with
sudoaccess - A DNS name such as
grafana.example.com - A firewall that does not expose Grafanaโs port 3000 to the public internet
- A reverse proxy with HTTPS for normal browser access
Use one installation method on a host. The APT method integrates with systemd and the distribution package manager. The Docker method is useful when you already operate containers.
Choosing Your VPS Provider
Choose a plan that fits the dashboard workload and the other services sharing the VPS. The provider table below is a starting point; verify current plan details before ordering:
| Provider | Monthly Price | RAM | CPU | Storage |
|---|---|---|---|---|
| Contabo VPS | 5.99 EUR | 4 GB | 2 vCPU | 200 GB SSD |
| Hetzner Cloud | 5.49 EUR | 4 GB | 2 vCPU | 40 GB NVMe |
| DigitalOcean | 6 USD | 2 GB | 1 vCPU | 50 GB SSD |
| Vultr | 6 USD | 2 GB | 1 vCPU | 55 GB SSD |
| Linode | 5 USD | 4 GB | 2 vCPU | 80 GB SSD |
Treat the table as a shortlist, not a sizing rule. For a decision page with Grafana-specific tradeoffs, compare the best VPS options for Grafana or the lower-cost Grafana VPS shortlist.
Step 1: Prepare the VPS
Connect with the administrative account created during provisioning:
ssh admin@your_vps_ip
Update the package index and installed packages before adding Grafana:
sudo apt-get update
sudo apt-get upgrade
If this is a production server, review the pending upgrades before accepting them and reboot if the operating system requires it.
Step 2: Install Grafana From the Official APT Repository
Grafanaโs current Debian and Ubuntu instructions require apt-transport-https, wget, and gnupg:
sudo apt-get install -y apt-transport-https wget gnupg
sudo mkdir -p /etc/apt/keyrings
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
sudo chmod 644 /etc/apt/keyrings/grafana.asc
Add the stable repository and install Grafana OSS:
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install grafana
The repository method lets normal package updates deliver future Grafana releases. Read the release notes and make a backup before a production upgrade.
Step 3: Start and Verify the Service
Enable Grafana at boot and start it now:
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server --no-pager
If the service is not active, inspect its recent log entries:
sudo journalctl -u grafana-server -n 100 --no-pager
Do not open port 3000 to the whole internet just to complete setup. Use an SSH tunnel for private first access:
ssh -L 3000:127.0.0.1:3000 admin@your_vps_ip
Keep that SSH session open and visit http://127.0.0.1:3000 on your own computer. Unless you changed the defaults, use admin for both the username and password, then replace the initial password when Grafana prompts you.
Step 4: Bind Grafana to the Private Interface
For an APT installation, place custom settings in /etc/grafana/grafana.ini. Do not edit defaults.ini. If the reverse proxy runs on the same VPS, bind Grafana to loopback and set its public URL:
[server]
http_addr = 127.0.0.1
http_port = 3000
domain = grafana.example.com
root_url = https://grafana.example.com/
enforce_domain = true
Restart Grafana and confirm that it listens locally:
sudo systemctl restart grafana-server
sudo systemctl is-active grafana-server
sudo ss -ltnp | grep ':3000'
Grafanaโs default empty http_addr binds to all interfaces. Setting it to 127.0.0.1 keeps direct access private when the reverse proxy is on the same host. If your proxy runs elsewhere, use the appropriate private network address and restrict access with firewall rules.
Step 5: Put HTTPS in Front of Grafana
Use Nginx, Apache, HAProxy, Traefik, or another maintained reverse proxy. Route the public hostname to 127.0.0.1:3000, terminate TLS at the proxy, and pass the original Host header. Grafana Live uses WebSockets, so copy the WebSocket headers from Grafanaโs official proxy example rather than using a generic HTTP-only block.
Check all of these before making the hostname public:
https://grafana.example.com/loads without a certificate warning- HTTP redirects to HTTPS
- Port 3000 is not reachable from an external network
- The configured
root_urlmatches the browser URL - Grafana Live connections work through the proxy
Step 6: Add a Data Source and a Test Panel
Only an organization administrator can add or remove a data source. In the current interface, open Connections > Data sources, choose the integration, enter its connection details, and use Save & test.
Create a small verification dashboard before importing a large community dashboard:
- Open Dashboards and create a dashboard.
- Add one panel with a simple query.
- Confirm the returned time range and units.
- Save the dashboard, sign out, and sign in again to verify persistence.
Grafana users can query data sources available to their organization. Use separate organizations, restricted data-source credentials, network rules, or Grafanaโs permission features when a data source contains sensitive records.
Docker Alternative With Persistent Storage
Skip the APT steps if you choose Docker. With Docker already installed, create a named volume and bind the published port to loopback:
sudo docker volume create grafana-storage
sudo docker run -d \
--name grafana \
--restart unless-stopped \
-p 127.0.0.1:3000:3000 \
--volume grafana-storage:/var/lib/grafana \
grafana/grafana
The volume is essential. Without persistent storage, deleting the container also discards its local Grafana database, users, dashboards, and other container filesystem changes. Put the same HTTPS reverse proxy in front of the loopback port.
Verify the container and its logs:
sudo docker ps --filter name=grafana
sudo docker logs --tail 100 grafana
Back Up Before Updates
For the APT installation, back up the modified configuration, plugin directory, and database:
/etc/grafana/grafana.ini/var/lib/grafana/plugins/var/lib/grafana/grafana.dbwhen using the default SQLite database
Stop Grafana before copying the SQLite database so that the backup is consistent. If you configured MySQL or PostgreSQL instead, use that database systemโs backup tools. For Docker, back up the named volume or the external database plus any provisioned configuration.
After an update, check service health, the login flow, data-source tests, a representative dashboard, alerts, and reverse-proxy logs. Keep the previous package or image version available until those checks pass.
FAQ
Does Grafana Store My Metrics and Logs?
Normally, no. Grafana stores its own application state, including users, dashboards, and data-source definitions. Metrics, logs, and traces usually remain in systems such as Prometheus, Loki, Tempo, or a database. Back up both layers according to their roles.
Why Does Grafana Work Through SSH but Not Through My Domain?
Check the reverse-proxy target, firewall, TLS certificate, DNS record, and the [server] values in grafana.ini. A mismatched root_url can break redirects. Grafana Live also needs the proxyโs WebSocket configuration.
Can I Expose Port 3000 Directly?
It can be exposed deliberately, but a public production setup should use HTTPS, access controls, and a reviewed firewall policy. Binding Grafana to loopback behind a reverse proxy reduces accidental direct exposure and gives you one place to manage TLS.
Which Files Must I Back Up?
For the default APT setup, protect /etc/grafana/grafana.ini, /var/lib/grafana/plugins, and /var/lib/grafana/grafana.db. Stop the service before copying the SQLite file. A Docker deployment needs a backup of its persistent volume or external database.