Category Archives: Uncategorized

Solving Python virtualenv “DistributionNotFound: distribute”

After upgrading my Ubuntu machine from 12.04 to 14.04 I had this error on virtualenv wrapper:

stevedore.extension distribute
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/stevedore/extension.py", line 75, in _load_plugins
    invoke_kwds,
  File "/usr/local/lib/python2.7/dist-packages/stevedore/extension.py", line 87, in _load_one_plugin
    plugin = ep.load()
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2087, in load
    if require: self.require(env, installer)
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2100, in require
    working_set.resolve(self.dist.requires(self.extras),env,installer)))
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 628, in resolve
    raise DistributionNotFound(req)
DistributionNotFound: distribute

After some investigation I found out the cause of the error, it seems that I’ve installed virtualenv-wrapper using pip and not Ubuntu apt-get, so when I installed it using apt-get it conflicted with the pip installation.

Solution

  • Remove virtualenvwrapper Ubuntu package: sudo aptitude remove virtualenvwrapper
  • Remove virtualenvwrapper pip package: sudo pip uninstall virtualenvwrapper virtualenv-clone virtualenv stevedore
  • Reinstall virtualenvwrapper Ubuntu package: sudo aptitude install virtualenvwrapper

Rsnapshot on OSX

Rsnapshot is a backup solution for Unix machines including Linux and OSX, it supports many great features including full backups with the size of only incremental backup, it also support backing up local and remote machines.

Check my previous post for more details about it, Backup Journey to rsnapshot

Install Rsnapshot

The easiest way to install unix programs in OSX is to use Homebrew, after installing Homebrew install rsnapshot and needed programs:

$ brew update
$ brew install rsnapshot
$ brew install coreutils

“coreutils” is needed because “cp” command installed with OSX doesn’t support GNU “cp” options needed for rsnapshot.

Configuration

I will be running rsnapshot from user account and not root user, I will be using my user “rayed”:

$ mkdir /Users/rayed/rsnapshot
$ cat > /Users/rayed/rsnapshot/rsnapshot.conf << EOF
#################################################
# rsnapshot.conf - rsnapshot configuration file #
#################################################
#                                               #
# PLEASE BE AWARE OF THE FOLLOWING RULES:       #
#                                               #
# This file requires tabs between elements      #
#                                               #
# Directories require a trailing slash:         #
#   right: /home/                               #
#   wrong: /home                                #
#                                               #
#################################################
config_version	1.2

snapshot_root	/Users/rayed/rsnapshot/

cmd_cp		/usr/local/bin/gcp
cmd_rm		/bin/rm
cmd_rsync	/usr/bin/rsync
cmd_ssh		/usr/bin/ssh
cmd_logger	/usr/bin/logger

retain		hourly	4
retain		daily	7
retain		weekly	4
retain		monthly	3

verbose		2
loglevel	3
logfile		/Users/rayed/rsnapshot/rsnapshot.log
lockfile	/Users/rayed/rsnapshot.pid

# Backup local machine
backup		/Users/rayed/	localhost/
# Backup remote machine
backup		rayed@example.com:/home/rayed/	example.com/
EOF

Important notes about the configuration files:

  • Use TABs not spaces between elements.
  • Directories require a trailing slash, i.e. /home/ not /home
  • On OSX we replaced “cmd_cp” from “/bin/cp” to “/usr/local/bin/gcp” to support rsnapshot options.
  • For remote machine backup, make sure you use ssh keys, Rsnapshot can’t use passwords.

Running rsnapshot

To test your setup try the following command:

rsnapshot -c /Users/rayed/rsnapshot/rsnapshot.conf hourly

When everything works fine, you need to configure “rsnapshot” to run periodically from cron, install the following line:

$ crontab -e
:
# RSnapshot
0 */6 * * *	/usr/local/bin/rsnapshot -c /Users/rayed/rsnapshot/rsnapshot.conf hourly
30 3 * * *	/usr/local/bin/rsnapshot -c /Users/rayed/rsnapshot/rsnapshot.conf daily
0  3 * * 1	/usr/local/bin/rsnapshot -c /Users/rayed/rsnapshot/rsnapshot.conf weekly
30 2 1 * *	/usr/local/bin/rsnapshot -c /Users/rayed/rsnapshot/rsnapshot.conf monthly

