Table of Contents

Steps used to install my Ubuntu server on Linode (UK)

Basic

Reference Docs

http://library.linode.com/advanced/migrate-server-to-linode
http://library.linode.com/networking/rdiff-backup-sshfs
http://library.linode.com/
http://articles.slicehost.com/ubuntu-intrepid
Checkout the DokuWiki plugins http://www.dokuwiki.org/plugins
http://library.linode.com/web-servers/nginx/php-fastcgi-ubuntu9.10-karmic

For Mail Filtering http://wiki.dovecot.org/LDA/Sieve

http://www.kirya.net/articles/setting-up-dspam-as-a-filter-for-postfix-on-debian-etch/
http://yoonkit.blogspot.com/2008/05/dspam-webgui-modifications-javascript.html
http://www.directadmin.com/forum/showthread.php?t=16015
http://diymacserver.com/installing-the-mailserver/adding-a-spam-filter/purging-the-dspam-database-automatically/

http://209.85.129.132/search?q=cache:dzru2MmA7zQJ:github.com/kuroneko/dspam+dspam+domain+dictionary&cd=9&hl=en&ct=clnk&client=safari

MySQL & phpMyAdmin

  1. Installed the following packages
    apt-get install mysql-server mysql-client phpMyAdmin
  2. In the post install phase, set a password for both the mysql root user and for phpmyadmin
  3. Then
    mkdir -p ./srv/www/pma.tarasis.net/logs
    ln -s /usr/share/phpmyadmin /srv/www/pma.tarasis.net/public
    
  4. Enable SSL support in NGINX
  5. Create SSL server certificates (or install existing ones if you have them)
  6. Create the NGINX conf for the site
    nano /etc/nginx/sites-available/pma.tarasis.net

    and then:

    server {
    }
    
  7. Enable the site
  8. restart NGINX

Web

Went with NGINX again (as Slicehost), this time with the stock Ubuntu version, not custom built.

NGINX

Basically per the initial instructions on Linode

  1. Update you
    /etc/apt/sources.list

    to be similar too

    ## main & restricted repositories
    deb http://us.archive.ubuntu.com/ubuntu/ karmic main restricted universe multiverse
    deb-src http://us.archive.ubuntu.com/ubuntu/ karmic main restricted universe multiverse
    
    deb http://security.ubuntu.com/ubuntu karmic-security main restricted universe multiverse
    deb-src http://security.ubuntu.com/ubuntu karmic-security main restricted universe multiverse
    
    deb http://security.ubuntu.com/ubuntu karmic-updates main restricted universe multiverse
    deb-src http://security.ubuntu.com/ubuntu karmic-updates main restricted universe multiverse
  2. Then issue the following to update the catalog files, upgrade the non essential packages and then install the required packages
    apt-get update
    apt-get upgrade
    apt-get install nginx php5-cli php5-cgi build-essential wget

NOTE While trying to figure out what was causing some problems I installed the latest dev release via the instructions on the NGINX site:

Ubuntu PPA
Jeff Waugh maintains recent versions of Nginx in his PPA.

echo "deb http://ppa.launchpad.net/jdub/devel/ubuntu hardy main" >> /etc/apt/sources.list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E9EEF4A1
apt-get update 
apt-get install nginx

I should likely revert to the stock Ubuntu release.

PHP

For providing PHP sites I have followed the steps Nginx and PHP-FastCGI on Ubuntu 9.10 (Karmic)

