Fedora’s Grafana package ships an SELinux policy that blocks the first thing you will do with it, connecting to Prometheus. On Fedora 45 the data source test failed with “connect: permission denied”, nothing showed up in the audit log, and the fix was a single boolean that is off by default. The same policy also keeps Nginx from reaching Grafana until you flip a second, purpose-built boolean, and on Fedora Server, Prometheus cannot even start until you move or disable Cockpit.
You’ll install Grafana from Fedora’s packages, lock down the default admin account, wire it to Prometheus and node-exporter from the same repositories, put it behind Nginx with HTTPS and import a real dashboard. Fedora 44 ships a much older Grafana, so on that release you’ll use the Grafana Labs repository instead. Everything ran on Fedora 45 in October 2026, with the Grafana Labs repository and the upgrade from Fedora’s build tested on Fedora 44.

That is the finished layout on our VM. Only Nginx is reachable from the network, Grafana and Prometheus stay on the host, and each arrow is a connection SELinux blocks until you turn on the boolean named in the box it starts from or ends at.
Choose Fedora’s package or Grafana’s repository
Fedora packages Grafana itself, and how far it trails upstream depends on the release you run. The table shows what each source installed on our machines, and the SELinux row matters as much as the version.
| Fedora 45 repo | Fedora 44 repo | Grafana Labs repo | |
|---|---|---|---|
| Version | 12.4.3 | 10.2.6 | 13.2.4 |
| SELinux domain | grafana_t (via grafana-selinux) | not checked | unconfined_service_t unless you add grafana-selinux |
| RPM licence field | AGPL-3.0-only | not checked | AGPLv3 |
Size of the grafana package | 944 MiB | 485 MiB | 1.3 GiB |
On Fedora 45 we would take Fedora’s package, because it comes with SELinux confinement and installs from the same repositories as the rest of the system. Know what you are trading for that: the 12.4 branch upstream had reached 12.4.13 by mid-October, ten patch releases past Fedora’s 12.4.3, and Grafana ships security fixes on that branch. Fedora sometimes backports fixes without changing the version, but if you run Grafana on the internet, check the Fedora package’s changelog against Grafana’s security advisories, or use Grafana’s repository. On Fedora 44, 10.2.6 is long out of upstream support, so use Grafana’s repository there, and add Fedora’s grafana-selinux package on top.
Install Grafana on Fedora
On Fedora 44, set up Grafana’s repository first, as described in the last section, and then carry on here. On Fedora 45 one package does it. It pulls in the SELinux policy module as a hard dependency and the Performance Co-Pilot plugin as a weak one:
sudo dnf install -y grafana
You’ll see four packages in the transaction. grafana-pcp is optional, and if you don’t run Performance Co-Pilot you can leave it out with --setopt=install_weak_deps=False, but keep grafana-selinux, because it is what confines the service.
Installing:
grafana x86_64 0:12.4.3-3.fc45 fedora 944.0 MiB
Installing dependencies:
grafana-selinux noarch 0:12.4.3-3.fc45 fedora 15.4 KiB
shared-mime-info x86_64 0:2.5.1-3.fc45 fedora 6.6 MiB
Installing weak dependencies:
grafana-pcp x86_64 0:6.0.1-2.fc45 fedora 41.4 MiB
Start it and ask the health endpoint for the version. The service is still called grafana-server, even though the binary now prints a deprecation notice for that name:
sudo systemctl enable --now grafana-server
curl -s http://localhost:3000/api/health
A healthy instance reports "database": "ok" and its version. If you get connection refused instead, give it a few more seconds, because the first start runs several hundred database migrations (our log showed 710).
{
"database": "ok",
"version": "12.4.3",
"commit": "NA"
}
ps -eZ | grep grafana showed it running as grafana_t, the confined domain from grafana-selinux. Out of the package it listens on port 3000 on every interface, which the Nginx section below changes to loopback only. Until then, keep 3000 closed in the firewall.
Change the default admin password
A fresh install accepts admin / admin, and not only in the browser: curl -u admin:admin http://localhost:3000/api/org returned 200. The login page asks you to change it on first sign-in, but with a Skip button right under the form, and the API accepts the default until somebody does, so change it from the shell before the port is reachable from anywhere. The obvious grafana cli command has a trap, so don’t run this one; it is shown only so you recognise it:
sudo grafana cli --homepath /usr/share/grafana --config /etc/grafana/grafana.ini admin reset-admin-password 'use-a-long-random-password'
It reports success:
Admin password changed successfully ✔
Yet admin / admin still worked afterwards. The CLI had created a new, root-owned database in /usr/share/grafana/data and changed the password there, because the systemd unit passes the real data path, /var/lib/grafana, as a command-line override that the CLI never sees. Fedora’s unit and Grafana’s own both do this, so the trap is the same on either package. Give the CLI the same override and run it as the grafana user:
sudo -u grafana grafana cli --homepath /usr/share/grafana --config /etc/grafana/grafana.ini --configOverrides cfg:default.paths.data=/var/lib/grafana admin reset-admin-password 'use-a-long-random-password'
After this, admin:admin got a 401 and the new password a 200, so the change reached the database the service actually uses. The password now sits in your shell history, so clear that line with history -d, and keep the password in a password manager, because without SMTP configured for the “Forgot your password?” link, this CLI is the way back in. If you ran the plain command first, delete the stray copy with sudo rm -rf /usr/share/grafana/data; the service never reads it.
Connect Grafana to Prometheus
Fedora packages both Prometheus and node-exporter, and the packaged /etc/prometheus/prometheus.yml already scrapes node-exporter on port 9100, so there is nothing to edit on that side. On Fedora Server, check port 9090 first, because Cockpit listens there by default. No output means 9090 is free, and you can skip to the install below.
sudo ss -ltnp | grep 9090
Error: “listen tcp 0.0.0.0:9090: bind: address already in use”
If systemd owns 9090, that’s cockpit.socket, and Prometheus will fail to start. We enabled Cockpit on our VM to reproduce it, and the Prometheus journal filled with this line while the service ended up failed:
time=2026-10-15T20:15:53.298Z level=ERROR source=main.go:1259 msg="Unable to start web listener" err="listen tcp 0.0.0.0:9090: bind: address already in use"
If you don’t use Cockpit, sudo systemctl disable --now cockpit.socket ends the clash. To keep it, move Cockpit rather than Prometheus. Port 9090 carries the websm_port_t SELinux label, which the Grafana policy knows about, so leaving Prometheus there saves you labelling work on the Grafana side. Move Cockpit with a socket drop-in:
sudo mkdir -p /etc/systemd/system/cockpit.socket.d
sudo vim /etc/systemd/system/cockpit.socket.d/listen.conf
The empty ListenStream= clears the packaged port before the new one is added:
[Socket]
ListenStream=
ListenStream=9091
Port 9091 had no SELinux label on our box, so give it Cockpit’s, then reload systemd and restart the socket. 9091 is also the default port of the Prometheus Pushgateway, so pick another free port if you plan to run that.
sudo semanage port -a -t websm_port_t -p tcp 9091
sudo systemctl daemon-reload
sudo systemctl restart cockpit.socket
In our test Prometheus then held 9090 and Cockpit answered on 9091. Whichever option you chose, disable or move, the firewall needs a change too. Fedora Server’s FedoraServer zone allows the cockpit service, and that service is defined as 9090/tcp, so once Prometheus owns 9090 it would be open to the network without authentication. Remove the service, and open 9091 only if you reach Cockpit remotely:
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --permanent --add-port=9091/tcp
sudo firewall-cmd --reload
We switched our VM to the FedoraServer zone to check this, and after these commands, plus the HTTP and HTTPS services the Nginx section adds, firewall-cmd --list-services showed dhcpv6-client http https ssh with 9091 as the only extra port. Fedora Workstation’s default zone is different: it allows ports 1025 to 65535, so close 9090 and 9100 explicitly there. With 9090 free, install and start the monitoring pair:
sudo dnf install -y prometheus node-exporter
sudo systemctl enable --now prometheus prometheus-node-exporter
Prometheus 3.15.0 and node-exporter 1.12.1 came from the Fedora 45 repositories, and within 12 seconds the Prometheus targets API reported both the node and prometheus jobs as up. Both listen on every interface without authentication, so leave 9090 and 9100 closed in firewalld; Grafana reaches them on localhost. Add the data source as a provisioning file rather than through the UI, so it survives a database reset and lives in version control:
sudo vim /etc/grafana/provisioning/datasources/prometheus.yaml
This is the file we provisioned. access: proxy means the Grafana server makes the query, not your browser, which is why the SELinux rules below matter.
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://localhost:9090
isDefault: true
Grafana reads the file as the grafana user, so give that group read access and restart the service.
sudo chown root:grafana /etc/grafana/provisioning/datasources/prometheus.yaml
sudo chmod 640 /etc/grafana/provisioning/datasources/prometheus.yaml
sudo systemctl restart grafana-server
Error: “dial tcp [::1]:9090: connect: permission denied”
Grafana logged inserting datasource from configuration, so the file was fine. The data source health check still failed, and the error looks like a firewall problem even though no firewall was involved:
{"message":"Post \"http://localhost:9090/api/v1/query\": dial tcp [::1]:9090: connect: permission denied - There was an error returned querying the Prometheus API.","status":"ERROR"}
The Grafana policy only lets grafana_t connect to websm_port_t when a boolean says so. ausearch found no AVC for it, so the usual “check the audit log” approach gets you nowhere. List the policy’s booleans:
getsebool -a | grep -i grafana
All six are off by default, on Fedora 44’s policy as well as 45’s. Five open one kind of backend port to Grafana, and grafana_can_reverse_proxy works the other way round, letting a web server reach Grafana, which the Nginx section needs.
grafana_can_reverse_proxy --> off
grafana_can_tcp_connect_elasticsearch_port --> off
grafana_can_tcp_connect_ldap_port --> off
grafana_can_tcp_connect_mysql_port --> off
grafana_can_tcp_connect_postgresql_port --> off
grafana_can_tcp_connect_prometheus_port --> off
Turn on the Prometheus one. If you later add MySQL, PostgreSQL, Elasticsearch or LDAP, flip the matching boolean then. The policy already allows standard HTTP ports, so data sources served there need none of them:
sudo setsebool -P grafana_can_tcp_connect_prometheus_port 1
The same health check then answered "Successfully queried the Prometheus API.". The same Prometheus can scrape other services too; our guide to monitoring Valkey with Prometheus and Grafana builds on this setup, and pairs with our Redis and Valkey guide for Fedora.
Put Grafana behind Nginx with HTTPS
Grafana’s built-in HTTP listener is fine on a laptop. On a server, terminate TLS in Nginx and keep Grafana on loopback, which also gives you a safe way into the web UI for the rest of the setup. You need three settings in the [server] section, all commented out in the packaged file, and each fixes a different proxy problem:
http_addrkeeps port 3000 off the networkdomainis the name users typeroot_urlmakes links and redirects use HTTPS
Open the main config file to set them.
sudo vim /etc/grafana/grafana.ini
Uncomment and set them, using your own name.
http_addr = 127.0.0.1
domain = grafana.example.com
root_url = https://grafana.example.com/
Without root_url, Grafana builds links from http://localhost:3000/, which is what /api/frontend/settings reported as appUrl before the change. Afterwards it reported https://grafana.example.com/, and ss -ltn showed port 3000 on 127.0.0.1 only. Restart Grafana, install Nginx and put a certificate in place. Our lab had no public DNS name, so we used a self-signed one at the paths the server block expects; certbot replaces those two lines later:
sudo systemctl restart grafana-server
sudo dnf install -y nginx
sudo openssl req -x509 -nodes -newkey rsa:2048 -days 30 -subj "/CN=grafana.example.com" -keyout /etc/pki/tls/private/grafana.key -out /etc/pki/tls/certs/grafana.crt
Nginx on Fedora reads every file in /etc/nginx/conf.d/, so the proxy gets its own file.
sudo vim /etc/nginx/conf.d/grafana.conf
Grafana Live, which pushes dashboard updates to the browser, runs over WebSockets at /api/live/, so that location gets the upgrade headers. This is the file from our VM.
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
server {
listen 80;
listen [::]:80;
server_name grafana.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name grafana.example.com;
ssl_certificate /etc/pki/tls/certs/grafana.crt;
ssl_certificate_key /etc/pki/tls/private/grafana.key;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
}
location /api/live/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
}
Start Nginx:
sudo systemctl enable --now nginx
The first request returns a 502, and the Nginx error log shows connect() to 127.0.0.1:3000 failed (13: Permission denied). Port 3000 is grafana_port_t, and here the usual reverse-proxy boolean, httpd_can_network_relay, made no difference in our test. httpd_can_network_connect fixed it but lets Nginx connect to any port. The Grafana policy has its own boolean for exactly this case, and it alone took the request from 502 to 200:
sudo setsebool -P grafana_can_reverse_proxy 1
Open HTTP and HTTPS in firewalld and leave 3000 closed, since Grafana now listens on loopback and only Nginx needs to reach it. Fedora Server runs firewalld by default. Our cloud image did not, so we installed and enabled it first with sudo dnf install -y firewalld and sudo systemctl enable --now firewalld; its default zone keeps SSH open, so your session survives.
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
For a real certificate, point a public DNS name at the server and let certbot’s Nginx plugin replace the self-signed lines. On Fedora the plugin needs python3-pyparsing as well, a missing dependency our Django on Fedora guide ran into on both releases, and the renewal timer has to be started once. We kept the self-signed certificate in this lab, so these three lines come from that guide, not from this one:
sudo dnf install -y certbot python3-certbot-nginx python3-pyparsing
sudo certbot --nginx -d grafana.example.com
sudo systemctl enable --now certbot-renew.timer
Browse to your HTTPS name and sign in with the password you set earlier. This is the login page through the proxy:

The same loopback-backend pattern, with the SELinux side of it on Rocky Linux, is in our Tomcat behind Nginx guide.
Import a Node Exporter dashboard
With the UI reachable over HTTPS, check the data source once in the browser. Under Connections, then Data sources, open Prometheus and click Test at the bottom of the page:

For a dashboard to look at, import the community Node Exporter Full board. Open Dashboards, then New, then Import, type 1860 into the Grafana.com field and click Load:

The current revision picks the data source through a dashboard variable, so the import page asks for nothing more than Import. A few minutes after node-exporter started, the board showed our VM’s CPU, memory, network and disk:

Short time ranges read best while Prometheus has only minutes of history. We used the last 15 minutes here, and the 24-hour view stays mostly empty until a day of data has built up.
Use Grafana’s repository on Fedora 44
Fedora 44 packages Grafana 10.2.6, and the 10.x line is long out of upstream support. Grafana Labs publishes its own RPM repository, so import its key and add the repository file from the Grafana install docs:
curl -s -o gpg.key https://rpm.grafana.com/gpg.key
sudo rpm --import gpg.key
sudo vim /etc/yum.repos.d/grafana.repo
Paste the definition from Grafana’s docs. It has no sslcacert line, so it does not hit the missing CA bundle path that breaks some vendor repository files on Fedora 44 and 45.
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
sslverify=1
Both repositories now offer a package called grafana, and on a box without Grafana, sudo dnf install -y grafana picks the higher version from Grafana’s repository. If Fedora’s 10.2.6 is already installed, that command only answers Package "grafana-10.2.6-24.fc44.x86_64" is already installed. and does nothing, so the switch needs an upgrade instead.
Before you switch a Grafana that holds real dashboards, stop the service and back up /etc/grafana and /var/lib/grafana (the SQLite database and plugins), as Grafana’s upgrade guide advises, because the new version migrates the database on its first start. Plan for the jump too: Grafana 12 removed AngularJS support, so panels and data source plugins from the 10.x era that still use Angular stop working after the upgrade, and you’ll need their current versions or replacements. Then run the upgrade:
sudo dnf upgrade -y grafana
dnf replaced Fedora’s build with the one from Grafana’s repository:
Upgrading:
grafana x86_64 0:13.2.4-1 grafana 1.3 GiB
replacing grafana x86_64 0:10.2.6-24.fc44 fedora 485.4 MiB
The upstream package ran as unconfined_service_t, because it ships no SELinux policy. Fedora’s grafana-selinux installs on its own, so add it and restart. After the restart the binaries carried grafana_exec_t, the process ran as grafana_t, and the health endpoint answered 200:
sudo dnf install -y grafana-selinux
sudo systemctl restart grafana-server
From then on the same six booleans apply as on Fedora 45, so set the Prometheus and reverse-proxy ones as you reach those steps. We only checked that this combination starts and serves the API. A policy written for 10.2.6 may not cover every feature of 13, so watch journalctl -u grafana-server for permission errors when you add plugins. The Grafana guide for Ubuntu 26.04 covers the same upstream repository on Debian-family systems.