On getting my own server I had two purposes, firstly to get access to some online services (self-production) and to learn many aspects of server administration and configuration (Mail and LDAP by example are not so trivial).
Since i've learned a lot of this experience (I maintain a server for 2 years now), and sometimes in pain (LDAP I'll curse you to twenty-six generations), I thinked it would be usefull to publish a summary of such a configuration. Fristly to help me in my next migration and perhaps to help anyone who find this article.
The hardware
I had the chance to get an SUN Ultra 5 wich is a 64bit workstation. Emmbeded with a 360Mhz UltraSPARC-IIi and 320 meg of ram. Inside there was a 8.3Go IDE HDD, one floppy and one IDE CD-ROM.
Since it has only one Ethernet card and i'll need twice, i just plugged a PCI Ethernet card with a RealTek chipset.
Next, I unplugged the floppy disk, since nobody still actually use it (or so rarely that i could put it back for the occasion). The floppy was mounted onto a rack that perfectly fit two IDE hard drive, so here they goes. The first one, a 80go for the data and the second one 4Go for daily backup
Choosing the distro
My first choice was a Debian GNU/Linux 3.1 for SPARC. But i wasn't able to boot on the box with it, so i used a Ubuntu 6.06 LTS Server for Sparc wich is pretty the same. Note that I had to boot on rescue mode since normal mode wasn't working, after that everything goes well.
Note that to boot on cd-rom, i had to press Stop-A and then type boot cdrom. Then the box restarted and booted on the cd.
After installation, i modified /etc/fstab to use my HDs.
# home partition /dev/hdc2 /home ext3 defaults 0 0 # backup /dev/hdd2 /mnt/hd ext3 defaults 0 0
Configuring Network
On debian|ubuntu to configure your network you have to modify the /etc/network/interfaces file. Of course on another distribution you'll have to modify something else (example: on Slackware the file would be /etc/rc.d/rc.inet1). Here's mine configuration :
# The loopback network interface
auto lo eth0 eth1
iface lo inet loopback
iface eth1 inet static
address 172.19.3.3
network 172.19.3.0
broadcast 172.19.3.255
netmask 255.255.255.0
gateway 172.19.3.1
post-up /etc/init.d/firewall
iface eth0 inet static
address 10.41.6.201
network 10.41.6.0
netmask 255.255.255.0
Of course this is a fairly personal configuration, it probably won't fit your needs. First interface (eth0) is connected to the LAN where the ADSL modem-router is connected. The second interface (eth1) is used to plug my laptop in direct connection (yeah i know, hub are cheap, but looking at my house this is the best solution). Of course i want my laptop be NATed. So I configured a firewall script, for NAT and for security (did i mention i'm a little paranoid ?), this is the meaning of the post-up /etc/init.d/firewall directive. It call the following script just after the last interface gets up :
$ cat /etc/init.d/firewall #!/bin/sh echo "Load rc.firewall rules set ..." EXTIF="eth1" INTIF="eth0" echo " External Interface: $EXTIF" echo " Internal Interface: $INTIF" INTNET="10.41.6.0/24" # Load the NAT module (this pulls in all the others). modprobe iptable_nat # clear everything iptables --flush # Set up the Ports for the main servers # i don't use FTP anymore, SFTP or WebDAV is enough #iptables -A INPUT -p tcp --dport 20 -j ACCEPT ## FTP - Data Transfer #iptables -A INPUT -p udp --dport 20 -j ACCEPT ## FTP - Data Transfer #iptables -A INPUT -p tcp --dport 21 -j ACCEPT ## FTP - Connection iptables -A INPUT -p tcp --dport 2222 -j ACCEPT ## SSH iptables -A INPUT -p tcp --dport 80 -j ACCEPT ## HTTP iptables -A INPUT -p tcp --dport 636 -j ACCEPT ## LDAPS iptables -A INPUT -p tcp --dport 993 -j ACCEPT ## IMAPS #iptables -A INPUT -p tcp --dport 4662 -j ACCEPT ## eDonkey2000 #iptables -A INPUT -p udp --dport 4666 -j ACCEPT ## eDonkey2000 #iptables -A INPUT -p tcp --dport 6882 -j ACCEPT ## Bittorent #iptables -A INPUT -p tcp --dport 6881 -j ACCEPT ## BT Tracker iptables -A INPUT -p tcp --dport 4080 -s $INTNET -j ACCEPT ## Mldonkey control # Xorg from laptop iptables -A INPUT -s 10.41.6.206 -p tcp --dport 6000 -j ACCEPT # In the NAT table (-t nat), Append a rule (-A) after routing # (POSTROUTING) for all packets going out EXTIF which says to # MASQUERADE the connection (-j MASQUERADE). iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A POSTROUTING -s $INTNET -j MASQUERADE # Turn on IP forwarding echo 1 > /proc/sys/net/ipv4/ip_forward # Drop everything else except from localhost iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -j DROP
Installing Packages
Next i just installed theses packages from apt-get to provide differents services:
- build-essential (to build other software)
- apache2 (WebServer)
- php5, php5-xmlrpc, php5-xsl, php5-mysql, php5-ldap
- mysql (DataBase)
- OpenLDAP (Directory)
- ssh (OpenSSH client and server)
- dovecot-imapd (IMAPS)
- fetchmail and procmail
- bogofilter and ssmtp
And i had to retreive those packages from various SPARC repositery since Ubuntu does not support them :
And last but not least, i compiled myself dirsync since no SPARC version is aviable.
Configuring Services
Dynamic DNS
I use two dynamic DNS solution:
That's why i use updatedd. It support a large variety of dynamic dns solutions and is coded in pure C. To configure it, I just modified the file /etc/updatedd-wrapper.conf like this :
dyndns(active) {
login = dyndns_1;
hostnames = "grima.homelinux.net";
ip-addr = ipv4:`/usr/share/updatedd/ipserv.pl dyndns`;
use-syslog = yes;
}
ovh(active) {
login = ovh_1;
hostnames = "grima.be";
ip-addr = ipv4:`/usr/share/updatedd/ipserv.pl dyndns`;
use-syslog = yes;
}
Of course the login fields must be modified accordingly. Since my server is behind a ADSL-Modem/Router, I just added this line in the crontab :
00 * * * * updatedd-wrapper
It call the script each hours to update (if needed) the DNS. If your box is intended to directly make the PPP connection, just had the script in ip-up of /etc/ppp/.
Generating SSL Certificate
You'll perhaps need to generate self-signed SSL certificates for your server. I needed three, one for IMAPS, one for LDAPS and the last for HTTPS (of course you could use the same certificate for the three services).
I invite you to read the officiel OpenSSL documentation wich explain how to generate such self-signed certificate. But if you're in a hurry, I think this link will help you : http://www.tc.umn.edu/~brams006/selfsign.html.
Automatised Backup
Easy task with a tools like dirsync. Just mount the HDD dedicated to backup somewhere (i use /mnt/hd). You'll just have to configure your crontab :
30 0 * * * dirsync /var/lib/mysql/ /mnt/hd/mysql/ >/dev/null 2>&1 35 0 * * * dirsync /home/www/ /mnt/hd/www/ >/dev/null 2>&1 50 0 * * * dirsync /etc/ /mnt/hd/etc/ >/dev/null 2>&1
Of course you could save nearly anything that you want, just add directories (like /home, /var/lib/ldap/, etc.).
Remote Login : OpenSSH
Default installation is ready to use, I just tweaked the /etc/ssh/sshd_config a little bit :
- Port 2222 (since there's too much scan on 22)
- PermitRootLogin no (since i'm paranoid ;))
Webserver: Apache 2 / MySQL / PHP5
Debian/Ubuntu has a very pretty packaging for Apache 2. It's a real piece of cake to configure it. First i added /etc/apache2/conf.d/admin with theses directives :
ServerAdmin thegrima@altern.org AddDefaultCharset UTF-8 DocumentRoot "/home/www/" ServerName grima.be
Then we must configure the virtualhost in /etc/apache2/sites-available (next just link this file to sites-enabled) :
NameVirtualHost *
<VirtualHost *>
ServerAdmin thegrima@altern.org
DocumentRoot /home/www
ServerName grima.homelinux.net
ServerAlias grima.be
ErrorLog /var/log/apache2/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/access.log combined
ServerSignature Email
</VirtualHost>
Since I use this server only for me and not to host other people, I didn't tweaked much PHP and MySQL configuration. I just modified (in php.ini) short_open_tag to Off since it cause problems with XML and extension=mysql.so to load MySQL extension (disabled by default with PHP5).
For MySQL i just configured everything with phpMyAdmin.
Mails : Procmail / Fetchmail / ssmtp / BogoFilter
Here comes the big thing. Dealing with mail was the primary objective of my server, I needed to access them from many computer (mine, my laptop, dad, school, friends, etc.) always securely (I don't want my password goes clear on untrusted network).
So here's the configuration I use : Since every belgian ISP are filtering port 25, i cannot host myself an SMTP server. For historical reasons, my primary mails are on altern.org, a free pop3 hoster. So i had to get my mails on the server first, using fetchmail.
$ cat .fetchmailrc poll altern.org with proto POP3 user XXX1 there with password YYY1 is grima here and wants mda "/usr/bin/procmail" user XXX2 there with password YYY2 is grima here and wants mda "/usr/bin/procmail"
As you see, fetchmail connect to the remote server, get the mails and deliver them on local to procmail (grima is, of course, my local user). So here's the procmail configuration :
$ cat .procmailrc DROPPRIVS=yes LINEBUF=4096 VERBOSE=off MAILDIR=$HOME/Mail/ FORMAIL=/usr/bin/formail SENDMAIL=/usr/sbin/ssmtp PMDIR=$HOME/.procmail #LOGFILE=$PMDIR/log #LOG=" #" INCLUDERC=$PMDIR/rc.maillists INCLUDERC=$PMDIR/mountyhall.maillists INCLUDERC=$PMDIR/hex05.maillists INCLUDERC=$PMDIR/akt.maillists INCLUDERC=$PMDIR/unif.maillists INCLUDERC=$PMDIR/spam.rc :0: * $MAILDIR
Report to the procmail man page to get details of this configuration but basically, it include different filters for mailing-list and spam and the deliver to my local mailbox wich is ~/Mail. You may alos ask why i use ssmtp and not classical sendmail (or postfix). Since my server was not intended to directly receive mail, I just needed a little tiny program to send mail to other SMTP: Ssmtp has been conceived just that goal. And since sendmail has a long tradition of remote-root exploit, i prefer not using it.
Here is two included files for your learning :
$ cat .procmail/rc.maillists :0: * ^TOniouz@reseaucitoyen.be $HOME/Mail/.INBOX.RC/ $ cat .procmail/spam.rc ## Silently drop asiatic language mails UNREADABLE='[^?"]*big5|iso-2022-jp|ISO-2022-KR|euc-kr|gb2312|ks_c_5601-1987' :0: * 1^0 $ ^Subject:.*=\?($UNREADABLE) * 1^0 $ ^Content-Type:.*charset="?($UNREADABLE) $HOME/Mail/.Junk/ :0: * ^Content-Type:.*multipart * B ?? $ ^Content-Type:.*^?.*charset="?($UNREADABLE) $HOME/Mail/.Junk/ :0: * ^X-Spam-Status: Yes $HOME/Mail/.Junk/ :0fw | bogofilter -u -e -p :0: * ^X-Bogosity: Yes, tests=bogofilter $HOME/Mail/.Junk/ :0: * ^X-Bogosity:.Spam $HOME/Mail/.Junk/
For details about this configuration, report to the bogofilter documentation. Also, don't forget that bogofilter must be trained before deployed like that. You must have a corpus of spam and non-spam mail to train it. Against, report to the bogofilter configuration if you're interested (otherwise just don't include it).
So the configuration to get our mails is nearly complete. I just added in crontab (crontab -e) this line to get my mails every ten minutes :
0,10,20,30,40,50 * * * * fetchmail >/dev/null 2>&1
Mail Server: Dovecot
After all this configuration, just to get your mails, you may think building a IMAP server will be an hard task. It is not ! I had just four directives in the default configuration file (/etc/dovecot/dovecot.conf) modified and all was running:
protocols = imaps default_mail_env = maildir:~/Mail ssl_cert_file = /etc/ssl/certs/imapd.pem ssl_key_file = /etc/ssl/private/imapd.pem
First one is because i want ONLY IMAPS and not traditional unencrypted IMAP. Second one precise the place where to get mails for users. The two last are the SSL certificate to use. And that's all ! Restart dovecot (sudo /etc/init.d/dovecot restart) and you've got a working IMAPS server, bravo !
Directory Server: OpenLDAP
Deploying an LDAP server may not be as hard as it looks, but if you don't understand how works LDAP hierarchy you'll crunch your mind. So I invite to read this article on Wikipedia. Ok, ready ?
So the first step will be to write down a directory structure. I primary deployed LDAP to have a centralised address book compatible with most of the mail reader. I won't use it to authenticate user against a whole system but I need user authetification to configure access right to the address book. So here is the deal :
dc=grima, dc=be |->cn=Manager |->ou=People |->ou=users
Manager is intended to be the super user of the LDAP (it could be putted in ou=users, but it's more easy to retain his full DN like that). People is the organisational unit to store the address book and users is the ou to store user credentials. Now we have decided a basic hierarchy, let's configure sldap :
$ cat /etc/ldap/slapd.conf
# Schema and objectClass definitions
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
# Schema check allows for forcing entries to
# match schemas for their objectClasses's
schemacheck on
# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile /var/run/slapd/slapd.pid
# List of arguments that were passed to the server
argsfile /var/run/slapd.args
# Read slapd.conf(5) for possible values
loglevel 0
# Where the dynamically loaded modules are stored
modulepath /usr/lib/ldap
moduleload back_bdb
# SSL:
TLSCertificateFile /etc/ssl/certs/ldap.pem
TLSCertificateKeyFile /etc/ssl/private/ldap.pem
# Specific Backend Directives for bdb:
backend bdb
checkpoint 512 30
# Specific Directives for database #1, of type bdb:
database bdb
# The base of your directory in database #1
suffix "dc=grima,dc=be"
rootdn "cn=Manager,dc=grima,dc=be"
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw secret
# Where the database file are physically stored for database #1
directory "/var/lib/ldap"
# Indexing options for database #1
index objectClass eq
# Save the time that the entry gets modified, for database #1
lastmod on
#############
# ACCESS CONFIG
#############
# everyone could auth and chage his own password
# but no-one could read hash
access to attrs=userPassword
by dn="cn=Manager,dc=grima,dc=be" write
by anonymous auth
by self write
by * none
# allow users to write some stuff
access to attrs=loginShell,shadowLastChange
by dn="cn=Manager,dc=grima,dc=be" write
by self write
by * read
# Address Book access
# user could read/write
access to dn.subtree="ou=People,dc=grima,dc=be"
by users write
by anonymous none
# Ensure read access to the base for things like
# supportedSASLMechanisms.
access to dn.base="dc=grima,dc=be" by * read
# The admin dn has full write access and users could read eveything
access to *
by dn="cn=Manager,dc=grima,dc=be" write
by users read
by * none
As you could see, I activated SSL, included Schema, configured Manager Password, root DN and access rights. Next step is to configure on wich interface the deamon should be aviable. This is done at deamon startup and could be configured on Ubuntu/Debian on the file /etc/default/slapd. I just modified one line :
SLAPD_SERVICES="ldap://127.0.0.1/ ldaps:///"
This tell to slapd to be aviable with SSL to each interface and with clear-text connection only for localhost. I use this to prevent local software (especially PHP one) to use unnecessary encrypted channel and to ensure remote connection are encrypted.
Now that slapd is configured, just launch it :sudo /etc/init.d/slapd (re)start. If everything goes well it works, elsewhere try to run slapd -d 256 to have debug printed in syslog.
Next step is to import the initial structure in the LDAP. First create a file (by example: mylldap.ldif) :
dn: dc=grima,dc=be objectclass: dcObject objectclass: organization o: grima.be dc: grima dn: cn=Manager,dc=grima,dc=be objectclass: organizationalRole cn: Manager dn: ou=People,dc=grima,dc=be ou: People objectClass: top objectClass: organizationalUnit dn: ou=users,dc=grima,dc=be ou: users objectClass: top objectClass: organizationalUnit
As you can see it's the reflect of our directory structure. You can import it in your LDAP with : ldapadd -x -D "cn=Manager,dc=grima,dc=be" -W -f myldap.ldif. And here it is, you've a functionnal LDAP system.
Of course for now it is pretty empty. You'll have to configure one (or more) common user and to fill in the addressbook. But you don't have to use such a rough interface, just install a phpLDAPadmin ! It will make your life a lot easier.
To manage Address Book online, I configured ConTagged a PHP WebApp wich use LDAP as backend. It's not perfect but working pretty well.