Well I did but as I kept getting 502 Bad Gateway errors, I thought I would go back to the setup I used on Slicehost which doesn't use spawn-fcgi.

  1. Create a defaults file
    nano /etc/default/php-fcgi

    into which you place the following

    #
    # Settings for php-cgi in external FASTCGI Mode
    #
    
    # Should php-fastcgi run automatically on startup? (default: no)
    
    START=yes
    
    # Which user runs PHP? (default: www-data)
    
    EXEC_AS_USER=www-data
    # Host and TCP port for FASTCGI-Listener (default: localhost:9000)
    
    FCGI_HOST=localhost
    FCGI_PORT=9000
    
    # Environment variables, which are processed by PHP
    
    PHP_FCGI_CHILDREN=2
    PHP_FCGI_MAX_REQUESTS=500
  2. Next create
    nano /etc/init.d/php-fastcgi

    and put the following in

    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides:          php-fastcgi
    # Required-Start:    $all
    # Required-Stop:     $all
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: Start and stop php-cgi in external FASTCGI mode
    # Description:       Start and stop php-cgi in external FASTCGI mode
    ### END INIT INFO
    
    # Author: Kurt Zankl <kz@xon.uni.cc>
    
    # Do NOT "set -e"
    
    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    DESC="php-cgi in external FASTCGI mode"
    NAME=php-fastcgi
    DAEMON=/usr/bin/php-cgi
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME
    PHP_CONFIG_FILE=/etc/php5/cgi/php.ini
    
    # Exit if the package is not installed
    [ -x "$DAEMON" ] || exit 0
    
    # Read configuration variable file if it is present
    [ -r /etc/default/$NAME ] && . /etc/default/$NAME
    
    # Load the VERBOSE setting and other rcS variables
    #. /lib/init/vars.sh
    
    # Define LSB log_* functions.
    # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
    . /lib/lsb/init-functions
    
    # If the daemon is not enabled, give the user a warning and then exit,
    # unless we are stopping the daemon
    if [ "$START" != "yes" -a "$1" != "stop" ]; then
            log_warning_msg "To enable $NAME, edit /etc/default/$NAME and set START=yes"
            exit 0
    fi
    
    # Process configuration
    export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS
    DAEMON_ARGS="-q -b $FCGI_HOST:$FCGI_PORT -c $PHP_CONFIG_FILE"
    
    
    do_start()
    {
            # Return
            #   0 if daemon has been started
            #   1 if daemon was already running
            #   2 if daemon could not be started
            start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
                    || return 1
            start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON \
                    --background --make-pidfile --chuid $EXEC_AS_USER --startas $DAEMON -- \
                    $DAEMON_ARGS \
                    || return 2
    }
    
    do_stop()
    {
            # Return
            #   0 if daemon has been stopped
            #   1 if daemon was already stopped
            #   2 if daemon could not be stopped
            #   other if a failure occurred
            start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE > /dev/null # --name $DAEMON
            RETVAL="$?"
            [ "$RETVAL" = 2 ] && return 2
            # Wait for children to finish too if this is a daemon that forks
            # and if the daemon is only ever run from this initscript.
            # If the above conditions are not satisfied then add some other code
            # that waits for the process to drop all resources that could be
            # needed by services started subsequently.  A last resort is to
            # sleep for some time.
            start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
            [ "$?" = 2 ] && return 2
            # Many daemons don't delete their pidfiles when they exit.
            rm -f $PIDFILE
            return "$RETVAL"
    }
    
    case "$1" in
      start)
            [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
            do_start
            case "$?" in
                    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
            esac
            ;;
      stop)
            [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
            do_stop
            case "$?" in
                    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
            esac
            ;;
      restart|force-reload)
            log_daemon_msg "Restarting $DESC" "$NAME"
            do_stop
            case "$?" in
              0|1)
                    do_start
                    case "$?" in
                            0) log_end_msg 0 ;;
                            1) log_end_msg 1 ;; # Old process is still running
                            *) log_end_msg 1 ;; # Failed to start
                    esac
                    ;;
              *)
                    # Failed to stop
                    log_end_msg 1
                    ;;
            esac
            ;;
      *)
            echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
            exit 3
            ;;
    esac
    
  3. Then issue the following commands to make php-fcgi launch on startup & run it now
    chmod 755 /etc/init.d/php-fastcgi
    update-rc.d php-fastcgi defaults
    /etc/init.d/php-fastcgi start

XCACHE

apt-get install php5-xcache

Edit

/etc/php5/conf.d/xcache.ini

to (remembering to change username & password)

# configuration for php Xcache module

[xcache-common]
;; install as zend extension (recommended), normally "$extension_dir/xcache.so"
zend_extension = /usr/lib/php5/20060613+lfs/xcache.so

[xcache.admin]
xcache.admin.enable_auth = On
# Configure this to use admin pages
xcache.admin.user = "AUSER"
; xcache.admin.pass = md5($your_password)
xcache.admin.pass = "AN MD5'd PASSWORD"

[xcache]
; ini only settings, all the values here is default unless explained

; select low level shm/allocator scheme implemenation
xcache.shm_scheme =        "mmap"
; to disable: xcache.size=0
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
xcache.size  =                64M
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
xcache.count =                 4
; just a hash hints, you can always store count(items) > slots
xcache.slots =                8K
; ttl of the cache item, 0=forever
xcache.ttl   =                 0
; interval of gc scanning expired items, 0=no scan, other values is in seconds
xcache.gc_interval =           0

; same as aboves but for variable cache
xcache.var_size  =            64M
xcache.var_count =             4
xcache.var_slots =            8K
; default ttl
xcache.var_ttl   =             0
xcache.var_maxttl   =          0
xcache.var_gc_interval =     300

xcache.test =                Off
; N/A for /dev/zero
xcache.readonly_protection = Off
; for *nix, xcache.mmap_path is a file path, not directory.
; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection
; 2 group of php won't share the same /tmp/xcache
; for win32, xcache.mmap_path=anonymous map name, not file path
xcache.mmap_path =    "/dev/zero"


; leave it blank(disabled) or "/tmp/phpcore/"
; make sure it's writable by php (without checking open_basedir)
xcache.coredump_directory =   ""

; per request settings
xcache.cacher =               On
xcache.stat   =               On
xcache.optimizer =            On

[xcache.coverager]
; per request settings
; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance)
xcache.coverager =          Off

; ini only settings
; make sure it's readable (care open_basedir) by coverage viewer script
; requires xcache.coverager=On
xcache.coveragedump_directory = ""

Setup a vhost for xcache



Note for my type of vps do I really need this? what are the best mem options? 32mb?