After few hours double check your setup by making reviewing the log file “/Users/rayed/rsnapshot/rsnapshot.log”, and check the rsnapshot root directory for your backups, you should have something like:

$ ls -l /Users/rayed/rsnapshot/
hourly.0
hourly.1
hourly.2
hourly.3
daily.0
daily.1
:

Monitoring Servers with Munin

This is a draft on configuring Munin to monitor services on a Linux machine, still dirty but published for my reference, if you have question let me know.

Monitoring Servers

sudo apt-get install munin

sudo htpasswd -c /etc/munin/htpasswd rayed

vi vi /etc/munin/munin-conf.d/example_com_site
:
[munin-node.example.com]
    address munin-node.example.com
    use_node_name yes
:


sudo vi vi /etc/nginx/sites-enabled/default
server {
:
location /munin/static/ {
        alias /etc/munin/static/;
        expires modified +1w;
}

location /munin/ {
        auth_basic            "Restricted";
        auth_basic_user_file  /etc/munin/htpasswd;

        alias /var/cache/munin/www/;
        expires modified +310s;
}
:
}

Monitored Servers

sudo apt-get install munin-node
sudo apt-get install munin-plugins-extra

sudo vi /etc/munin/munin-node.conf
:
allow ^172\.18\.100\.100$   # monitoring server address
:

MySQL plugin

sudo apt-get install libcache-perl libcache-cache-perl

sudo munin-node-configure --suggest --shell | sh

sudo munin-run mysql_commands 

sudo service munin-node restart

Memcached plugin

sudo aptitude install libcache-memcached-perl

sudo ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_bytes
sudo ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_counters
sudo ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_rates

sudo munin-run mysql_commands 

sudo service munin-node restart

Nginx Web Server

Configure Nginx to repoer its status under the URL http://localhost/nginx_status, which will be read from Munin Nginx plugin:

sudo vi /etc/nginx/sites-enabled/default
server {
:
        # STATUS
        location /nginx_status {
                stub_status on;
                access_log off;
                allow 127.0.0.1;
                allow ::1;
                allow my_ip;
                deny all;
        }
:
}

sudo service nginx restart

Configure Munin:

sudo apt-get install libwww-perl

sudo ln -s '/usr/share/munin/plugins/nginx_request' '/etc/munin/plugins/nginx_request'
sudo ln -s '/usr/share/munin/plugins/nginx_status' '/etc/munin/plugins/nginx_status'

sudo munin-run nginx_request

sudo service munin-node restart

Django memory leak with gunicorn

tl;dr add “–max-requests” to Gunicorn to easily solve memory leak problems.

If you have a long running job that leaks few bytes of memory it will eventually will consume all of your memory with time.

Of course you need to find out where is the memory leak and fix it, but sometimes you can’t because it on a code that you use and not your own code.

Apache webserver solve this problem by using “MaxRequestsPerChild” directive, which tells Apache worker process to die after serving a specified number of requests (e.g. 1000), which will free all the memory the process acquired during operation.

I had a similar problem with Django under Gunicorn, my Gunicorn workers memory keep growing and growing, to solve it I used Gunicorn option “–max-requests”, which works the same as Apache’s “MaxRequestsPerChild”:

gunicorn apps.wsgi:application -b 127.0.0.1:8080 --workers 8 --max-requests 1000

Django Themes (or where to put base.html?)

The Wrong Way

I used to create a new directory to hold common templates like “base.html”, and add it TEMPLATES_DIR in the settings.py file:

TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'templates') ,)

But in most cases the “base.html” would need to use CSS, JS, and image files to be functional, so I changed the url routing to access them (from the DEBUG mode only), something like:

$ vi apps/urls.py
:
# Serve Static Files 
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += patterns('django.views.static',
        url(r'^(?P<path>(js|css|img)/.*)$', 'serve', {'document_root':  settings.BASE_DIR+'/../www'}),
        )

This setup isn’t ideal for many reasons:

  • I had to modify settings.py and urls.py with complicated settings.
  • Theme design span multiple directories, and it isn’t self contained.
  • Switching the design is complicated, and include many changes.

Django Simple Themes

Nowadays I create a new Django application e.g. “my_theme” to hold my “base.html” template and all needed static files (CSS, JS, Images, etc …).

./manage.py startapp my_theme

Then add it to INSTALLED_APPS:

INSTALLED_APPS = (
    # django core apps ...
    'my_theme',
    # other apps ...
)

The directory structure for my new app looks like this:

my_theme/
    templates/
        base.html
    static/
        my_theme/
            css/
            js/
            img/

and from my “base.html” (or any other template) I could access the static file using the static tag:

{% load staticfiles %}
<img src="{% static "my_theme/img/logo.png" %}" />

I don’t even need to change the “urls.py” file to access the static file, since the development server (i.e. ./manage.py runserver) already knows how to find them.

But for production I have to define:

STATIC_ROOT = os.path.join(BASE_DIR, '../www/static')

and run:

./manage.py collectstatic --noinput

New Theme

By having all theme files inside an application I can start new theme by copying “my_theme” to something like “new_theme” and replace it in the INSTALLED_APPS in the settings.py.

What about uploaded files?

To access uploaded file from development server you need to define both MEDIA_URL and MEDIA_ROOT and change your “urls.py”:

$ vi apps/urls.py
:
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Source: Serving files uploaded by a user during development

Sample Theme

You can download my sample theme from:
https://github.com/rayed/django_theme

Protect your Server with Fail2Ban

Fail2ban is a program that scan your log files for any malicious behavior, and automatically block the offending IP.

The default Fail2ban installation on Ubuntu will protect ssh, but in this article I will show how to protect against WordPress comment spammers too, to slow them down.

Installation & Configuration

# Install fail2ban
$ sudo apt-get install fail2ban

# Copy default config to custom config
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Add your own IPs so they never get blocked
$ sudo vi /etc/fail2ban/jail.local
:
ignoreip = 127.0.0.1/8 10.0.0.0/8 192.168.1.5
:

# restart it
$ sudo service fail2ban restart

Fail2ban is now configured and running.

You can use the following commands to inspect and trouble shoot its operation:

# fail2ban usually add new rules to your IPTables
$ sudo iptables -L

# You can check the status of specific rules using the command:
$ sudo fail2ban-client status ssh

# and of course check log to see if it is working:
$ sudo tail -f /var/log/fail2ban.log 

Protecting WordPress Comments

By default fail2ban protect many ssh but let’s assume you want to protect WordPress from spam bots trying to post comments on your blog.

First we add a filter to catch the attempts by creating new filter file named “/etc/fail2ban/filter.d/wordpress-comment.conf”:

$ sudo vi /etc/fail2ban/filter.d/wordpress-comment.conf 
#
# Block IPs trying to post many comments
#
[Definition]
failregex = ^<HOST> -.*POST /wordpress/wp-comments-post.php

Then we create a new JAIL by adding the following to “jail.local” file:

$ sudo vi /etc/fail2ban/jail.local
:
:
[wordpress-comment]
enabled = true
port = http,https
filter = wordpress-comment
logpath = /var/log/apache2/*access*.log
bantime = 3600
maxretry = 5

Then restart fail2ban using:

sudo service fail2ban restart

كيف تنشئ موقع انترنت مجانا

هل تملك عنوان بريد الكتروني تحت gmail او hotmail؟ ماذا لو بحثت عن اسمك هل ستظهر صفحتك في تويتر او فيس بوك؟

لماذا لا تقوم بحجز اسم نطاق خاص بك مثل www.rr.sa ويكون عنوانك البريدي هو rayed@rr.sa، وبالمجان ايضاً.

نحتاج للخدمات ما يلي:

  1. تسجيل اسم النطاق domain: المركز السعودي لمعلومات الشبكة (SaudiNIC) يقدم نطاق تحت العنوان “.sa” مجانا.
  2. استضافة اسم النطاق: موقع ClouDNS يقدم خدمة استضافة النطاقات مجانا. (نعم تسجيل النطاق شئ واستضافته شئ آخر) اتمنى لو يقدم المركز السعودي هذه الخدمة مجانا ايضاً.
  3. استضافة موقع الويب، والخيارات هنا عديدة ما اعرفها هي:
    1. Github Pages مع اسم نطاق مخصص Setting up a custom domain with GitHub Pages
    2. موقع tumblr.com مع اسم نطاق مخصص Using a custom domain name
  4. استضافة البريد: موقع ClouDNS يقدم خدمة استقبال واعادة ارسال البريد Email Forwarding لثلاث حسابات مجانا.