: HOWTOLightVPS

Welcome :: Categories :: PageIndex :: RecentChanges :: RecentlyCommented :: Login/Register

Setup an HTTP/IMAP/SMTP/DNS/SSH server on Developer VPS

Ok, although the title sounded promising, this howto is mostly links and tips to other howtos, but there are some helpful directions and tricks as well. If you went for Developer VPS be prepared to do things the hard way. It took me 3 days to setup mine (ok I've never done such a thing before).

Again, this is NOT a step by step tutorial, it will just save you a few headaches and google searches.

Used software

First of all, how are we going to fit a complete server environment in 128mb of RAM? Using lightweight software, of course.

OpenSSH - We'll use OpenSSH for both remote logins and FTP. It works out of the box, nothing to configure, yay!
MySQL - we just cannot do without
Postfix - a well known SMTP server
dovecot - currently my favourite IMAPd, looks very fast
DSPAM - because SpamAssassin ate all my RAM.
DKIM-Milter - DKIM makes us looks better in front of spam filters
DK-Milter - DomainKeys, just to make Yahoo happy
BIND - DNS server, usually it comes preinstalled with CentOS
PHP - I think we all know what it is
NGINX - Lightweight HTTP server, I'm using development branch

What to do, or which tutorials I followed

The software were listed in the order I used to set them up. MySQL is surprisingly the first thing I setup, because thats were postfix, dovecot and dspam will store users and other data.

MySQL

This one is easy, just install it with yum. Make sure you activate CentOS+ repository. Here you can find out how to do that

Post server


Postfix, Dovecot
The best way to set them up is to follow this tutorial. Skip the PostfixAdmin part, you can also make the SQL tables with way less columns. I used the following

alias table: address, goto
domain table: domain, description
mailbox table: username, password, description

Note that I didn't use a maildir column in the mailbox table because I use a naming convention instead. Here is one example query for dovecot

user_query = SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, 101 AS uid, 12 AS gid FROM mailbox WHERE username = '%u'


and one for Postfix

query = SELECT CONCAT(SUBSTRING_INDEX(username, '@', 1),'/',SUBSTRING_INDEX(username, '@', -1)) FROM mailbox WHERE username='%s'


Make sure to not messup with permissions and double check all paths in the configuration files, I lost quite some time for them.

Also, I compiled postfix with the following

make makefiles CCARGS='-DUSE_SASL_AUTH -DDEF_SERVER_SASL_TYPE=\"dovecot\" -DHAS_MYSQL -I/usr/include/mysql -DUSE_TLS' AUXLIBS='-L/usr/lib64/mysql -lmysqlclient -lz -lm -lssl -lcrypto'


And then the usual make && make install

DSpam
DSpam documentation is almost non-existant. I didn't configure it very well, you can find some tutorials in its Wiki. Here is what I have in my master.cf

dspam   unix    -       n       n       -       -      pipe
  flags=Rhq user=spamfilter:spamfilter argv=/usr/local/bin/dspam --client --deliver=innocent,spam --user all -- ${recipient}


Make sure you started the dspam daemon first.

So, I got tired of everything being misclassified. I suggest using the spam corpuses at these URL (I only applied them partially):

SpamAssassin Public Corpus - these are quite old
2005 TREC Public Spam Corpus - you must get these with lynx.

To use the second, huge, spam corpus, I've made this script. To use it you must cd to one of full, spam25 or other

#!/bin/bash

while read line; do
class=`expr "$line" : '\([^ ]*\)'`
file=`expr "$line" : '[^ ]* \([^ ]*\)'`

if [ $class = ham ]; then
	class=innocent
fi

/usr/local/bin/dspam --client --user all --class=$class --source=corpus<$file > /dev/null 2>&1

done <index


Note that I write user all not because it means "all users" but because thats the only dspam user on my system (all users use the same spam db).

Also, you better train dspam with your emails. In order to do this I dropped the following script in /etc/cron.daily

#!/bin/bash

cd /var/dspam/error_training/ham
ls | while read file; do
/usr/local/bin/dspam --client --user all --class=innocent --source=error <"$file" > /dev/null 2>&1
rm -f "$file"
done

cd /var/dspam/error_training/spam
ls | while read file; do
/usr/local/bin/dspam --client --user all --class=spam --source=error <"$file" > /dev/null 2>&1
rm -f "$file"
done


This isn't the only way to do this, but is very confortable for me because Apple Mail just lets me drop the emails over the Transmit dock droplets, so I can report false negatives and false positives with a single drag/drop.

Notes
If you setup alias which are actually pipes to shell command, it won't work out of the box. You could use procmail/maildrop. Or you could add this little C program to your delivery route, I added it between dspam and dovecot's deliver. Please note that I wrote this little program for my specific needs and it may not suit yours. It takes 1 argument, which is the mail address or path (started with | character) of the program you want to pipe to. It does NO error checking, so only feed it correctly

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define dovecot "/usr/libexec/dovecot/deliver -d "
#define dovecotlen 32

int main(int argc, char *argv[]) {
	char *pipestring;
		
	if(argv[1][0] != '|') {
		int arglen = strlen(argv[1]);
		pipestring = malloc((dovecotlen+arglen+1) * sizeof(char));
		strcpy(pipestring, dovecot);
		strcat(pipestring, argv[1]);
	} else {
		argv[1][cmdlen(argv[1])] = '\0';
		pipestring = (argv[1])+1;
	}
	
	FILE *pipe = popen(pipestring, "w");
	
	int c;
	
	while((c = getc(stdin)) != EOF) {
		putc(c, pipe);
	}
	
	pclose(pipe);
	
	return 0;
}

int cmdlen(char *dirty_cmd) {
	int i = 0;
	while(*dirty_cmd != '@' && *dirty_cmd != '\0') {
		i++;
		dirty_cmd++;
	}

	return i;
}


DKIM-milter & DK-milter
This is really, really easy, follow this (Milters in Postfix), this (DKIM setup) and this (DK setup). I didn't follow the last tutorial to the letter, because I recompiled the milter myself instead of installing from the rpm.

DNS server


Configuring BIND
Bind again, is a piece of a cake. You can edit /etc/named.conf and add the zones you like (I also deleted the other zones, if you don't use localhost as dns server they are useless). For example I have this

zone "briksoftware.com" IN {
	type master;
	file "briksoftware.com.zone";
	allow-update { none; };
};


And create a zone file in /var/named. Do not forget to put your DKIM and SPF records there as well!

You can test if things are working with dig @127.0.0.1 yourdomain.com

Notes
To get a correct PTR record instead, you must open a ticket which will forwarded to the datacenter. Setting up the zone yourself won't have any effect. It will take some hours so be patient.

HTTP Server


Gettings PHP to work
PHP is a little tricky, its configure script does not play well with 64-bit machines. Here is what to do to compile it

ln -s /usr/include /opt/include
ln -s /usr/lib64 /opt/lib
./configure --prefix=/usr --enable-fastcgi --with-gd --with-zlib --with-bz2 --enable-inline-optimization --with-iconv --with-png-dir=/opt --with-jpeg-dir=/opt --with-freetype-dir=/opt --with-mysql=/opt --with-curl=/opt --with-openssl=/opt --enable-sockets --with-mm --enable-soap --with-mcrypt --with-mash --enable-mbstring --enable-exif --enable-ftp --enable-calendar --enable-bcmath --with-gmp=/opt --enable-gd-native-ttf --enable-sqlite-utf8 --enable-zip
rm /opt/lib
LDFLAGS="-L/usr/lib64/mysql" make
make install
rm /opt/include


You might need to stop all services to compile PHP. In particulare parse_date.c is quite big and will make compilation run out of memory if other services are running.
You can then install ZendOptimizer and eAccelerator if you wish, they seem to work pretty well.

NGINX
NGINX is not hard to configure, you must understand a bit its configuration file, but following the tutorial on its Wiki should suffice.

Remember that NGINX has no mod_php, you must use it as a FastCGI. Is pretty easy to do that if you use spawn-fcgi utility from lighttpd (you have to compile lighttpd but do not have to install it, just copy src/spawn-fcgi somewhere)

Mantainance

Ok this works all fine until a restart. I've actually got (either downloaded or wrote) correct init and logrotate scripts. Make sure to start crond for log rotation.

In particular those not bundled with CentOS are below

/etc/init.d/dovecot
#!/bin/bash
#
#	/etc/rc.d/init.d/dovecot
#
# Starts the dovecot daemon
#
# chkconfig: 2345 54 54
# description: Dovecot Imap Server
# processname: dovecot
# Source function library.
. /etc/init.d/functions

test -x /usr/sbin/dovecot || exit 0

RETVAL=0
prog="Dovecot Imap"

start() {
	    echo -n $"Starting $prog: "
	daemon /usr/sbin/dovecot
	RETVAL=$?
	[ $RETVAL -eq 0 ] && touch /var/lock/subsys/dovecot
	echo
}

stop() {
	echo -n $"Stopping $prog: "
	killproc /usr/sbin/dovecot
	RETVAL=$?
	[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/dovecot
	echo
}

#
#	See how we were called.
#
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  reload|restart)
	stop
	start
	RETVAL=$?
	;;
  condrestart)
	if [ -f /var/lock/subsys/dovecot ]; then
	    stop
	    start
	fi
	;;
  status)
	status /usr/sbin/dovecot
	RETVAL=$?
	;;
  *)
	echo $"Usage: $0 {condrestart|start|stop|restart|reload|status}"
	exit 1