wiki.tarasis.net

  1. Copied data off Slicehost using
    rsync -aHSKDvz -e ssh wiki.tarasis.net AUSER@109.74.199.95:/srv/www
  2. Upgraded DokuWiki version to latest stable release per http://www.dokuwiki.org/install:upgrade
  3. Created
    /etc/nginx/sites-available/wiki.tarasis.net
  4. Add the following which tells NGINX about the website, where to put the logs, denies access to the .htaccess files (though they aren't used as NGINX doesn't support them) and defines the rewrite rules for having clean urls.
    server {
        listen   80;
        server_name wiki.tarasis.net;
        access_log /srv/www/wiki.tarasis.net/logs/access.log;
        error_log /srv/www/wiki.tarasis.net/logs/error.log;
    
        location ~ /\.ht {
            deny  all;
        }
    
        root   /srv/www/wiki.tarasis.net/public/;
    
        rewrite ^(/)_media/(.*) $1lib/exe/fetch.php?media=$2 last;
        rewrite ^(/)_detail/(.*) $1lib/exe/detail.php?media=$2 last;
        rewrite ^(/)_export/([^/]+)/(.*) $1doku.php?do=export_$2&id=$3 last;
    
        if (!-f $request_filename) {
            rewrite ^(/)(.*)?(.*)  $1doku.php?id=$2&$3 last;
            rewrite ^(/)$ $1doku.php last;
        }
    
        location ~ \.php$ {
            include /etc/nginx/fastcgi_params;
            fastcgi_pass  127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param  SCRIPT_FILENAME  /srv/www/wiki.tarasis.net/public$fastcgi_script_name;
        }
    }
    
  5. Edit
    /srv/www/wiki.tarasis.net/public/conf/local.php

    and add

    $conf['userewrite'] = 1;
    

    which tells dokuwiki to use clean urls and that the webserver will be handling it.

  6. Make the site available for NGINX and then restart it.
    ln -s /etc/nginx/sites-available/wiki.tarasis.net /etc/nginx/sites-enabled
    /etc/init.d/nginx restart

tarasis.net

Basically a Blog running Wordpress

pma.tarasis.net

phpMyAdmin

Mail

Existing setup is Exim (using vexim for vhosts), Dovecot, dspam & clamd

Considering going Postfix (with postfixadmin for vhosts), dovecot and not sure about Antispam & antivirus this time around.

Using combination of

Step 1

Install Postfix & Dovecot-imap3d

root@indy:~# aptitude install postfix postfix-mysql
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Initializing package states... Done
Writing extended state information... Done
The following NEW packages will be installed:
  postfix postfix-mysql ssl-cert{a} 
0 packages upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 1359kB of archives. After unpacking 3457kB will be used.
Do you want to continue? [Y/n/?] y
Writing extended state information... Done
Get:1 http://us.archive.ubuntu.com karmic/main ssl-cert 1.0.23ubuntu2 [10.9kB]
Get:2 http://us.archive.ubuntu.com karmic/main postfix 2.6.5-3 [1304kB]
Get:3 http://us.archive.ubuntu.com karmic/main postfix-mysql 2.6.5-3 [44.0kB]
Fetched 1359kB in 0s (6043kB/s)  
Preconfiguring packages ...
Selecting previously deselected package ssl-cert.
(Reading database ... 20776 files and directories currently installed.)
Unpacking ssl-cert (from .../ssl-cert_1.0.23ubuntu2_all.deb) ...
Selecting previously deselected package postfix.
Unpacking postfix (from .../postfix_2.6.5-3_i386.deb) ...
Selecting previously deselected package postfix-mysql.
Unpacking postfix-mysql (from .../postfix-mysql_2.6.5-3_i386.deb) ...
Processing triggers for man-db ...
Setting up ssl-cert (1.0.23ubuntu2) ...

Setting up postfix (2.6.5-3) ...
Adding group `postfix' (GID 108) ...
Done.
Adding system user `postfix' (UID 105) ...
Adding new user `postfix' (UID 105) with group `postfix' ...
Not creating home directory `/var/spool/postfix'.
Creating /etc/postfix/dynamicmaps.cf
Adding tcp map entry to /etc/postfix/dynamicmaps.cf
Adding group `postdrop' (GID 109) ...
Done.
setting myhostname: indy
setting alias maps
setting alias database
changing /etc/mailname to daffy.tarasis.net
setting myorigin
setting destinations: daffy.tarasis.net, indy, localhost.localdomain, localhost
setting relayhost: 
setting mynetworks: 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
setting mailbox_size_limit: 0
setting recipient_delimiter: +
setting inet_interfaces: all
/etc/aliases does not exist, creating it.
WARNING: /etc/aliases exists, but does not have a root alias.

Postfix is now set up with a default configuration.  If you need to make 
changes, edit
/etc/postfix/main.cf (and others) as needed.  To view Postfix configuration
values, see postconf(1).

After modifying main.cf, be sure to run '/etc/init.d/postfix reload'.

When it asks set the system mail name to

System mail name: daffy.tarasis.net

NOTE Need to change the myhostname: indy

Next Dovecot

root@indy:/etc/postfix# aptitude install dovecot-postfix
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Reading extended state information      
Initializing package states... Done
The following NEW packages will be installed:
  dovecot-common{a} dovecot-imapd{a} dovecot-pop3d{a} dovecot-postfix libpq5{a} 
