Tag Archives: python

5 things on our Linux monitoring daemon

Our Linux server monitoring daemon is called sb-daemon. Here are few facts about it.

1. It’s written in pure Python.

We conducted tests on Centos and Fedora with Python versions 2.6 and 2.7. So it should work properly on other operating systems with mentioned Python versions.

2. It doesn’t require external libraries or tools.

To start using our server monitoring you don’t have to install anything except our daemon since it doesn’t have third-party software dependencies.

3. sb-daemon reads only /proc filesystem.

sb-daemon is open-source Python script.  You can check it to investigate how it works. To get performance parameters we check only /proc filesystem.

4. sb-daemon doesn’t fork processes.

We do not fork any processes from Python. Everything you may want to monitor we get from /proc filesystem so it doesn’t lead to any performance issues.

5. sb-daemon only sends data to ServerBeep.

Our software never requests any data from your servers. sb-daemon doesn’t open any listening sockets but only sends data to our servers.

Launching Python applications with Gunicorn and systemd

At ServerBeep.com we love Python and use it widely. There are a lot of ways to deploy Python application. One of them is using Gunicorn.

Gunicorn is a Python WSGI HTTP Server for UNIX. So if you have WSGI complaint application you can run it with Gunicorn. It can be, for instance, Django or Flask powered applications.

From the other hand, last versions of Fedora Linux ship with systemd. Systemd is a featured replacement of old SysV system. Among other features there is one which allows to launch the processes after server boot. To use systemd for the applications called app launch create file /lib/systemd/system/gunicorn-app.service:


ExecStart=/usr/bin/gunicorn -D -n gunicorn-app -w5 tracwsgi:application -b --access-logfile /home/app/log/app.serverbeep.net-access.log --error-logfile /home/app/log/app.serverbeep.net-error.log
WorkingDirectory = /home/app/


And enable it:

systemctl enable gunicorn-app.service

Now after server boots you will get your application run. After you start it Gunicorn will handle the requests which are sent to Next step could be nginx or Apache setup as reverse proxy. It means that webserver listens well-known port 80 and serves some files (usually static ones) directly and send rest of requests to Gunicorn. It responses back and webserver provides a reply to a user.

With systemd you don’t have to setup supervisord or other processes monitoring and management tools. Systemd will take care of it. It’s easy and neat way to launch the daemons.

Email infrastructure made right. Part 2: handling bounces.

In our previous post on email infrastructure we were talking about minimum requirements which should be implemented. Today we will cover bounces handling. What do the bounces mean? In short words, it’s a non delivery report. You could get if you send a mail to non-existing user (error code 5.1.1 ) or a user which has full mailbox (5.2.2).

There are kinds of the bounces:

  • soft bounces;
  • hard bounces.

If you get soft bounces it means that you can try to send an email later. And hard bounces mean that email account you are trying to send to is invalid. Such email accounts should not be used for further mail sending. And if you have a lot of subscribers you need a way to get rid of invalid email accounts. But how can you do it? Fortunately there’s a simple way. Probably you’ve heard about VERP. It stands for Variable envelope return path. Here’s how it works (we will cover Sendmail and Dovecot based setup on Centos).

Let’s assume we want to send a mail to joe@example.com from no-reply@serverbeep.com. If there’s no user joe@example.com we will get a bounce message to no-reply@serverbeep.com. But why don’t we collect all bounces in one mailbox? For simplicity of handling bounces we can setup some mail account. Let’s called it bounces@serverbeep.com and setup our LDA to deliver all mails to some user account (it could be system user bounces or some other account depending on your setup). Set up Sendmail to forward all incoming mail sent to bounces@serverbeep.com to system account bounces. Open /etc/aliases files and add next line:

bounces@serverbeep.com: bounces

Tell Sendmail to use Dovecot as LDA:

FEATURE(`local_procmail', `/usr/libexec/dovecot/deliver',`/usr/libexec/dovecot/deliver -d $u')

It should be placed to /etc/mail/sendmail.mc.

Apply Sendmail changes:

cd /etc/mail ; make all restart

If you don’t have Dovecot installed it’s time to install it:

yum install dovecot

Here’s an example of Dovecot configuration file working as LDA:

# 2.0.9: /etc/dovecot/dovecot.conf
# OS: Linux 2.6.32-279.1.1.el6.x86_64 x86_64 CentOS release 6.3 (Final)
disable_plaintext_auth = no
lda_mailbox_autocreate = yes
listen =
mail_location = maildir:~/Maildir
mbox_write_locks = fcntl
passdb {
driver = pam
postmaster_address = postmaster@serverbeep.com
ssl = no
userdb {
driver = passwd
protocol lda {
auth_socket_path = /var/run/dovecot/auth-master
info_log_path = /var/log/dovecot/delivery-info.log
log_path = /var/log/dovecot/delivery.log
postmaster_address = postmaster@serverbeep.com

(Make sure you have /var/log/dovecot and dovecot has the permissions to write there).

Well, since we prepared everything let’s get back to VERP. To get a bounces while sending a mail to joe@example.com to bounces user maildir we need to add Return-Path header to our mail. Short example in PHP:

mail("joe@example.com", "Message subject", "Message body", "From: no-reply@serverbeep.com\n", "-fbounces+joe=example.com@serverbeep.com");

So, there will be additional header in the email:

Return-Path: bounces+joe=example.com@serverbeep.com

In this case if there’s no user joe@example.com we will get a bounce message in our POP3/IMAP4 account bounces from where the messages could be easily fetched with simple Python script.

import imaplib
M = imaplib.IMAP4('')
M.login('bounces', 'strongest_password')
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
print 'Message %s\n%s\n' % (num, data[0][1])

Once you get the messages you can parse it to get a list of invalid email accounts and make a modification of your users table in the database.