Howtos

Howtos

SOHO Mailserver with Postfix+Postgresql+Dovecot+SpamAssassin+Roundcube

This HowTo describes my Home-Mailserver Setup. Basically this is a sum-it-all-up article from various resources on the net. 

Used Software:

  • Arch Linux OS
  • Postfix MTA
  • PostgreSQL database backend
  • Dovecot IMAP Server
  • Roundcube Webmail + Apache Webserver
  • Spamassassin junk filter
  • Server-side filtering with Sieve
  • fetchmail (for pulling all spread accounts in this one place)

Preconditions:

  • Server behind Firewall/NAT
  • Dynamic IP (No-IP Plus managed DynDNS service with MX Record etc)
  • StartSSL certificate for both Web- and Mail-Server domain
  • ISP doesn't allow running an outgoing mail server
  • Apache + PHP + Postgresql already running and working

1. Prepare the host interfaces

As the server runs with LAN IP it's required to set hostnames in /etc/hosts. Here both Apache and the Mail-$foo will listen on one interface.

192.168.1.2   domain.net   mail.domain.net

2. Install required packages

This host runs Arch-Linux with community, extra and AUR enabled.

# yaourt -S postfix postfixadmin dovecot pigeonhole roundcubemail spamassassin \
razor fetchtmail perl-dbd-pg perl-lockfile-simple

3. Setup Postgresql DB

We will need two DBs: one for postfix/postfixadmin/dovecot, one for roundcubemail

$ createuser postfixadmin -P     # no superuser, no createdb, no createuser
$ createuser mailreader -P        # dito
$ createuser roundcube -p         # dito
$ createdb postfix --owner postfixadmin
$ createdb roundcube --owner roundcube

4. Setup PostfixAdmin

I installed postfixAdmin into a vhost which is only accessible on localhost, using following config (mind: AUR package of postfixadmin)

Alias /postfixAdmin "/usr/share/webapps/postfixAdmin"
<Directory "/usr/share/webapps/postfixAdmin">
      AllowOverride All
      Options FollowSymlinks
      Order allow,deny
      Allow from all
</Directory>

.. and included that in the local-only vhost.

Then edit /etc/webapps/postfixadmin/config.inc.php

$CONF['configured'] = true;
...
$CONF['database_type'] = 'pgsql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfixadmin';
$CONF['database_password'] = 'secret';
...
$CONF['admin_email'] = 'postmaster@domain.net';
...
$CONF['smtp_server'] = 'mail.domain.net';
$CONF['smtp_port'] = '25';
...
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';

Now head to http://admin.localhost/postfixAdmin/setup.php. Generate a setup_password and put the hash in /etc/webapps/postfixadmin/config.inc.php.

Now run the setup. This will install the DB-Schema for Postfix, and setup an admin user.

5. Prepare Dovecot

The next step is to prepare Dovecot. I will use Dovecot LDA as delivery agent, and enable Sieve/ManageSieve for server-side filtering. Edit following file in /etc/dovecot (only changed lines are shown).

edit dovecot.conf

protocols = imap sieve
listen = *, ::

create dovecot-sql.conf.ext

driver = pgsql
connect = host=localhost dbname=postfix user=postfix password=secret
default_pass_scheme = MD5
user_query = \
    SELECT '/var/mail/vmail/'||maildir AS home, '*:bytes='||quota AS quota_rule \
    FROM mailbox WHERE username = '%u' AND active = TRUE
password_query = \
    SELECT '/var/mail/vmail/'||maildir AS userdb_home, \
        username AS user, password, '*:bytes='||quota AS userdb_quota_rule \
    FROM mailbox WHERE username = '%u' AND active = TRUE

conf.d/10-mail.conf

mail_location = maildir:/var/mail/vmail/%d/%n/
mail_uid = 8
mail_gid = 12
first_valid_uid = 8
last_valid_uid = 8
first_valid_gid = 12
last_valid_gid = 12
mail_plugins = quota

