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.
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]