Moving Zimbra Collaboration Server to a new IP address

Here’s a quick overview how to migrate a ZCS mail server (based on Ubuntu) to a new IP address:

0) Not covered here: Adjusting DNS entries. Make sure you lower the TTLs of the relevant DNS entries a couple of days in advance in order to minimize downtime for clients (e.g. set a TTL of 300 for a 5 minute downtime).

1) Set the new IP address in:
* The relevant DNS entries
* /etc/network/interfaces
* /etc/hosts
* If ZCS runs in a container/VM, don’t forget to adjust its IP address too.

2) If the new IP address is part of a new subnet, make sure to add this new subnet to ZCS’s trusted_networks, otherwise, sending (relaying) messages through ZCS from Zimbra Desktop (or any other mail client) won’t work[1]. This can be set using ZCS’s web admin interface (i.e. https://mail.myserver.com:7071/zimbraAdmin/):
Navigate to “Server settings”, then open the “MTA” tab and set something analogous to the following in “MTA Trusted Networks”:
127.0.0.0/8 w.x.y.z/26

3) Restart networking and the ZCS services (it’s important, as this adjusts the trusted_network setting in ZCS’s amavisd too):
# /etc/init.d/zimbra stop
# /etc/init.d/networking restart
# /etc/init.d/zimbra start

Alternatively, just reboot the server, particularly if it runs in a VM.

Voilà!

Note: The need for the adjustments in step 2) might come as a surprise. Authenticated messages to be relayed through ZCS apparently seem to originate from the external IP address, not localhost/127.0.0.1.

[1] A typical postfix error message might look like:
Delivery Failure Notification: Invalid address: somebody . com.zimbra.cs.mailbox.MailSender$SafeSendFailedException: MESSAGE_NOT_DELIVERED; chained exception is: com.zimbra.cs.mailclient.smtp.InvalidRecipientException: RCPT failed: Invalid recipient somebody@somedomain.com: 554 5.7.1 : Relay access denied

Kimai – Open Source Time Tracking Tool

So far, I’ve always used “good old” spreadsheets for time tracking on projects. Custom ones I pimped up with some nifty formulae, but still just spreadsheets. Advantage: I can easily adjust them to any special needs anytime – be it the inclusion or exclusion of specific work or just a customization of the sheet’s design or layout. The price for this flexibility is the generally higher effort to track the time “manually” rather than using a specialized time tracking tool – which makes time tracking a tedious task.

Of course I’ve evaluated many proprietary and open source time tracking tools over the years, but so far, none of them managed to fully convince me.

Today, I’ve just stumbled over Kimai – an open source, web-based time tracking tool written in PHP. And so far, Kimai looks promising. Installation is dead easy – just make sure you’ve compiled PDO support into PHP (Gentooers: enable the PDO flag for dev-lang/php and remerge php), else the nice web-based installation wizard will abort without printing any error message.

Once you’ve logged in, you’ll be presented a very clean, intuitive GUI where you can setup customers, projects and tasks. On the top-right there’s a big push-button to start/stop/pause the time tracking.

During my quick evaluation, I haven’t found the functionality yet to export the timesheets, but as far as I know, such functionality will be provided by extensions that can be installed. Let’s see. [Addition 20091009: There’s a stats extension quick-hack for Kimai 0.8.x that can be used to list and print selected reports. To use it, simply download it, extract it in the extensions folder and navigate to {Kimai install folder}/extensions/stats/]

Here’s a screenshot of Kimai 0.8.1.890:

Kimai 0.8.1.890 Screenshot
Kimai 0.8.1.890 Screenshot

With the currently still very limited feature-set, Kimai doesn’t compete with full-grown project management solutions (I’ve recently seen a quick demo of a very sophisticated and cool, Django-based project management solution I’m not allowed to tell any details about yet). But it looks like a promising start. I hope the Kimai project will gain momentum, grow and mature as there’s definitely a need for open source time tracking tools – particularly web-based ones.

P.S. I haven’t had the time yet to audit Kimai’s source code, but if the orderly, clean GUI is any indication, it can’t be too bad.

Django custom model field for an unsigned BIGINT data type

Web 2.0 social media platforms tend to think “big”. They hence often use big integers (8 bytes / 64 bits long instead of just 4 bytes / 32 bits like a normal integer) for user IDs (or sometimes message IDs) to be prepared for even the most extreme potential future growth of their user base. Usually, these big integers are unsigned, allowing for up to 18’446’744’073’709’551’615 UIDs to be stored (which is probably enough to register the inhabitants of quite a few other blue planets too ;).

Facebook, with currently more than 300 million active users, also uses  a 64 bit unsigned integer for storing user IDs and expects Facebook applications to be able to handle this. Of course, 300 M user IDs would still easily fit into a 32 bit unsigned integer, but Facebook already goes beyond the 32 bit limit by issuing 15 digit UIDs like 100’000’xxx’xxx’xxx to registered test users (which allows Facebook to better distinguish between test accounts and real accounts).