conf.d/20-imap.conf

mail_plugins = $mail_plugins imap_quota

conf.d/10-master.conf

service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = mail
    group = mail
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}

service auth-worker {
  user = $default_internal_user
}

conf.d/10-auth.conf (I enabled plain-text auth for testing. Take care!)

disable_plaintext_auth = no  #DANGEROUS
#!include auth-system.conf.ext
!include auth-sql.conf.ext

conf.d/15-lda.conf

postmaster_address = postmaster@domain.net
protocol lda {
  mail_plugins = $mail_plugins sieve
}

conf.d/90-plugin.conf

Note: /var/lib/dovecot/sieve/ has to be created and owned by mail:mail

plugin {
   sieve = ~/.dovecot.sieve
   sieve_global_path = /var/lib/dovecot/sieve/default.sieve
   sieve_dir = ~/sieve
   sieve_global_dir = /var/lib/dovecot/sieve/global/
}

conf.d/10-ssl.conf

Note: for StartSSL combine the server and the intermediate cert in one .pem (with cat .. > ..), and specify the root ca

ssl = yes
ssl_cert = </etc/ssl/certs/mail.domain.net.pem
ssl_key = </etc/ssl/private/mail.domain.net.key
ssl_ca = </etc/ssl/certs/startssl-ca-bundle.crt

6. Prepare Postfix

main.cf

myhostname = mail.domain.net
mydomain = domain.net
mydestination = $myhostname, localhost
mynetworks = 192.168.1.0/24, 127.0.0.0/8
myorigin = $mydomain
relay_domains = proxy:pgsql:/etc/postfix/pgsql/relay_domains.cf
# this is needed if your ISP doesn't allow to run a outgoing mailserver. Use their mail relay.
relayhost = mail.mnet-online.de
# enable auth via Dovecot
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
# vmail stuff
virtual_mailbox_base = /var/mail/vmail
virtual_mailbox_limit = 512000000
virtual_mailbox_domains = proxy:pgsql:/etc/postfix/pgsql/virtual_domains_maps.cf
virtual_mailbox_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_mailbox_maps.cf
virtual_alias_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_alias_maps.cf
virtual_uid_maps = static:8
virtual_gid_maps = static:12
virtual_minimum_uid = 8
dovecot_destination_recipient_limit = 1
virtual_transport = dovecot-spamassassin
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps

/etc/postfix/pgsql/relay_domains.cf

user = mailreader
password = secret
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = true

/etc/postfix/pgsql/virtual_alias_maps.cf

user = mailreader
password = secret
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = true

/etc/postfix/pgsql/virtual_domains_maps.cf

user = mailreader
password = secret
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = false and active = true

/etc/postfix/pgsql/virtual_mailbox_limits.cf

# Used for QUOTA!
user = mailreader
password = secret
hosts = localhost
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s'

/etc/postfix/pgsql/virtual_mailbox_maps.cf

user = mailreader
password = secret
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true

/etc/postfix/master.cf

We pipe through spamassassin forwards to Dovecot DLA

dovecot-spamassassin   unix  -       n       n       -       -       pipe
  flags=DRhu user=mail:mail argv=/usr/bin/vendor_perl/spamc -f -e /usr/lib/dovecot/deliver
  -f ${sender} -d ${recipient}

7. Prepare Spamassassin

Just install, and edit /etc/conf.d/spamd

SAHOME="/var/lib/spamassassin"
SPAMD_OPTS="--max-children 1 --username spamd --helper-home-dir ${SAHOME} -s ${SAHOME}/spamd.log -x -q --pidfile /var/run/spamd.pid"

8. Create domain and users in postfixAdmin

Login with the admin user created in (4.).

  1. In Domain List -> New Domain create a new domain domain.tld and enable create default aliases checkbox
  2. In Virtual List -> Add Mailbox create a new mailbox

