• Home
  • Django
  • Install self hosted Sentry on a Digitalocean droplet

Install self hosted Sentry on a Digitalocean droplet

Sentry is an Open-source error tracking that helps you monitor and fix crashes in real time. Imagine that you have a django installation on a production system. On a development server, you can see in real time the errors and output as it happens. However on a production system, the only normal way to see logs is to ssh into the server and read the log file. However if the program gave an error to a customer, you’re left relying on the customer to report it, which is a very bad idea. With Sentry, errors are reported instantly by email, with a link to the full stack trace online.

You could use the non-hosted version of Sentry from Sentry.io, but you’re sending your code to a third party with no idea how they are going to use it. Plus, there are limitations on the free account. Host the open source sentry software yourself, and these problems go away.

Requirements:
The cheapest droplet of Digitalocean (I used the $5, 1GB RAM droplet).

Note that this may need temporary upgrading to one with more RAM and CPU when you install plugins. Digitalocean is a cloud VPS service. You can create a VPS and boot it in less than a minute. You can even resize your VPS temporarily, which is very useful if you’re doing this for Sentry, which requires more resources during migrations and plugin installs.

If you join Digitalocean today by clicking this link, you get $100 credits to try it out!

Boot up the new Ubuntu instance
Prepare the environment, install a virtual environment, and install sentry module:

apt update 
apt upgrade -y
apt install python-setuptools python-dev libxslt1-dev gcc libffi-dev libjpeg-dev libxml2-dev libxslt-dev libyaml-dev libpq-dev
apt install python-pip
pip install -U virtualenv
virtualenv /www/sentry/
source /www/sentry/bin/activate
pip install -U sentry
sentry init /etc/sentry
nano /etc/sentry/sentry.conf.py

Now create the database:

sudo su - postgres
$ psql -d template1 -U postgres
psql (9.5.12)
Type "help" for help.
template1=# create extension citext;
CREATE EXTENSION
template1=# \q

And then:

$ createdb sentrydb
$ createuser sentry --pwprompt
$ psql -d template1 -U postgres
psql (9.5.12)
Type "help" for help.
template1=# GRANT ALL PRIVILEGES ON DATABASE sentrydb to sentry;
GRANT
template1=# ALTER USER sentry WITH SUPERUSER;
ALTER ROLE
template1=# \q
exit

Edit and modify the DATABASES section of /etc/sentry/sentry.conf.py giving the same details you used earlier:

DATABASES = {
    'default': {
        'ENGINE': 'sentry.db.postgres',
        'NAME': 'sentrydb',
        'USER': 'sentry',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '',
        'AUTOCOMMIT': True,
        'ATOMIC_REQUESTS': False,
    }
}

Edit the Mail Server section in /etc/sentry/config.yml
As an example of using mailgun:

###############
# Mail Server #
###############
mail.backend: 'smtp'  # Use dummy if you want to disable email entirely
mail.host: 'smtp.mailgun.org'
mail.port: 25
mail.username: '[email protected]'
mail.password: 'pass545454-878676f-3cvkhkhk'
# mail.use-tls: false
# The email address to send on behalf of
mail.from: '[email protected]'

Initialize the database by running the upgrade function:

SENTRY_CONF=/etc/sentry sentry upgrade

If this command didnt create a superuser, create it now:

SENTRY_CONF=/etc/sentry sentry createuser

Start the webserver:

SENTRY_CONF=/etc/sentry sentry run web

At this point, sentry is supposed to be available at http://localhost:9000
Unfortunately since I’m doing this over ssh, I cant check over a local browser.

Since I’m interested in accessing Sentry logs over a remote connection over a dedicated IP, I need to setup a reverse proxy over nginx. Note that of apache or any other webserver is already occupying port 80, this cannot work. So you need to remove apache2 server:

apt remove apache2 --purge
killall apache2