esac

exit $RETVAL


/etc/init.d/dspam (this is a little buggy when restarting)
#!/bin/sh
#
# DSpam filter
#
# chkconfig: 2345 70 70
# description: DSpam filter
# processname: dspam

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="dspam daemon"
NAME=dspam
DAEMON=/usr/local/bin/$NAME
SCRIPTNAME=/etc/init.d/$NAME

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

d_start() {
  $DAEMON --daemon > /dev/null 2>&1 & 
}

d_stop() {
  killall dspam || echo -en "\n not running"
}

case "$1" in
  start)
	echo -n "Starting $DESC: $NAME"
	d_start
	    echo "."
  ;;
  stop)
	echo -n "Stopping $DESC: $NAME"
	d_stop
	    echo "."
  ;;
  restart)
	echo -n "Restarting $DESC: $NAME"
	d_stop
	sleep 1
	d_start
	echo "."
  ;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
	exit 3
  ;;
esac

exit 0


/etc/init.d/php-fcgi (you have to customize this one)
#!/bin/bash
#
#	/etc/rc.d/init.d/php-fcgi
#
# Starts PHP FastCGI
#
# chkconfig: 2345 63 63
# description: PHP FastCGI Server
# processname: php
# Source function library.
. /etc/init.d/functions

test -x /usr/local/bin/php-cgi || exit 0