9. Start and Test

Now start postfix, dovecot and spamd, and send some test mail from external account to your newly created mailbox. See postfix and dovecot logs if things arrive properly. Use some mail client (thunderbird, claws-mail etc) and configure your mailbox as IMAP account and the SMTP for sending.

10. Install roundcube

First, install the database schema

psql -U roundcube -d roundcube < /srv/http/roundcube/SQL/postgres.initial.sql

Then prepare the config

cd /srv/http/roundcube/config
cp db.inc.php.dist db.inc.php
cp main.inc.php.dist main.inc.php

In db.inc.php set the DSN like

$rcmail_config['db_dsnw'] = 'pgsql://roundcube:secret@localhost/roundcube';

In main.inc.php set

$rcmail_config['enable_installer'] = true;

Now point your browser to http://localhost/roundcube/installer/ and follow the instructions. Afterwards delete the installer folder.

You should be able to log into your mailbox account.

11. Setup fetchmail in postfixAdmin

BASH arrays and filenames with spaces

I'm sure I can use this one quite often.

1) Arrays are nice to avaoid temporaray files

2) Spaces in file names are a PITA. But there are nice ways to work around this

Array[0]="/some/path/to/mooo foo.txt"
Array[1]="/some/path/to/mooo foo bar 2.txt"
Array[2]="/some/path/to/mooo foo bar 3.txt"

There we have some example array.