0 packages upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 5879kB of archives. After unpacking 11.5MB will be used.
Do you want to continue? [Y/n/?] y

Install Amavisd-new

root@indy:/etc/dovecot# aptitude install amavisd-new
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Reading extended state information      
Initializing package states... Done
The following NEW packages will be installed:
  amavisd-new libarchive-zip-perl{a} libberkeleydb-perl{a} libconvert-binhex-perl{a} libconvert-tnef-perl{a} libconvert-uulib-perl{a} libcrypt-openssl-bignum-perl{a} 
  libcrypt-openssl-rsa-perl{a} libdigest-hmac-perl{a} libdigest-sha1-perl{a} liberror-perl{a} libio-multiplex-perl{a} libio-stringy-perl{a} libmail-dkim-perl{a} 
  libmailtools-perl{a} libmime-tools-perl{a} libnet-cidr-perl{a} libnet-dns-perl{a} libnet-ip-perl{a} libnet-server-perl{a} libunix-syslog-perl{a} pax{a} 
The following packages are RECOMMENDED but will NOT be installed:
  libcompress-raw-zlib-perl 

Install Spamassassin, spamc, Postgrey

root@indy:/etc/dovecot# aptitude install spamassassin spamc postgrey
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Reading extended state information      
Initializing package states... Done
The following NEW packages will be installed:
  libhtml-tree-perl{a} libsocket6-perl{a} libsys-hostname-long-perl{a} libwww-perl{a} postgrey spamassassin spamc 
The following packages are RECOMMENDED but will NOT be installed:
  libcompress-bzip2-perl libhtml-format-perl libio-socket-inet6-perl libmail-spf-perl libnet-rblclient-perl libparse-syslog-perl re2c 

For testing

root@daffy:~# aptitude install mailx telnet

Forgot this step

Set the server name to daffy.tarasis.net

root@indy:~# nano /etc/hostname
 
root@indy:~# nano /etc/hosts

Also setup the Reverse DNS on Linode (Linode>duemoko>Network)

IP Address	RDNS
109.74.199.95	 daffy.tarasis.net

Step 2

root@daffy:~# dpkg-reconfigure postfix
 * Stopping Postfix Mail Transport Agent postfix
   ...done.
setting synchronous mail queue updates: false
setting myorigin
setting destinations: daffy.tarasis.net, tarasis.net, localhost.localdomain, localhost
setting relayhost: 
setting mynetworks: 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
setting mailbox_size_limit: 0
setting recipient_delimiter: +
setting inet_interfaces: all
setting inet_protocols: ipv4
WARNING: /etc/aliases exists, but does not have a root alias.

Install Postfix Admin

Download the lastest version (for me 2.3), after untarring it. Move it to the right place

root@daffy:~/source# mkdir -p /srv/www/pfa.tarasis.net/logs
root@daffy:~/source# mv postfixadmin-2.3/ /srv/www/pfa.tarasis.net/public

Fix the file ownership

root@daffy:~/source# cd /srv/www/pfa.tarasis.net/
root@daffy:/srv/www# chown -R www-data:www-data public/

Create a NGNIX config file for it and restart

nano /etc/nginx/sites-available/pfa.tarasis.net

server {
  listen 80;
  server_name pfa.tarasis.net;

  access_log /srv/www/pfa.tarasis.net/logs/access.log;
  error_log /srv/www/pfa.tarasis.net/logs/error.log;

  location / {
    index index.php index.html;
    root /srv/www/pfa.tarasis.net/public;
  }

  # redirect postfixadmin to the https page
  location ~\.php$ {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /srv/www/pfa.tarasis.net/public$fastcgi_script_name;
  }
}

#save it and symlink it and restart nginx
ln -s /etc/nginx/sites-available/pfa.tarasis.net /etc/nginx/sites-enabled/
/etc/init.d/nginx restart

Create a Database for postfixadmin. Using the command line

mysql -p

Then (remembering to set a real password)

  CREATE DATABASE postfix;
  CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'choose_a_password';
  GRANT ALL PRIVILEGES ON `postfix` . * TO 'postfix'@'localhost';

Next edit config.inc.php and change the following lines to:

$CONF['configured'] = false;       << true
$CONF['postfix_admin_url'] = '';   << http://pfa.tarasis.net
$CONF['setup_password'] = 'postfixadmin';  <<

$CONF['database_type'] = 'mysql';  << mysqli
 
$CONF['database_password'] = 'postfixadmin'; << the password

$CONF['default_aliases'] = array (
    'abuse' => 'abuse@change-this-to-your.domain.tld',
    'hostmaster' => 'hostmaster@change-this-to-your.domain.tld',
    'postmaster' => 'postmaster@change-this-to-your.domain.tld',
    'webmaster' => 'webmaster@change-this-to-your.domain.tld'
);

$CONF['domain_path'] = 'NO';  << YES
$CONF['domain_in_mailbox'] = 'YES';  << NO

$CONF['mailboxes'] = '10'; << 20

