Journal indexDockup / field note
Note / self-host-grafana

How to Self-Host Grafana in 2026: Dashboards, Alerts and Persistent State

Deploy Grafana with the right port, durable storage, TLS, authentication and backups. Troubleshoot when dashboards vanish with the SQLite file in production.

There are two versions of “running Grafana”: a container exists, or the service completes its real job. Only the second matters. Here the proof is to add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point.

Grafana serves this purpose: dashboards and alerts over metrics, logs and traces. The deployment has to preserve the pieces behind that behavior; a port, a volume and a certificate are inputs, not the result.

The production shape of Grafana

The Grafana HTTP process listens on 3000; keep that port on the application network and publish only the platform route. The network contract for Grafana is reachable data sources and SMTP if alert delivery is required. Keep private endpoints on internal DNS, permit only required outbound calls and give Grafana a scoped service credential.

Write the boundary down as a short contract: who owns the requirement, which credential is used, what timeout is acceptable and how failure appears. Then run this transaction: add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point. Observe query fan-out, dashboard refresh intervals, alert evaluation and plugin memory rather than Grafana's own stored metrics during the run, because that workload gives a more useful starting size than an idle container.

Start Grafana without hiding the moving parts

Start Grafana in a way that leaves the route private until bootstrap is complete.

docker run -d \
  --name grafana \
  --restart unless-stopped \
  -p 127.0.0.1:3000:3000 \
  -v grafana-data:/var/lib/grafana \
  -e GF_SECURITY_ADMIN_PASSWORD=replace-with-a-long-random-value \
  grafana/grafana:latest

If the process loops, compare the image's expected user with the owner of each mounted path. If it stays up, test port 3000 locally and then move directly to the workflow: add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point. Version-pin the image only after that end-to-end check passes, and record the exact configuration beside the service.

Give Grafana one canonical address

TLS issuance is only half of the Grafana route. Set GF_SERVER_ROOT_URL to the public HTTPS URL. Send traffic internally to 3000 and forward the external scheme so generated URLs and secure cookies remain consistent.

Use the complete Grafana scenario from a clean network, not merely the root page. A 502 or certificate failure can be isolated with automatic domain and TLS setup. If traffic reaches the process and dashboards vanish with the SQLite file or OAuth callbacks use localhost, diagnose that condition where it occurs instead of stacking redirects.

Design the Grafana restore before launch

The durable recovery set is the Grafana database, plugins and provisioned configuration. Mount /var/lib/grafana before bootstrap, write harmless sample data and replace the container to prove that path is actually persistent. A volume protects data from container replacement, but not from host loss, accidental deletion or application-level corruption.

Take backups that understand the data source: use logical dumps for live databases when required and copy files only from a consistent state. Keep one encrypted copy away from the Grafana host. The acceptance criterion for a restore is specific — users, folders, dashboards, alert rules and data-source metadata return and the test alert evaluates. The restore-tested backup guide explains why job success alone is insufficient.

Close temporary setup access

A secure Grafana deployment starts by removing authority. Avoid keeping admin/admin or exposing anonymous access unintentionally; instead, replace the bootstrap admin password, restrict data-source editing and keep service-account tokens scoped.

Replace the sample GF_SECURITY_ADMIN_PASSWORD immediately, store it outside the image and rotate it like an administrator credential if it is exposed. Restrict administrative routes, use private DNS for dependencies and review every bind mount. When logs are shipped centrally, filter secrets and private content before they leave the server.

Rehearse the risky Grafana change

A green container is necessary but not sufficient. The service-level indicator is successful completion of “add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point”, while the likely pressure signals are query fan-out, dashboard refresh intervals, alert evaluation and plugin memory rather than Grafana's own stored metrics.

Change control matters because Grafana database migrations and plugin compatibility require a staged upgrade with the same provisioning files. Preserve the old image, test migrations on copied state and document whether rollback is supported after the schema moves. If dashboards vanish with the SQLite file or OAuth callbacks use localhost, diagnose the first boundary that differs from the working environment.

Record a known-good Grafana deployment

For Grafana, define a known-good transaction before launch: add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point. Put its prerequisites, expected response and cleanup steps in version control without secret values. Pin the image used to establish that reference.

Use the transaction to validate a replacement and an independent restore. The restored service is acceptable only when users, folders, dashboards, alert rules and data-source metadata return and the test alert evaluates. At the same time, observe query fan-out, dashboard refresh intervals, alert evaluation and plugin memory rather than Grafana's own stored metrics and turn the slowest or most constrained part into a service-level alert.

The gate also needs a negative case: temporarily deny the test identity access to reachable data sources and SMTP if alert delivery is required. Confirm that Grafana produces an actionable error while preserving data, restore the valid condition and repeat the known-good transaction. Keeping both results prevents a superficial health endpoint from becoming the only production evidence.

Where Dockup removes work for Grafana

Routing, certificates, service replacement and attached storage are reasonable automation targets. Dockup handles those for Grafana and can provision the related managed database or connect to services on a customer's own server.

What it should not invent is the Grafana trust policy. After deployment, set GF_SERVER_ROOT_URL to the public HTTPS URL, enforce this boundary — replace the bootstrap admin password, restrict data-source editing and keep service-account tokens scoped — and verify the result of this scenario: add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point. The outcome is one-click infrastructure with an application-specific acceptance test.

Frequently asked questions

What does Grafana need for a production deployment?

Route the Grafana container on port 3000 through one HTTPS origin. The supporting network requirement is reachable data sources and SMTP if alert delivery is required. Do not call Grafana ready until you can add a read-only data source, save a panel, evaluate an alert rule and deliver a test notification through a contact point.

Which Grafana data belongs in a backup?

Persist /var/lib/grafana and include the Grafana database, plugins and provisioned configuration in the same recovery manifest. A clean Grafana restore passes only when users, folders, dashboards, alert rules and data-source metadata return and the test alert evaluates.

Does Grafana require HTTPS behind a reverse proxy?

Use HTTPS for the public Grafana origin and keep port 3000 on the internal route. Apply the Grafana setting correctly: set GF_SERVER_ROOT_URL to the public HTTPS URL. For Grafana, HTTPS protects credentials or user content in transit and keeps origin-sensitive client behavior consistent.

How should a Grafana upgrade be tested?

Restore current Grafana state into an isolated deployment, apply the candidate version and repeat its acceptance transaction. Pay particular attention because Grafana database migrations and plugin compatibility require a staged upgrade with the same provisioning files. Keep the previous Grafana image until its data-migration and rollback boundary are understood.