for ((i=0;i<${#Array[@]};i++)); do echo ${Array[$i]}; done
/some/path/to/mooo foo.txt
/some/path/to/mooo foo bar 2.txt
/some/path/to/mooo foo bar 3.txt

Ok, now what if want to pass that to ls, we could quote it somehow. Or use some pattern expansion to replace the space with backslash space, like

for ((i=0;i<${#Array[@]};i++)); do echo ${Array[$i]// /\\ }; done
/some/path/to/mooo\ foo.txt
/some/path/to/mooo\ foo\ bar\ 2.txt
/some/path/to/mooo\ foo\ bar\ 3.txt

Great! Another way would be to temporarily change the special variable $IFS that determines which character is used for word splitting. Let's set this to "newline"

OLDIFS="$IFS"
IFS=$'\n'

for ((i=0;i<${#Array[$i]};i+=1)); do
   ls ${Array[$i]}
done

IFS="$OLDIFS"

That $IFS change can also be used in all sorts of other loops. Hell, I'm going to need that really often. Thanks to the guys on http://forums.gentoo.org/viewtopic-t-714971.html

Bash pattern matching

BASH offers a nice way to replace patterns. Until now I always used basename and a variable.
For example moving all .jpeg files in a folder to .jpg (hey, it's just an example..)

for moo in *.jpeg; do
    newname="`basename $moo .jpeg`.jpg"
    mv $moo $newname
done

But isn't that just plain ugly? That one is lot nicer:

for i in *.jpeg; do
    mv "$i" "${i%.*}.jpg"
done

1337

Howto connect OpenOffice to MS SQL server

Just had to connect to a MS SQL server that holds collected SAR statistics from our production servers.

Until now I used Toad in a virtual XP machine, but there has to be some way to connect in a graphical way from Linux too. And indeed there is!

Tools needed:

I chose JTDS, got the JAR file and copied it somehwere in the classpath. On OpenSUSE that is /usr/share/java. You can also add it in OpenOffice directly: Extras -> Options -> Java -> Classpath

Then fire up OpenOffice Base, and in the database wizard

  1. Open existing Database
  2. JDBC
jdbc:jtds:sqlserver://hostname:portnumber/databasename

The port number usually is 1433. The JDBC driver class is

net.sourceforge.jtds.jdbc.Driver

Then enter the db username, in the next step enter the password, and connect.

That's it.

 

Howto import SAR data into a PostgreSQL database and create graphs in OpenOffice.org

This is a walkthrough on how to get SAR data into a database, and use OpenOffice.org to create nice graphs using a JDBC connection to that database, and SUN Report Builder to do the graphs.

In this example I will use SAR's CPU utilisation data.

Software used:

 

1. Setup the Database

I use a PostgreSQL database named sar here. The SAR data is on the same host as the database, and the PostgreSQL user has read permission on the SAR files.

First we need to create a table

CREATE TABLE sar_cpu 
(
"host" varchar, 
"interval" numeric, 
"time" timestamp with time zone, 
"offset" numeric(1), 
"user" numeric(5,2), 
"nice" numeric(5,2), 
"system" numeric(5,2), 
"iowait" numeric(5,2), 
"steal" numeric(5,2), 
"idle" numeric(5,2)
)

 

 

2. Convert SAR data to CSV

Then we need to output the SAR data in a format we can load into the database, using sadf.

LC_ALL=en_US sadf -d /var/log/sa/sa15 -- -u > /tmp/sa20090215.csv

Note: The LC_ALL=en_US ensures that decimal values are seperated with a dot, not a comma.

 

3. Load the CSV directly into the database

Then we can load that CSV directly into the database:

echo "COPY sar_cpu FROM '/tmp/sa20090215.csv' DELIMITERS ';' CSV;"|psql -d sar

Cool, isn't it? This can be scripted easily and controlled via a cronjob, like import "yesterday's sar data, using a simple wrapper script and some date function.

 

4. Create an OpenOffice.org Base DB and connect it to PostgreSQL

Now start OOo Base, create a new DB -> JDBC.

See http://jdbc.postgresql.org/documentation/83/connect.html for an overwiev about the connection parameters:

URL:

jdbc:postgresql:sar

Class:

org.postgresql.Driver

 

5. Install SUN Report Builder

Then download SRB from http://extensions.services.openoffice.org/project/reportdesign, open Extras -> Extension Manager, and install it.

In OOo Base you'll find it in Reports -> Report in Design View

There you have the possibility to create graphs and diagrams as usual in Calc.

Howto use KDE4's device notifier to play a DVD in SMplayer

Just finally figured this one out! It's possible to add an entry to KDE4's device notifier, so you can just click & play a DVD in SMplayer. Awesome!

You need a very recent SMplayer and Mplayer, latter one compiled with dvdnav support.

  1. In SMplayer's preferences, go to mouse & keyboard -> mouse, and for left click select "Activate option in DVD menus".
  2. Create a file called smplayer-playdvd-predicate.desktop
    in $KDEDIR/share/apps/solid/actions, here that means /usr/kde/svn/share/apps/solid/actions/smplayer-playdvd-predicate.desktop, with following in it:
[Desktop Entry]
X-KDE-Solid-Predicate=[ StorageVolume.ignored == false AND OpticalDisc.availableContent == 'Data|VideoDvd' ]
Type=Service
Actions=open;

[Desktop Action open]
Name=Play DVD with SMplayer
Exec=smplayer dvdnav:////%d
Icon=smplayer

Now restart KDE, insert a DVD in your drive, or load DVD ISO image in cdemu, wait for the device notifier to pop up, and select.

Device notifier play DVD in SMplayer

That's it!

Howto: Convert avi/mov/any video to Flash/flv on Linux

Recently I wanted to convert a Quicktime .mov video to Flash .flv in order to post it on this page, for the fun of it.
First thought: uuuh how do I do this on Linux? But it's pretty simple, thanks to ffmpeg. Works fine with anything that ffmpeg can play, so avi, mpeg, wmv or whatever.

It's as simple as:

ffmpeg -i input.avi -s 320x240 -ar 44100 -o movie.flv

There is also a nice tool to add metadata info like duration etc to flv files, called flvtool2.

cat movie.flv | flvtool2 -U stdin movie.flv

Now your flv has duration info and is ready for the website.

Howto: Log firewall from OpenWrt to a remote rsyslog

At Planethome I'm currently setting up a central logserver, using rsyslog. So to get familiar with it, I installed it on my Gentoo box at home, set it as default syslog daemon, and feed it with data from my router running OpenWrt Kamikaze 8.09 RC1.

On the server (Gentoo) side, I enabled remote logging over UDP. On the client (OpenWrt) side a little bit more had to be done

1) Enable remote logging

Edit /etc/config/system and enable remote logging by adding:

option 'log_ip' '192.168.1.2'

Now reboot the router and see if it logs correctly.

2) -j LOG ++

Then I had to get IPtables to produce some log output. With Kamikaze's new firewall config layout this was a bit tricky. I decided to just log SYN flood protection actions, and the dropping of INVALID packets on INPUT and FORWARD chains. Therefore we need to edit /lib/firewall/uci_firewall.sh and add 3 lines (those with -j LOG)

In function fw_defaults()

$IPTABLES -A INPUT -m state --state INVALID -j LOG --log-prefix "DROP INVALID (INPUT): "
$IPTABLES -A INPUT -m state --state INVALID -j DROP
...
$IPTABLES -A FORWARD -m state --state INVALID -j LOG --log-prefix "DROP INVALID (FORWARD): "
$IPTABLES -A FORWARD -m state --state INVALID -j DROP

and for the SYN flood stuff, in function load_synflood()

$IPTABLES -A syn_flood -j LOG --log-prefix "SYN FLOOD: "
$IPTABLES -A syn_flood -j DROP

 

Howto: receive mail and save attachment with fetchmail, procmail and metamail

At work I recently had to set up a solution that periodically checks a POP3 account on our M$ Exchange wannabe mailserver, and saves the attachments to some folder for further processing. As I didn't find a ready-to-go-solution for this on the web, just snippets here and there, and of course hundrets of other people asking the same, here it is.

You will need

  • fetchmail
  • procmail
  • metamail (or uudeview, see first comment below)

In this example I'll use a POP3 account, the full mail will be backed up to ~/mail_backup, and attachments will be unpacked to ~/attachments. fetchmail also handles IMAP accounts just fine. Please refer to the fetchmail documentation.

Setting up fetchmail

First create a file $HOME/.fetchmailrc

poll my.pop3.server 
protocol pop3 
user 'myuser' 
password 'mypassword' 
mda '/usr/bin/procmail -d %T'

 

Setting up procmail and metamail

Then we configure procmail so it forwards the messages to metamail in $HOME/.procmailrc

:0
*^content-Type:
{
        # backup the complete mail first..
        # you can leave out this part if you don't want a backup of the complete mail
        :0c:
        $HOME/mail_backup

        # Now the actual unpacking part
        #
        # this is the place where the attachments will be unpacked to
        METAMAIL_TMPDIR=$HOME/attachments

        # forward to metamail
        :0fw
        | metamail -w -y -x
}

Regarding metamail, we tell it to ignore any mailcap file, so it doesn't use interpreters (-w), yanking the message and save the content raw (-y) and force it in non-interactive mode (-x).

That's it about it. We are ready for testing.

Test run

Now we simply fire up fetchmail, the rest should be magic.

fetchmail -kv

HTH

Tags: 

Howto create a youtube video from mp3/ogg audio using a picture

If you want to create a youtube video from an audio file, here is how to do this.
All you need is the audio file, a single picture, and ffmpeg.

First find out the lenght of the audio file in seconds, you'll need it. Here is an example with a 420 seconds file:

ffmpeg -loop_input -i picture.jpg -vcodec mpeg4 -r 25.00 -qscale 2 -s 480x360 \
-i audiofile.mp3 -acodec libmp3lame -ab 128k -t 420 video.avi

This will create a Hi-Res MPEG-4 video with 128k audio. The trick here is to use that one picture and loop it for -t seconds.