How To Install Grafana on Ubuntu 26.04 LTS

Install Grafana on Ubuntu 26.04

Dashboards tend to get built at the worst possible moment. A latency spike hits at 2 a.m., someone asks “what changed?”, and the only answer is a pile of top output and a half-remembered journalctl query. Grafana fixes that, but only if it is installed properly. A quick install that listens on a public port 3000 with the default admin password is a liability, not a monitoring platform.

Ubuntu 26.04 LTS, codename Resolute Raccoon, shipped in April 2026, and the 26.04.1 point release is now available. It is the natural base for a new monitoring stack, because LTS means five years of security updates. Ubuntu does not package Grafana in its own archives. The package comes from Grafana Labs’ repository at apt.grafana.com, so the install steps differ a little from a typical apt install.

This guide is for a real server rather than a lab VM. It covers the repository setup, service management, a reverse proxy with TLS, a Prometheus data source, firewall rules, the config file settings that matter, tuning, and the failures that show up in practice. The commands target Ubuntu 26.04 and also work on Debian. A short section covers AlmaLinux and other RPM-based systems.

What You Need Before Starting

Check the basics first. They save a lot of backtracking.

  • An Ubuntu 26.04 LTS server with a non-root user that has sudo.
  • At least 2 GB of RAM and 2 vCPUs for a small to mid-sized setup. Grafana itself is light. Your data sources and heavy dashboards are what use the resources.
  • A DNS record such as grafana.example.com if you plan to serve it over HTTPS.
  • Outbound internet access to apt.grafana.com.
  • Ports 80 and 443 reachable if you want Let’s Encrypt certificates.

Confirm the release before changing anything:

lsb_release -a
uname -r
df -h /var/lib
free -h

Grafana stores its state in /var/lib/grafana. That includes the SQLite database, plugins, and sessions. If /var is on a tiny partition, sort that out now.

Choosing an Install Method

There are three realistic ways to run Grafana on Ubuntu.

Method Best for Trade-off
APT repository Most production servers Upgrades come through normal apt upgrade
Standalone .deb Air-gapped hosts Updates are manual
Docker container Containerised stacks You manage volumes and image tags yourself

The APT route is the one to use almost everywhere. Security fixes arrive with your regular patching, and the package ships a proper systemd unit, a dedicated grafana user, and sane file ownership. The rest of this guide uses it.

Install Grafana from the Official APT Repository

Step 1: Update the system and install prerequisites

sudo apt update && sudo apt upgrade -y
sudo apt install -y apt-transport-https wget gnupg

Step 2: Import the Grafana signing key

Grafana’s documentation uses a keyring file under /etc/apt/keyrings:

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

The chmod 644 is not decoration. Apt drops privileges when it fetches and verifies packages, and an unreadable key produces confusing signature errors later.

Avoid the old apt-key add method. It trusted a key for every repository on the system, and it has been deprecated for years. A scoped signed-by entry limits that key to Grafana’s repo only.

Step 3: Add the repository

echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list

The line uses stable main and is not tied to a release codename. That matters on a brand-new LTS. You do not have to wait for Grafana to publish a “resolute” suite, and the same line works across Ubuntu and Debian releases.

Use tee without -a for a fresh file. Appending repeatedly is a classic way to end up with duplicate entries and “configured multiple times” warnings.

Step 4: Refresh and install

sudo apt update
apt-cache policy grafana
sudo apt install -y grafana

The apt-cache policy check is worth the two seconds. The candidate version should come from apt.grafana.com. If it shows nothing, the repo line or key is wrong, and it is easier to catch that here than after a failed install.

For the Enterprise edition, install grafana-enterprise instead. It comes from the same repository. It runs as the free OSS-equivalent unless a licence is applied, so some teams standardise on it from the start.

Start and Enable the Service

The package installs a systemd unit named grafana-server:

sudo systemctl daemon-reload
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server --no-pager

Then check that it responds locally:

curl -s http://localhost:3000/api/health
ss -tlnp | grep 3000

A healthy instance returns a small JSON body with "database": "ok". Open http://SERVER_IP:3000 in a browser for a first look. The default login is admin / admin, and Grafana forces a password change on first sign-in. Do that immediately, and do not leave a fresh instance exposed while you finish the setup.

If you only want to try it quickly, reach it through an SSH tunnel instead of opening the port:

ssh -L 3000:localhost:3000 user@your-server

Understand the File Layout

Knowing where things live shortens every future troubleshooting session.

  • /etc/grafana/grafana.ini is the main configuration file.
  • /etc/default/grafana-server holds environment variables for the service.
  • /var/lib/grafana/ holds the database, plugins, and session data.
  • /var/log/grafana/grafana.log is the application log.
  • /etc/grafana/provisioning/ holds data sources and dashboards as code.
  • /usr/share/grafana/ holds the binaries and static assets. Never edit anything in here.

The best habit: do not edit grafana.ini directly for local changes. Create a custom.ini pattern or use a drop-in systemd override with environment variables. Package upgrades may add new default options, and a heavily edited main file makes diffs painful. Many teams keep the file in Git or Ansible and treat it as managed config.

Configure Grafana for Production

Open the config:

sudo nano /etc/grafana/grafana.ini

The key settings:

[server]
protocol = http
http_addr = 127.0.0.1
http_port = 3000
domain = grafana.example.com
root_url = https://grafana.example.com/

[security]
admin_user = admin
cookie_secure = true
cookie_samesite = lax
disable_gravatar = true

[users]
allow_sign_up = false

[auth.anonymous]
enabled = false

[analytics]
reporting_enabled = false
check_for_updates = false

Why these choices?

Binding to 127.0.0.1 puts Grafana behind a reverse proxy, so only the proxy faces the internet. Setting root_url correctly matters more than people expect. Without it, password reset links, alert notification links, and OAuth redirects all point to the wrong address. cookie_secure = true stops session cookies travelling over plain HTTP. Turning off allow_sign_up means random visitors cannot create accounts.

Lines starting with ; are comments in this file. A setting that “does nothing” is often still commented out, so remove the leading semicolon.

Apply the changes:

sudo systemctl restart grafana-server
sudo journalctl -u grafana-server -n 50 --no-pager

Put Nginx in Front with HTTPS

Running Grafana directly on port 3000 over HTTP is fine for a test. For anything else, a reverse proxy gives you TLS, logging, rate limiting, and a clean URL.

sudo apt install -y nginx certbot python3-certbot-nginx

Create /etc/nginx/sites-available/grafana.conf:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name grafana.example.com;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:3000;
    }

    location /api/live/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:3000;
    }
}

The /api/live/ block handles WebSockets for Grafana Live. Skip it and you will see odd websocket errors in the browser console, plus streaming panels that never update.

Enable the site, test, and request a certificate:

sudo ln -s /etc/nginx/sites-available/grafana.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d grafana.example.com

Certbot rewrites the server block for HTTPS and sets up automatic renewal. Verify the renewal timer with a dry run:

sudo certbot renew --dry-run
systemctl list-timers | grep certbot

An expired certificate on a monitoring system is embarrassing. It usually fails silently until someone needs the dashboard during an incident.

Lock Down the Firewall

Ubuntu ships with UFW. Allow SSH first, or you will lock yourself out:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose

Do not open port 3000. With http_addr = 127.0.0.1, Grafana is not reachable from outside anyway, and the firewall provides a second layer. If monitoring traffic must come from specific networks, restrict by source address:

sudo ufw allow from 203.0.113.0/24 to any port 443 proto tcp

One more tip. Docker publishes ports by writing iptables rules that bypass UFW. If this host also runs containers, check with ss -tlnp and an external scan instead of trusting ufw status.

Connect a Data Source: Prometheus Example