Goto http://pfa.tarasis.net/setup.php, should be lots of okays and so on. One error is that php5-imap module is not installed and then restart php so that the new module is picked up

aptitude install php5-imap
/etc/init.d/php-fastcgi restart

Now return to setup.php and add a Setup password & admin user. When you click Add Admin it will complain password is not in the right format and copy the password hash into the config.inc.php file. Reload the page and the admin user is created.

NOTE “Warning: Magic Quotes: ON (internal workaround used)” « checkout if this is a problem

Add a user & group for the mail

groupadd virtual -g 5000
useradd virtual -u 5000 -g 5000
chown -R virtual:virtual /srv/mail

Next create the files which will give Postfix access to the DB with the aliases. Remember to change THE_PASSWORD to the real password.

root@daffy:/etc/postfix$ nano mysql_virtual_alias_maps.cf

user = postfix
password = THE_PASSWORD
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = 1

root@daffy:/etc/postfix# nano mysql_virtual_domains_maps.cf

user = postfix
password = THE_PASSWORD
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'

root@daffy:/etc/postfix# nano mysql_virtual_mailbox_maps.cf

user = postfix
password = THE_PASSWORD
hosts = localhost
dbname = postfix
#query = SELECT CONCAT(domain,'/',maildir) FROM mailbox WHERE username='%s' AND active = 1
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1

root@daffy:/etc/postfix# nano mysql_virtual_mailbox_limit_maps.cf

user = postfix
password = THE_PASSWORD
hosts = localhost
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s'

root@daffy:/etc/postfix# nano mysql_relay_domains_maps

user = postfix
password = THE_PASSWORD
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'

Install & Configure Dovecot

Create a sql conf file so Dovecot knows how to find the users. In /etc/dovecot/ create dovecot-mysql.conf

driver = mysql
connect = dbname=postfix user=postfix host=localhost password=!postfixadmin*
default_pass_scheme = md5-crypt

user_query = SELECT maildir, maildir AS home, 5000 AS uid, 5000 AS gid FROM mailbox WHERE username  = '%u' AND active = '1'
password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = '1'

# Later two lines are from http://www.miphol.com/muse/2009/06/setting-up-a-lightweight-mail.html, keeping around for ideas.
#user_query = SELECT '/home/vmail/%u' as home, 'maildir:/home/vmail/%u' as mail, 5000 AS uid, 12 AS gid, concat('*:storage=', quota, 'M') AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'

#password_query = SELECT username as user, password, '/home/vmail/%u' as userdb_home, 'maildir:/home/vmail/%u' as userdb_mail, 5000 as userdb_uid, 12 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'

Configure /etc/dovecot/dovecot.conf

Note mailfiltering disabled for the moment.

protocols = imap imaps
listen = *
ssl_disable = no
ssl_cert_file = /etc/ssl/certs/myssl.crt
ssl_key_file = /etc/ssl/private/myssl.key

# the trailing Maildir is left over from when mail was handled by Exim / Courier
# given Dovecot can handle it by appending Maildir I shall simply do that.
mail_location = maildir:/srv/mail/%d/%n/Maildir

first_valid_uid = 5000
last_valid_uid = 5000
first_valid_gid = 5000
last_valid_gid = 5000

Uncomment #protocol ldap {

  postmaster_address = postmaster@tarasis.net

  auth_socket_path = /var/run/dovecot/auth-master

  # Enabling Sieve plugin for server-side mail filtering
  mail_plugins = cmusieve
  
  #sieve_global_dir = /srv/mail/
  global_script_path = /srv/mail/.dovecot.sieve
  
  log_path = /var/log/dovecot-deliver.log
  info_log_path = /var/log/dovecot-deliver.log
Uncomment } at end of ldap block

Comment out the passdb pam block

In auth default {

  mechanisms = digest-md5 plain login

  passdb sql {
    # Path for SQL configuration file
    args = /etc/dovecot/dovecot-mysql.conf
  }
  
  userdb sql {
    # Path for SQL configuration file
    args = /etc/dovecot/dovecot-mysql.conf
  }  

user = nobody

  socket listen {
    master {
      # Master socket provides access to userdb information. It's typically
      # used to give Dovecot's local delivery agent access to userdb so it
      # can find mailbox locations.
      path = /var/run/dovecot/auth-master
      mode = 0660
      # Default user/group is the one who started dovecot-auth (root)
      user = virtual 
      group = virtual
    }
    client {
      # The client socket is generally safe to export to everyone. Typical use
      # is to export it to your SMTP server so it can do SMTP AUTH lookups
      # using it.
      path = /var/spool/postfix/private/auth
      mode = 0660
	  user = postfix
	  group = postfix
    }
  }
  
At the very end add so that the sieve knowns where to find my sieve file (replaces procmail)

plugin {
 # NOTE: %variable expansion works only with Dovecot v1.0.2+
 sieve = /srv/mail/%d/%n/.dovecot.sieve
}

Add the following to the end of /etc/postfix/master.cf to have postfix use Dovecot for delivery

dovecot   unix  -       n       n       -       -       pipe
        flags=DRhu user=virtual:virtual argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}