Now if you happen to use Django to build your Facebook application, this fact needs special attention as Django doesn’t support 64 bit integer field types for its ORM models by default. As a Django developer, you could thus resort to using a CharField for storing Facebook UIDs (which would be odd) or, better, define a custom model field you can use in your models instead of IntegerField. Fortunately, Django offers an elegant way to define custom model fields. You can write your custom PositiveBigIntegerField by simply subclassing (extending, inheriting from) models.PositiveIntegerField:

So, in your models.py add the following code:

from django.db import models
from django.db.models.fields import PositiveIntegerField

class PositiveBigIntegerField(PositiveIntegerField):
    """Represents MySQL's unsigned BIGINT data type (works with MySQL only!)"""
    empty_strings_allowed = False

    def get_internal_type(self):
        return "PositiveBigIntegerField"

    def db_type(self):
        # This is how MySQL defines 64 bit unsigned integer data types
        return "bigint UNSIGNED"

class Mytest(models.Model):
    """Just a test model"""

    huge_id = PositiveBigIntegerField()

    def __unicode__(self):
        return u'id: %s, huge_id: %s' % (self.id, self.huge_id)

(NB: The “Mytest” class is just for testing the PositiveIntegerField definition, it’s not part of the PositiveIntegerField definition.)

Note that this solution only works for MySQL as a database backend (as MySQL supports the “bigint UNSIGNED” data type for columns which isn’t defined in the SQL standard).

For testing, define a “Mytest” model as shown above and execute “python manager.py syncdb” to create a new myapp_mytest table with an unsigned bigint(20) column named huge_id. Register this new model “Mytest” in admin.py, restart runserver and you’ll be able to enter 64 bit integer values through Django’s admin application.

The only minor “issue” is that Django admin’s CSS class (.vIntegerField) used for HTML form input fields representing integer values defines the width as “5em” which is a bit too narrow to display the entire 64 bit integer. This can be adjusted however (e.g. by writing your own ModelForm and telling ModelAdmin to use that, see the Django admin documentation and the Widget.attrs documentation).

P.S. Note that for Django to be able to access and use a “bigint UNSIGNED” data type, you don’t necessarily need to define a PositiveBigIntegerField and adjust your models. Instead, you could simply adjust the column type in MySQL accordingly as a quick-fix. If you use syncdb (like most Django devs) and want it to create your tables and columns correctly however, defining a custom model type as described is the way to go and strongly recommended for consistency and QA.

Gentoo: Greylisting for Postfix using Postgrey

Finally, I’ve had to enable greylisting for this domain due to ever increasing levels of spam. Fortunately, setting it up is very easy. For Gentoo and Postfix, here’s a nice walkthrough:

postfix greylisting on gentoo (postgrey) | andreas d.’s.

Let’s hope that this, in conjunction with other anti-spam measures, will do it for a while.

Non-spammers shouldn’t experience any problems due to this change, but if you do, please contact me using Skype (mettlerd), phone or SMS.

Gentoo ebuild for Lx-Office ERP 2.6.0 beta 1

Finally, I’ve created Gentoo ebuilds for Lx-Office ERP 2.6.0 beta 1 and its dependencies. Lx-Office is a fork of the server-based open source accounting solution SQL-Ledger and customized for the German market (and to some extent, the Swiss and Austrian markets).

A screenshot of Lx-Office ERP 2.6.0 beta 1 showing the XUL menu:

Screenshot of Lx-Office ERP 2.6.0 beta 1 using the XUL menu

And here’s a flash video of Lx-Office ERP 2.6.0 beta 1 showing the XUL menu in action.

Lx-System (the company backing Lx-Office ERP) and LINET Services host a public demo of Lx-Office ERP 2.4.3 (user: demo, password: demo).

To install Lx-Office ERP 2.6.0 beta 1 on Gentoo, follow these steps:

1) Set up a local portage overlay (e.g. at /usr/local/portage), if you haven’t done so already.

# mkdir -p /usr/local/portage

In /etc/make.conf, set

PORTDIR_OVERLAY=/usr/local/portage

2) Download lx-office-erp-2.6.0_beta_p1-r1_plus_dependencies.tgz and extract it to your local portage overlay

# cd /usr/local/portage
# tar xzvf lx-office-erp-2.6.0_beta_p1-r1_plus_dependencies.tgz

3) In /etc/portage/package.keywords, add the line

www-apps/lx-office-erp ~amd64

(or ‘www-apps/lx-office-erp ~x86‘, depending on the architecture of your machine)

4) In /etc/portage/package.use, add the line

www-apps/lx-office-erp vhosts

5) Install Lx-Office ERP on your system by executing

# emerge -av lx-office-erp

Depending on your current portage settings and installed ebuilds, you may need to unmask additional ebuilds.