Grafana does nothing on its own. It visualises data from somewhere else. Prometheus plus Node Exporter is the most common first pairing.

Install them from the Ubuntu archive:

sudo apt install -y prometheus prometheus-node-exporter
sudo systemctl enable --now prometheus prometheus-node-exporter

Confirm that Prometheus is up on port 9090 and Node Exporter on port 9100:

curl -s localhost:9090/-/ready
curl -s localhost:9100/metrics | head

The archive version of Prometheus may lag the upstream release. For production, many teams use the upstream binaries or a container image to get current features. For learning and small deployments, the packaged version is fine.

Add it through provisioning

Click-ops works, but a provisioned data source survives rebuilds. Create /etc/grafana/provisioning/datasources/prometheus.yaml:

apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://localhost:9090
    isDefault: true
    editable: false

Restart Grafana, then go to Connections, then Data sources, and confirm that the connection test passes. Import the community dashboard ID 1860 (Node Exporter Full) from the Dashboards, then New, then Import screen for an instant host overview.

Backups and Upgrades

Back up before every upgrade. With SQLite it is a short job:

sudo systemctl stop grafana-server
sudo cp -a /var/lib/grafana /var/lib/grafana.bak-$(date +%F)
sudo cp -a /etc/grafana /etc/grafana.bak-$(date +%F)
sudo systemctl start grafana-server

For a PostgreSQL backend, use pg_dump. Also keep dashboards in version control, either through provisioning or the API export.

Upgrading follows the normal route:

sudo apt update
sudo apt install --only-upgrade grafana

Pin or hold the package on critical systems if you want to control the timing:

sudo apt-mark hold grafana

Remember to unhold it later. Held packages quietly miss security fixes.

Troubleshooting Common Problems

Repository signature or expired key errors

The symptom is an apt update error mentioning EXPKEYSIG or “NO_PUBKEY”. Grafana extended the lifetime of its signing key in August 2025, and anyone who enabled the repository earlier saw errors until they fetched the new key. Re-download it:

sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
sudo chmod 644 /etc/apt/keyrings/grafana.asc
sudo apt update

Service fails to start

Always read the logs first:

sudo journalctl -xeu grafana-server --no-pager | tail -50
sudo tail -50 /var/log/grafana/grafana.log

Typical causes are an INI syntax error, a port already in use, or wrong permissions on /var/lib/grafana. Check the port with sudo ss -tlnp | grep 3000, and repair ownership with sudo chown -R grafana:grafana /var/lib/grafana /var/log/grafana.

502 Bad Gateway from Nginx

Grafana is probably not running, or is listening somewhere else. Test curl -I http://127.0.0.1:3000. If that works, check the Nginx error log at /var/log/nginx/error.log, and on RHEL systems check SELinux.

Login redirect loops or “origin not allowed”

This points to a root_url mismatch or a proxy that does not pass the Host header. Match root_url to the public URL exactly, scheme included, and keep proxy_set_header Host $http_host; in place.

“Database is locked”

SQLite is struggling with concurrent writes or slow disk. Check iostat -x 1 for high wait times. If it recurs under real load, migrate to PostgreSQL.

Data source test fails

“Connection refused” means the target is down or bound only to another interface. “Context deadline exceeded” suggests a firewall or a very slow backend. Test from the Grafana host itself with curl, because that is the network path Grafana uses.

Dashboards are slow

Open the panel’s Query Inspector and look at the actual query time. If the backend takes 8 seconds, no Grafana setting will rescue it. Narrow the time range, add label filters, and precompute heavy queries.

r00t is an experienced Linux enthusiast and technical writer with a passion for open-source software. With years of hands-on experience in various Linux distributions, r00t has developed a deep understanding of the Linux ecosystem and its powerful tools. He holds certifications in SCE and has contributed to several open-source projects. r00t is dedicated to sharing her knowledge and expertise through well-researched and informative articles, helping others navigate the world of Linux with confidence.

Related Posts