Next edit /etc/postfix/main.cf to this. This version permits SASL, TLS and Virtual Mail via Dovecot

# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
delay_warning_time = 4h

readme_directory = no

myhostname = daffy.tarasis.net
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = daffy.tarasis.net, daffy, localhost.localdomain, localhost
relayhost = 
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

home_mailbox = 
smtpd_sender_restrictions = 

mailbox_command = 

# Per http://bliki.rimuhosting.com/space/knowledgebase/linux/mail/postfixadmin+on+debian+sarge
# ---- Virtual Domains / account handling ----
virtual_mailbox_base = /srv/mail/

# The domains we accept mail for
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf

# Determine mailbox location
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

virtual_transport = dovecot
dovecot_destination_recipient_limit = 1

# ---- TLS parameters ----
smtp_tls_cert_file=/etc/ssl/certs/myssl.crt
smtp_tls_key_file=/etc/ssl/private/myssl.key
smtpd_tls_cert_file=/etc/ssl/certs/myssl.crt
smtpd_tls_key_file=/etc/ssl/private/myssl.key

smtpd_tls_security_level = may
smtpd_tls_received_header = yes
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_tls_mandatory_protocols = SSLv3, TLSv1
smtpd_tls_mandatory_ciphers = medium

inet_protocols = ipv4

tls_random_source = dev:/dev/urandom

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

# ---- support SASL2 ----
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_authenticated_header = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination

Test for open relays

From the Linode

telnet rt.njabl.org 2500

It will then run a barrage of relay tests against the server. Check that none are allowed.

root@daffy:~# telnet rt.njabl.org 2500
Trying 69.28.95.130...
Connected to rt.njabl.org.
Escape character is '^]'.
<snip>

<<< 250 DSN
>>> MAIL FROM:<relaytestsend@rt.njabl.org>
<<< 250 2.1.0 Ok
>>> RCPT TO:<relaytest@rr.njabl.org>
<<< 554 5.7.1 <relaytest@rr.njabl.org>: Relay access denied
>>> RSET
<<< 250 2.0.0 Ok
<snip>
>>> RCPT TO:<relaytest%rr.njabl.org@daffy.tarasis.net>
<<< 554 5.7.1 <relaytest%rr.njabl.org@daffy.tarasis.net>: Relay access denied
Can't relay 
Connection closed by foreign host.

Next Goto http://www.abuse.net/relay.html and enter the server name as the address to test and press “Test For Relay”. Again it should complete the tests without any relays being allowed.

Configure Postgrey

Edit the config file /etc/default/postgrey to change the default delay (countdown from 3)

root@daffy:~# nano /etc/default/postgrey 

POSTGREY_OPTS="--inet=10023 --delay=<A DELAY>"

Tell Postfix to use Postgrey by adding check_policy_service inet:127.0.0.1:10023 in /etc/postfix/main.cf

smtpd_recipient_restrictions = 	permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, 
								check_policy_service inet:127.0.0.1:10023, permit

NOTE Consider putting the delay back up to 300 or even increase it. Though people don't tend to want their mail delayed 5 minutes at first.

Tweaking Postfix for Anti-Spam measures

http://dman13.dyndns.org/~dman/config_docs/antispam-postfix/node3.html
http://www.mail-archive.com/postfix-users@postfix.org/msg07601.html for some check_helo_access examples
http://www.linuxquestions.org/questions/linux-server-73/how-to-configure-postfix-to-reject-spams-474799/

Install & Configure Amavis-New, Clamav, Spamassassin / DSPAM

Building DSPAM

Ubuntu comes with DSPAM 3.6.8 which is rather old now, so I am going to build the very recent release of DSPAM 3.9.0

The following additional packages need to be installed:

root@daffy:/opt# aptitude install libmysqlclient16-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Reading extended state information      
Initializing package states... Done
The following NEW packages will be installed:
  libmysqlclient-dev{a} libmysqlclient16-dev zlib1g-dev{a} 

Add the dspam group and user

root@daffy:/opt# groupadd dspam
root@daffy:/opt# useradd -M -s /sbin/nologin -g dspam dspam

Now configure the package, with the mysql driver, to locate it in /opt, to enable the daemon mode and virtual users

./configure --enable-domain-scale --with-storage-driver=mysql_drv,hash_drv --prefix=/opt --enable-daemon --enable-virtual-users --enable-preferences-extension --enable-clamav --with-mysql-libraries=/usr/lib/mysql/ --with-mysql-includes=/usr/include/mysql/ --with-dspam_owner=dspam --with-dspam_group=dspam --enable-debug

Now make and install it & the webui

root@daffy:~/dspam-3.9.0# make && make install
root@daffy:~/dspam-3.9.0# cp -a webui /opt/var/dspam

Change the ownership of the dspam files /opt/var/dspam

root@daffy:/opt/var# chown -R dspam:dspam dspam

Create the dspam database and add a dspam user to the db

root@daffy:~/dspam-3.9.0/src/tools.mysql_drv# mysqladmin -u root -p create dspam
root@daffy:~/dspam-3.9.0/src/tools.mysql_drv# mysql -u root -p

mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON dspam.* TO 'dspam'@'localhost' IDENTIFIED BY 'A PASSWORD';

Inject the db tables

root@daffy:~/dspam-3.9.0/src/tools.mysql_drv# mysql -u root -p dspam < mysql_objects-4.1.sql
Enter password: 
root@daffy:~/dspam-3.9.0/src/tools.mysql_drv# mysql -u root -p dspam < virtual_users.sql    
Enter password: 

We will need root@daffy:~/dspam-3.9.0/src/tools.mysql_drv# less purge-4.1.sql later for purging the dspam db nightly of unneeded tokens.

Next edit /opt/etc/dspam.conf and change the MySQL lines as follows

MySQLServer             /var/run/mysqld/mysqld.sock
#MySQLPort
MySQLUser               dspam
MySQLPass               A PASSWORD
MySQLDb                 dspam
MySQLCompress           true
MySQLReconnect          true

Edit /etc/default/dspam and set start to yes

START=YES

For notes, installing dspam package adds following entries to file system and doesn't remove them when the dspam package is removed. Handy :)

added dspam
added cron.daily/dspam
added default/dspam
added dspam/default.prefs
added dspam/dspam.conf
added dspam/dspam.d
added init.d/dspam
added logrotate.d/dspam
added rc0.d/K21dspam
added rc1.d/K21dspam
added rc2.d/S21dspam
added rc3.d/S21dspam
added rc4.d/S21dspam
added rc5.d/S21dspam
added rc6.d/K21dspam

Configure DSPAM

Edit /opt/etc/dspam.conf

Trust postfix
Trust www-data

Feature chained

Preference "spamAction=tag"	# { quarantine | tag | deliver } -> default:quarantine
Preference "signatureLocation=headers"	# { message | headers } -> default:message
Preference "tagSpam=on"		# { on | off }

DeliveryHost		127.0.0.1
DeliveryPort		10024
DeliveryIdent		localhost
DeliveryProto		SMTP

#ServerHost		127.0.0.1
#ServerPort		11124
#ServerQueueSize	32
ServerDomainSocketPath	"/var/run/dspam/dspam.sock"

ServerPID		/var/run/dspam/dspam.pid
ServerMode auto

ServerParameters	"--deliver=innocent,spam"
ServerIdent		"localhost.localdomain"

ParseToHeaders on
ChangeModeOnParse on
ChangeUserOnParse full

TrackSources spam nonspam virus


Start dspam

Quickly edit /etc/init.d/dspam and make following edits.

PATH=/opt/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/bin/$NAME

CHANGE THE LEFT OVER DSPAM INIT SCRIPT

Then

/etc/init.d/dspam start

—- TIDY THIS UP —-

In Postfix main.cf, add the following to your smtpd_recipient_restrictions:

smtpd_recipient_restrictions = 
  [...]
  check_recipient_access pcre:/etc/postfix/dspam_filter_access

 where dspam_filter_access contains:

/./ FILTER dspam:dspam

 Add he following service at the end of master.cf:

dspam                 unix    -       n       n       -       -    pipe
  flags=Ru user=dspam argv=/usr/bin/dspam
  --client
  --deliver=innocent,spam
  --user ${recipient}
  --mail-from=${sender}

 You will also have to add the following line in main.cf:
dspam_destination_recipient_limit = 1


Step 3: Configure a reinjection port

  You'll also need to configure Postfix to listen on a local port for
  reinjection. This is where DSPAM sends back the "good" mail (or alternatively,
  tagged mail also). Add this to your master.cf:

localhost:10026 inet  n -       n       -       -        smtpd
  -o content_filter=
  -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
  -o smtpd_helo_restrictions=
  -o smtpd_client_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8
  -o smtpd_authorized_xforward_hosts=127.0.0.0/8

WEB UI

Need to install the following perl libraries

root@daffy:/opt/var/dspam/webui/cgi-bin# aptitude install libgd-gd2-noxpm-perl libgd-gd2-perl libgd-graph3d-perl
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Reading extended state information      
Initializing package states... Done
Writing extended state information... Done
The following NEW packages will be installed:
  libgd-gd2-perl libgd-graph-perl{a} libgd-graph3d-perl libgd-text-perl{a} libgd2-xpm{a} libxpm4{a} 
The following packages will be REMOVED:
  libgd-gd2-noxpm-perl{a} libgd2-noxpm{a}

Copy contents of /opt/var/dspam/webui/htdocs



Permissions

root@daffy:/opt/var# chown www-data /opt/var/dspam
root@daffy:/opt/var# chown www-data /opt/var/dspam/webui
root@daffy:/opt/var/dspam/webui# chown www-data base.css dspam*

Make dir for logs

root@daffy:/opt/var/dspam/webui# mkdir logs

Make a site file for nginx and enable it.

root@daffy:/opt/var# nano /etc/nginx/sites-available/dspam.tarasis.net