If that fails to clear port 80 (you can check with netstat -lpn, you should reboot your droplet.

Now, install nginx:

apt install nginx-full

The important lines are given below. You can comment or delete others:

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	server_name sentry.local;

	location / {
		proxy_pass         http://localhost:9000;
		proxy_redirect     off;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
	}
}
server {
	listen 80 ;
	listen [::]:80 ;
    server_name sentry.domain.com; 
	location / {
		proxy_pass         http://localhost:9000;
		proxy_redirect     off;

	        proxy_set_header   Host              $host;
	        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
	        proxy_set_header   X-Forwarded-Proto $scheme;
	}
}

Now you can restart nginx and test that you can access sentry at http://yourdomain.com

service nginx restart

You need to configure supervisor or systemd to start required processes every time machine is rebooted.
If using supervisor:
Create a file /etc/supervisor/conf.d/sentry.conf:

[program:sentry-web]
directory=/www/sentry/
environment=SENTRY_CONF="/etc/sentry"
command=/www/sentry/bin/sentry run web
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=syslog
stderr_logfile=syslog

[program:sentry-worker]
directory=/www/sentry/
environment=SENTRY_CONF="/etc/sentry"
command="C_FORCE_ROOT=yes /www/sentry/bin/sentry run worker"
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=syslog
stderr_logfile=syslog

[program:sentry-cron]
directory=/www/sentry/
environment=SENTRY_CONF="/etc/sentry"
command=/www/sentry/bin/sentry run cron
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=syslog
stderr_logfile=syslog

The C_FORCE_ROOT is definitely not recommended! You can remove that from your file.

Reload supervisor:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all

If using systemd, check these instructions.

Using SSL for Sentry:
Change your nginx configuration after installing SSL certificates:

server {
	listen 80;
	server_name sentry.yoursite.com;

	location / {
      if ($request_method = GET) {
        rewrite  ^ https://$host$request_uri? permanent;
      }
      return 405;
	}
}
server {
	listen 443 ssl default_server;
	listen [::]:443 ssl default_server;
    server_name sentry.yoursite.com;
    proxy_set_header   Host              $http_host;
    proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
	proxy_redirect     off;

	location / {
		proxy_pass         http://localhost:9000;
        add_header Strict-Transport-Security "max-age=31536000";
	}    
    ssl_certificate /etc/letsencrypt/live/sentry.yoursite.com/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/sentry.yoursite.com/privkey.pem; 
    include /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
}

Restart nginx:

service nginx restart

Installing certificates from letsencrypt:
Letsencrypt provides free domain validation SSL certificates. The nginx based method of generation of certificates may work for you. It didnt for me. So I used DNS based generation of certificates which requires that you add a TXT record to your domain’s DNS records:

apt install certbot
certbot -d mydomain.com --manual --preferred-challenges dns certonly

Resources:

  1. Sentry doku
  2. Scaleway blog

Issues:
No messages are being sent
If worker fails to start, messages will not be sent. If this happens, check if worker has started. If it hasnt, manually start it:

source /www/sentry/bin/activate
C_FORCE_ROOT=yes SENTRY_CONF=/etc/sentry sentry run worker &

Additional changes needed for SSL:

Changes needed to settings.py:

import os
import raven
RAVEN_CONFIG = {
    'dsn': 'https://a675656:[email protected]/2?verify_ssl=0',
    'release': raven.fetch_git_sha(os.path.dirname(os.pardir)),
}
import logging.config
import os
from django.utils.log import DEFAULT_LOGGING

# Disable Django's logging setup
LOGGING_CONFIG = None

LOGLEVEL = os.environ.get('LOGLEVEL', 'info').upper()

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'root': {
        'level': 'WARNING',
        'handlers': ['sentry'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s  %(asctime)s  %(module)s '
                      '%(process)d  %(thread)d  %(message)s'
        },
    },
    'handlers': {
        'sentry': {
            'level': 'INFO', # To capture more than ERROR, change to WARNING, INFO, etc.
            'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
            'tags': {'custom-tag': 'x'},
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'django.db.backends': {
            'level': 'ERROR',
            'handlers': ['console'],
            'propagate': False,
        },
        'raven': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'sentry.errors': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
    },
}

Notice the change in url to https and the verify_ssl=0 setting.