Deploy Grafana

Self-hosted Grafana dashboards & alerts for Prometheus, Loki, InfluxDB, SQL

Deploy Grafana

Grafana for railway.app

Template Header

Deploy Grafana Community Edition on railway with one click. Grafana is a multi-platform, feature rich metrics dashboard and graph editor for Graphite, InfluxDB & Prometheus. It is most commonly used for visualizing time series data.

Deploy on Railway

✨ Features

  • Grafana with automated setup
  • Grafana UI
  • Password Authentication (Set username & password in environment variables)
  • Railway config as code via railway.toml

🏗️ Architecture

flowchart LR
    Client(["🌐 Client"]) -->|HTTPS| Domain["Railway Public Domain"]
    Domain -->|"$PORT → GF_SERVER_HTTP_PORT"| App["Container\ngrafana/grafana-oss"]
    App --> Volume[("Volume\n/var/lib/grafana")]

Production recommendations (Railway)

  • Set strong GF_SECURITY_ADMIN_PASSWORD in Railway Variables
  • Persist /var/lib/grafana with a Railway volume
  • Keep healthcheck path at /api/health
  • Restrict plugin list in GF_PLUGINS_PREINSTALL to required plugins only

📏 Resource requirements

Measured on a fresh deploy of Grafana 13.0.2:

  • RAM: ~0.3 GB peak on first boot, ~0.27 GB idle
  • Volume: ~0.25 GB right after first boot; grows with dashboards, alert state and plugin updates. Plan for ≥ 0.5 GB
  • Plan: Hobby or higher recommended. Free and Trial cap RAM (0.5 GB / 1 GB) and volumes (0.5 GB); a full volume or memory spike crashes Grafana

📜 Logging

The first boot runs ~700 database migrations. The image sets GF_LOG_FILTERS=migrator:warn so they don't trip Railway's log rate limit; warnings and errors stay visible. Override it in Railway Variables, e.g. GF_LOG_FILTERS=migrator:info for full migration logs.

💾 Volume permissions

Railway mounts volumes as root:root, while the upstream Grafana image runs as UID 472. A plain grafana/grafana-oss deployment therefore fails on first boot with:

mkdir: can't create directory '/var/lib/grafana/plugins': Permission denied
GF_PATHS_DATA='/var/lib/grafana' is not writable.

This template handles it in docker-entrypoint.sh: the container starts as root, takes ownership of the mount, and then execs into UID 472. Since it is an exec rather than a fork, no root process survives into runtime — the Grafana process itself stays unprivileged.

You do not need RAILWAY_RUN_UID=0, which would keep Grafana running as root. The recursive chown only runs while the mount root is misowned, i.e. once after attaching a volume.

🖼️ Image rendering (grafana-image-renderer)

Adding grafana-image-renderer to GF_PLUGINS_PREINSTALL does not work on the default image and fails at startup with exit status 127:

Error: ✗ *rendering.RenderingService run error: Unrecognized remote plugin message

The plugin binary is linked against glibc, while grafana/grafana-oss is Alpine-based and ships musl. Grafana closed the corresponding upstream report (grafana-image-renderer#475) as not planned, so there is no fix to wait for. Two options work:

OptionHowTrade-off
Ubuntu image variantSet VERSION=13.0.2-ubuntu (matching the pinned version) (build arg / Railway variable)glibc-compatible, single service — but a noticeably larger image and rendering competes with Grafana for the same CPU/memory
Separate renderer serviceDeploy grafana/grafana-image-renderer as its own Railway service, then point Grafana at it via GF_RENDERING_SERVER_URL=http://SERVICE_NAME:8081/render and GF_RENDERING_CALLBACK_URL=http://GRAFANA_SERVICE_NAME:3000/Scales independently and keeps Chromium out of the Grafana container — but a second service to run and pay for

For anything beyond occasional PDF or panel exports, the separate service is the better fit: rendering is CPU- and memory-spiky, and isolating it keeps those spikes away from the dashboards themselves.

🐍 How to Deploy

  1. Click Deploy on Railway and setup your credentials in the environment variables
GF_DEFAULT_INSTANCE_NAME=my-instance
GF_SECURITY_ADMIN_USER=yourusername
GF_SECURITY_ADMIN_PASSWORD=yourpassword
GF_PLUGINS_PREINSTALL=grafana-clock-panel
GF_LOG_MODE=console
PORT=3000
  1. Wait for Build & Deployment to Finish
  2. Open the custom URL an enter your credentials

👩‍💻 How to Use

  1. Log in with GF_SECURITY_ADMIN_USER / GF_SECURITY_ADMIN_PASSWORD
  2. Add a data source (Prometheus, Loki, InfluxDB, PostgreSQL, …) via its Railway private domain
  3. Build dashboards and alerts; everything is persisted on the volume

🪲 Bug Reporting

If you find a bug in the template for railway, you can submit an issue to the GitHub Repository. Even better you can submit a Pull Request with a fix.

🐳 Local Development

docker compose build
docker compose up -d

Connect to http://localhost:3000 use setup username & password from docker-compose file to login to grafana.

💬 Support

Questions or feedback? Visit the template forum on Railway Central Station.


Airbyte Apache Airflow CloudBeaver CodiMD Django Email Service FastAPI Flask Flowise GitLab CE Grafana Home Assistant InfluxDB MJML MongoDB Mosquitto MQTT MySQL n8n Node.js Node-RED OpenSearch Open WebUI Operately Outerbase Studio PostgreSQL Redis TYPO3 CMS


Template Content

More templates in this category

View Template
Rootprint
Open-source logs and traces with full-text search on object-storage.

Rootprint
1
View Template
VPS Fleet Watch Hub with Beszel
A persistent Beszel hub for external VPS agents and fleet alerts.

dankeewithtwoes
0
View Template
Pyroscope profiling
Protected continuous profiling with durable Pyroscope storage.

Anton Orel
1