6) Use webapp-config to link your Lx-Office ERP installation to a specific host, e.g. by executing

# webapp-config -I -h localhost -d lx-erp lx-office-erp 2.6.0_beta_p1-r1

7) Follow the steps displayed on the screen to setup and configure Lx-Office ERP. Some of these steps might be automated in a later release of the ebuild.

8) Have fun using Lx-Office ERP on Gentoo! :)

(These ebuilds are sponsored by my company Printscreen GmbH, dedicated to the developers of Lx-Office ERP and Gentoo and released for free use under the terms and conditions of the GNU GPLv2 license.)

Setting up Procmail and Postfix with maildir for mobile usage

When I’m on the road, I can check my private and business e-mail using my very handy Nokia e61i smartphone (which I like a lot, apart from its rather unstable web browser). However, as I’ve never been far away from a computer for a long time so far, I’ve only used to check mail that was delivered to my inbox, and not to any of its about 200 subfolders (I once tried to subscribe to all folders – the mail client of the e61i simply crashed ;). Now, I figured I’d need to do something about this in order to not miss any of the mails that are automatically moved to a subfolder by the server-side procmail mail filter.

The solution: Simply create a new procmail rule that copies (that’s what the c stands for) any incoming message to a special folder (I named it “mobile”; note that my postfix uses the maildir format to store messages):

:0 c
.mobile/

Preferably, this rule should be placed after the spam filtering rules (you don’t want to pay for spam on your mobile, do you? ;) and before the normal procmail mail filter rules (which move every incoming mail to the appropriate subfolder). You can also use a dedicated rules file for every group of similar rules. For example, I include the files spam.rc, mobile.rc, lists.rc (with their according rules) in the main .procmailrc config file.

Now every mail that wasn’t filtered by the spam filter gets copied to the “mobile” subfolder of your inbox prior to getting moved to the appropriate subfolder (by the rules in lists.rc).

On my e61i, I hence only need to subscribe to the “mobile” subfolder in order to catch all incoming messages. As you can’t unsubscribe from the inbox subfolder itself, you should set the maximum number of caught new inbox mails to 1 (which is the minimum) in order to avoid fetching things twice. You can further configure that only headers are fetched to minimize the amount of data[1] that is automatically downloaded with every mail check (also: switch off polling if you don’t need it).

Note that another advantage of this solution is that you won’t tamper with any of the original messages (that are either in your inbox or in any of its subfolders). Some might call this a disadvantage though.

That’s it, have fun! :)

[1] I pay 0.10 CHF per 20 KB, i.e. 5 CHF (5 USD) per MB (which is incredibly expensive as I currently don’t have any flat rate data plan -> please don’t send me a mail bomb just for fun, else I’ll have to write a more sophisticated procmail rule that only copies messages < 100 KB to the mobile folder)

Ready, steady, go!

Refreshing. Innovative. New. Creative. The sky is the limit. Startup fever. Brian Haven:

This new job is ambiguous. I don’t have a job title. The company doesn’t have a name. At the moment, there are only three of us. We don’t know what this will become, we only have a general direction. My office will be at my house… in Austin… and in cyberspace on IM, Twitter, Facebook… To many, this recipe might spell fear. To me, it’s comfortable. I thrive in the unknown–no rules, no baggage, no momentum to pull us into mediocrity. We get to build this from scratch in a thoughtful and disciplined manner. It’s my opportunity to bring my engagement ideas to life and the perfect time to leverage my background to apply a design thinking approach to the way we, and our clients, do business.

I had the joy to experience the reviving entrepreneurial spirit at yesterday’s public beta launch party at the Wuala office in Zurich. And I experience it daily when working for my own company – Printscreen GmbH. A great feeling indeed, and inspiring others, too.

Twitter / mettlerd

I’ve finally joined the flock of birds: Twitter / mettlerd. Let’s see whether it will be just a waste of time or an unexpected blessing. In general, most reviews of other (much earlier) birds are cautiously positive..

Aug 29, 2008: BlogCamp Switzerland 3.0 in Zurich

Note that this year’s Swiss BlogCamp, the BlogCamp Switzerland 3.0, will take place on the same date (August 29, 2008) as the Tag der Informatik (informatica08) and the tweakGrill, and at the same location (Technopark in Zurich), too! Of course, this is no coincidence :) No matter whether you’re a blogger or not (or plan to be, have been, are interested in the Swiss blogging scene, the web 1.0, 2.0, 3.0, 4.0, whatever etc. ;): Be there, I’m sure it will be an interesting event, again! (And attending the “Tag der Informatik” is a point of honor anyway :)

(Bloggy Friday will start at 8 PM, guess where ;)

BlogCamp Switzerland 3.0

[UPDATE 20080802: I probably can’t be there due to military service :( At rather short notice as they managed to send the march order to an address that doesn’t exist. No comment.]