RETVAL=0
prog="PHP FastCGI"

start() {
	    echo -n $"Starting $prog: "
	/usr/local/bin/spawn-fcgi -a 127.0.0.1 -p 10005 -u www -g www -f /usr/local/bin/php-cgi
	RETVAL=$?
	[ $RETVAL -eq 0 ] && touch /var/lock/subsys/php-fcgi
	echo
}

stop() {
	echo -n $"Stopping $prog: "
	killall php-cgi
	RETVAL=$?
	[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/php-fcgi
	echo
}

#
#	See how we were called.
#
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  reload|restart)
	stop
	start
	RETVAL=$?
	;;
  condrestart)
	if [ -f /var/lock/subsys/php-fcgi ]; then
	    stop
	    start
	fi
	;;
  status)
	RETVAL=0
	;;
  *)
	echo $"Usage: $0 {condrestart|start|stop|restart|reload|status}"
	exit 1
esac

exit $RETVAL


/etc/init.d/nginx (you may need to customize this as well)
#!/bin/sh
#
# NGNIX Web Server
#
# chkconfig: 2345 63 63
# description: NGINX HTTP server
# processname: nginx

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="nginx daemon"
NAME=nginx
DAEMON=/usr/local/nginx/sbin/$NAME
CONFIGFILE=/usr/local/nginx/conf/nginx.conf
PIDFILE=/usr/local/nginx/logs/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

d_start() {
  $DAEMON -c $CONFIGFILE || echo -en "\n already running"
}

d_stop() {
  kill -QUIT `cat $PIDFILE` || echo -en "\n not running"
}

d_reload() {
  kill -HUP `cat $PIDFILE` || echo -en "\n can't reload"
}

case "$1" in
  start)
	echo -n "Starting $DESC: $NAME"
	d_start
	    echo "."
  ;;
  stop)
	echo -n "Stopping $DESC: $NAME"
	d_stop
	    echo "."
  ;;
  reload)
	echo -n "Reloading $DESC configuration..."
	d_reload
	    echo "."
  ;;
  restart)
	echo -n "Restarting $DESC: $NAME"
	d_stop
	sleep 1
	d_start
	echo "."
  ;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
	exit 3
  ;;
esac

exit 0


/etc/logrotate.d/nginx
/usr/local/nginx/logs/*.log {
missingok
sharedscripts
postrotate
 if [ -f /usr/local/nginx/logs/nginx.pid ]; then
  /bin/kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
 fi
endscript
}


That's all folk!

There are no comments on this page. [Add comment]

Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by Wikka Wakka Wiki 1.1.6.2
Page was generated in 0.0914 seconds