Graphite and Graphite Web on Debian – Part 1

graphiteTo complement our Icinga configuration, I’m installing Graphite and Graphite web on my Icinga master. Find out more here and of course here. Basically we’re going to visualise our Icinga checks.

It’s not the easiest thing I’ve done so far, mainly because a few concepts were new to me. For instance: it works with a time-series database and a webserver called gunicorn, both I do not know.

But with a little patience and a lot of searching online, I can present to you this 2 part series how to set everything up.

Graphite (and Django, see later on) need a database to store it’s tables and by default this is SQLite. This is the first thing we’re going to change to MySQL so let’s create a database.

# mysql
> CREATE DATABASE graphitedb;
> CREATE USER 'graphuser'@'localhost' IDENTIFIED BY 'yourstrongpass';
> GRANT ALL ON graphitedb.* TO 'graphuser'@'localhost';
> flush privileges;
> exit;

Next we need to install various python software and then with ‘pip’ install the rest.

# apt install python-dev python-pip libcairo2-dev libffi-dev build-essential
# pip install --no-binary=:all:
# pip install --no-binary=:all:
# pip install --no-binary=:all:

For our database connection:

# apt install python3-mysqldb libmysqlclient-dev
# pip install mysql-python

We’re creating our first config file by copying the example and editing a few things.

# cd /opt/graphite/webapp/graphite
# cp
# vi

Find the following sections, comment them out and edit them like below (of course filling in the blanks):

SECRET_KEY = 'createyoursecretkeyandinsertithere'
TIME_ZONE = 'Your timezone'
DASHBOARD_REQUIRE_EDIT_GROUP = 'dashboard-editors-group'
'default': {
'NAME': 'graphite',
'ENGINE': 'django.db.backends.mysql',
'USER': 'graphuser',
'PASSWORD': 'insertyourpass',
'HOST': 'localhost',
'PORT': '3306'

Import the database schema, this should produce no errors:

# cd /opt/graphite/webapp
# migrate --settings=graphite.settings --run-syncdb

For serving the webapp there are a couple of options, but we will be using Nginx and Gunicorn.

Setting it up was certainly not as transparent as some of the rest of the documentation. The gist of it, is that Nginx functions as a proxy and Gunicorn has to be running and be serving the webapp.

Create the logfiles:

# touch /var/log/nginx/graphite.access.log
# touch /var/log/nginx/graphite.error.log
# chmod 640 /var/log/nginx/graphite.*
# chown www-data:www-data /var/log/nginx/graphite.*

Create the Nginx conf:

# vi /etc/nginx/sites-available/

The config file:

upstream graphite {
server fail_timeout=0;

[ YOUR server blocks, SSL configuration, Security headers and OCSP stapling ]

location = /favicon.ico {
return 204;

# serve static content from the "content" directory
location /static {
alias /opt/graphite/webapp/content;
expires max;

location / {
try_files $uri @graphite;

location @graphite {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://graphite;

Get the config active:

# ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
# nginx -t
# systemctl restart nginx

This will give a “502 Bad Gateway” error though when surfing to This is because Gunicorn is not running and serving anything. Next post we’l finish this.

Complete series: Intro, LEMP preparation, Installation, Clients part 1, Clients part 2, Third Party Plugins part 1, Third Party Plugins part 2, Schedule downtime, Telegram push part 1, Telegram push part 2, Graphite part 1 and Graphite part 2.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.