server {
    listen   80;
    server_name dspam.tarasis.net;
    access_log /opt/var/dspam/webui/logs/access.log;
    error_log /opt/var/dspam/webui/logs/error.log;

    root  /opt/var/dspam/webui;
    index dspam.cgi;

        auth_basic "DSPAM Restricted Site";
        auth_basic_user_file htpasswd;

    location ~ \.cgi$ {
      gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
      fastcgi_pass 127.0.0.1:8999;
      fastcgi_index dspam.cgi;
      fastcgi_param SCRIPT_FILENAME /opt/var/dspam/webui/cgi-bin$fastcgi_script_name;
      fastcgi_param REMOTE_USER       $remote_user;
      include /etc/nginx/fastcgi_params;      
  }
}

Next create an auth file with a crypt3 password (htpasswd would work or search for online generator)

Get NGINX setup for Perl based FCGI per the steps on this Linode article.

Finally edit /opt/var/dspam/webui/cgi-bin/configure.pl

# Change following to my domain
$CONFIG{'LOCAL_DOMAIN'} = "domain.tld";

# comment out following line
#$CONFIG{'AUTODETECT'}  = 1;

# uncomment following block
# Or, if you're running dspam.cgi as untrusted, it won't be able to auto-detect
# so you will need to specify some features manually:
$CONFIG{'AUTODETECT'}   = 0;
$CONFIG{'LARGE_SCALE'}  = 0;
$CONFIG{'DOMAIN_SCALE'}= 1;
$CONFIG{'PREFERENCES_EXTENSION'} = 1;

Restart NGINX and goto to the url and sign in.

DSPAM Maintenance

Pruging via purge-4.1.sql script & possibly using the dspam_maintenance script

Copy the purge-4.1.sql script to /opt/var/dspam

cp src/tools.mysql_drv/purge-4.1.sql /opt/var/dspam

Next create a cron script to run nightly (though weekly possibly okay)

nano /etc/cron.daily/dspam.purge

#!/bin/sh -
PATH=/bin:/sbin:/usr/sbin:/usr/bin:/usr/libexec:/opt/bin
export PATH
MYSQL=/usr/bin/mysql
 
echo "Purging the Dspam database"
$MYSQL -password=A PASSWORD dspam -user=dspam < /opt/var/dspam/purge-4.1.sql

Make it executable

chmod +x /etc/cron.daily/dspam.purge

Also using a user as a tar pit to make corpus for everyone.

Finally

Other Things

Things Missing

Jan 21 21:42:37 daffy amavis[2132]: Amavis::DB code      loaded
Jan 21 21:42:37 daffy amavis[2132]: Amavis::Cache code   loaded
Jan 21 21:42:37 daffy amavis[2132]: SQL base code        NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: SQL::Log code        NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: SQL::Quarantine      NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: Lookup::SQL code     NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: Lookup::LDAP code    NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: AM.PDP-in proto code loaded
Jan 21 21:42:37 daffy amavis[2132]: SMTP-in proto code   loaded
Jan 21 21:42:37 daffy amavis[2132]: Courier proto code   NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: SMTP-out proto code  loaded
Jan 21 21:42:37 daffy amavis[2132]: Pipe-out proto code  NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: BSMTP-out proto code NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: Local-out proto code loaded
Jan 21 21:42:37 daffy amavis[2132]: OS_Fingerprint code  NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: ANTI-VIRUS code      NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: ANTI-SPAM code       NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: ANTI-SPAM-EXT code   NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: ANTI-SPAM-C code     NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: ANTI-SPAM-SA code    NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: Unpackers code       loaded
Jan 21 21:42:37 daffy amavis[2132]: DKIM code            loaded
Jan 21 21:42:37 daffy amavis[2132]: Tools code           NOT loaded
Jan 21 21:42:37 daffy amavis[2132]: Found $file            at /usr/bin/file
Jan 21 21:42:37 daffy amavis[2132]: No $altermime,         not using it
Jan 21 21:42:37 daffy amavis[2132]: Internal decoder for .mail
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .F   
Jan 21 21:42:37 daffy amavis[2132]: Found decoder for    .Z    at /bin/uncompress
Jan 21 21:42:37 daffy amavis[2132]: Internal decoder for .gz  
Jan 21 21:42:37 daffy amavis[2132]: Found decoder for    .bz2  at /bin/bzip2 -d
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .lzo  tried: lzop -d
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .rpm  tried: rpm2cpio.pl, rpm2cpio
Jan 21 21:42:37 daffy amavis[2132]: Found decoder for    .cpio at /usr/bin/pax
Jan 21 21:42:37 daffy amavis[2132]: Found decoder for    .tar  at /usr/bin/pax
Jan 21 21:42:37 daffy amavis[2132]: Found decoder for    .deb  at /usr/bin/ar
Jan 21 21:42:37 daffy amavis[2132]: Internal decoder for .zip 
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .7z   tried: 7zr, 7za, 7z
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .rar  tried: unrar-free
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .arj  tried: arj, unarj
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .arc  tried: nomarch, arc
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .zoo  tried: zoo
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .lha 
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .doc  tried: ripole
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .cab  tried: cabextract
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .tnef
Jan 21 21:42:37 daffy amavis[2132]: Internal decoder for .tnef
Jan 21 21:42:37 daffy amavis[2132]: No decoder for       .exe  tried: unrar-free; arj, unarj