This document explains, howto setup a server to serve as HTTP, FTP, SMTP, POP3 and IMAP-Server which can be controlled via HTTP & MySQL and used via webmail.
The following software will be needed:
gcc
Postfix as SMTP-Server
Apache as Web-Server
Dovecot as POP3 & IMAP-Server
Pure-FTPD as FTP-Server
MySQL for configuration
CCC for control (Corvus ControlCenter)
Roundcube for Webmail
PHP
This How-To is written in september 2006, so some configuration may be too old to work. Try to use google if you have questions.
If you're using systems like Debian, SuSE or similar don't jump over the installation chapter, some programs have to be compiled even if you have the packages installed!
May the success be with you!
Here a little list of programs you need to continue this howto:
gcc, gcc-c++, libgcc
optional: OpenSSL
If you're using systems like debian or SuSE linux, you may get some of the software as packages. Try to install the following packages if availabe:
MySQL (>= 4.1), MySQL-devel, MySQL-client
apache2, apache2-mod_php5
if you can't find apache2-mod_php5 try apache2-mod_php4 or install php5 or php4 if available
php5-mysql
pure-ftpd
postfix, postfix-mysql
dovecot (>= 1.0)
Important: install dovecot package only if it's version 1.0 or higher
Make sure compilation software is installed and then go on. Every step contains compilation information.
You need MySQL installed on your machine. If you need instructions click here: http://www.google.com/search?q=mysql+howto
If you don't want your software to use root mysql access just create a new user which has access to one database you want to use. In this howto we use a database called 'ccc'. Here the struct of the database:
CREATE TABLE `domains` ( `domain` varchar(255) collate utf8_bin NOT NULL, `path` varchar(255) collate utf8_bin NOT NULL, UNIQUE KEY `domain` (`domain`) ); CREATE TABLE `emails` ( `id` int(10) NOT NULL auto_increment, `account` varchar(255) collate utf8_bin NOT NULL, `domain` varchar(255) collate utf8_bin NOT NULL, `password` varchar(32) collate utf8_bin NOT NULL, `quota` int(10) NOT NULL default '0', `alias` int(10) NOT NULL default '0', UNIQUE KEY `id` (`id`) ); CREATE TABLE `ftp` ( `name` varchar(50) collate utf8_bin NOT NULL, `password` varchar(32) collate utf8_bin NOT NULL, `homedir` varchar(255) collate utf8_bin NOT NULL, UNIQUE KEY `name` (`name`) ); CREATE TABLE `kunden` ( `id` int(5) NOT NULL auto_increment, `nick` varchar(50) collate utf8_bin NOT NULL, `pass` varchar(32) collate utf8_bin NOT NULL, UNIQUE KEY `id` (`id`,`nick`) ); CREATE TABLE `subdomains` ( `name` varchar(255) collate utf8_bin NOT NULL, `domain` varchar(255) collate utf8_bin NOT NULL, `path` varchar(255) collate utf8_bin NOT NULL );
Now we have to one user to the table "kunden":
INSERT INTO TABLE `kunden` (`nick`, `pass`) VALUES ('Admin', MD5('yourpassword'));You have configured MySQL!
First install apache via package or get it from http://httpd.apache.org. As always our friend google can help us with installation!
Notice: If you have to compile it yourself remember to compile it with mysql and php support (and install PHP first!)
Usually you can find the httpd.conf within /etc/apache2/. If it is not there, try to search it (with grep... man grep if you don't know how).
Apache will be configured OK by default. Additional configuration for virtual domains will be done by CCC.
Install the package pure-ftpd or get it from the internet: http://www.pureftpd.org
You should find the config file pure-ftpd.conf within the folder /etc/pure-ftpd/
Set the following directives:
ChrootEveryone yes TrustedGID no AnonymousOnly no NoAnonymous yes MySQLConfigFile /etc/pure-ftpd/pureftpd-mysql.conf AutoRename no #this is not needed but if it's set to yes you can't overwrite files
Caution: these were only settings you should change or test, many other settings are needed, too, but aren't listed because they should influence this howto!
Now create the file /etc/pure-ftpd/pureftpd-mysql.conf:
#MYSQLPort 3306 MYSQLSocket /var/lib/mysql/mysql.sock MYSQLUser mysqluser MYSQLPassword mysqlpassword MYSQLDatabase ccc MYSQLCrypt md5 MYSQLGetPW SELECT password FROM ftp WHERE name = "\L" MYSQLGetUID SELECT 1001 MYSQLGetGID SELECT 100 MYSQLGetDir SELECT homedir FROM ftp WHERE name = "\L"
Notice: don't forget to insert YOUR mysqluser and mysqlpassword!
/etc/init.d/pure-ftpd reload
Maybe you want to check the log files (/var/log/messages in common) for possible errors!
Even if you have installed the package you may need the source code. In SuSE 10.1 for example you get only Postfix 2.2 via yast, but you need Postfix 2.3 or higher.
So go to http://www.postfix.org/download.html and get the version you want (but 2.3 or higher!).
wget ftp://ftp.fu-berlin.de/unix/mail/postfix/official/postfix-2.3.3.tar.gz
tar xfz postfix-2.3.3.tar.gz
cd postfix-2.3.3/
make -f Makefile.init makefiles \
'CCARGS=-DHAS_MYSQL -DUSE_SASL_AUTH -DUSE_TLS -DDEF_SERVER_SASL_TYPE=\"dovecot\" -I/usr/include/mysql' \
'AUXLIBS=-lmysqlclient -lssl -lcrypto -lz -lm'
make upgrade
Notice: this configures postfix to use Dovecot SASL, MySQL and OpenSSL. If you want more or less compatability visit postfix.org for more information!
Notice: This may need Berkeley devel packages or source code (db...-devel) and/or OpenSSL stuff to work
You should find the configuration files in /etc/postfix.
Open main.cf and configure postfix as you wish - then add the following lines to the end of the file:
home_mailbox = Maildir/ smtpd_helo_required = yes smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth virtual_mailbox_domains = mysql:/etc/postfix/mysql/domains.cfg virtual_mailbox_base = /var/mail virtual_mailbox_maps = mysql:/etc/postfix/mysql/mboxes.cfg virtual_alias_maps = mysql:/etc/postfix/mysql/aliases.cfg virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 virtual_transport = virtual #TLS Support, if you don't want to use TLS just comment the following #lines out. This config is taken from another howto. smtpd_use_tls = yes smtpd_tls_auth_only = no smtpd_tls_key_file = /usr/share/ssl/s/PrivateKey.pem smtpd_tls_cert_file = /usr/share/ssl/s/Cert.pem smtpd_tls_CAfile = /usr/share/ssl/s/demoCA/cacert.pem smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom
Notice: the paths in this file (except /dev/urandom) are chosen by the author, you may change them if you like
Notice: TLS is preconfigured with help from another howto. You may find some on postfix.org
Notice: The line "home_mailbox = Maildir/" says that postfix should use a mailbox instead of a single file for each user, if you want to use single files then you have to change some of the dovecot configuration later on!
Create the file you gave postfix as virtual_mailbox_domains (here: /etc/postfix/mysql/domains.cfg):
user = mysqluser password = mysqlpassword dbname = ccc query = SELECT domain FROM domains WHERE domain = '%s' hosts = localhost
Notice: remember to add YOUR mysql user information and not "mysqluser" and "mysqlpassword"
Create the file you gave postfix as virtual_mailbox_domains (here: /etc/postfix/mysql/domains.cfg):
user = mysqluser password = mysqlpassword dbname = ccc query = SELECT concat(domain, '/', account, '/') FROM emails WHERE account = '%u' AND domain = '%d' AND alias = 0 hosts = localhost
Notice: remember to add YOUR mysql user information and not "mysqluser" and "mysqlpassword"
Notice: This says postfix to create the mailbox in /your/mail/base/example.com/username/ (for example: /var/mail/postfix.org/info/ for info@postfix.org)
Create the file you gave postfix as virtual_mailbox_domains (here: /etc/postfix/mysql/domains.cfg):
user = mysqluser password = mysqlpassword dbname = ccc query = SELECT concat(e2.account, '@', e2.domain) FROM emails as e1, emails as e2 WHERE e1.account = '%u' AND e1.domain = '%d' AND e1.alias > 0 AND e1.alias = e2.id hosts = localhost
Notice: remember to add YOUR mysql user information and not "mysqluser" and "mysqlpassword"
Install per package, but be careful, you need version 1.0 or higher! Very important! If you need the source go to http://www.dovecot.org/download.html
You can find the config file dovecot.conf in /etc or in /usr/local/etc. Open it and make sure the following settings are set:
protocols = imap imaps pop3 pop3s # only set the services you want - the s stands for secure (ssl)
disable_plaintext_auth = no
#ssl:
ssl_disable = no
ssl_cert_file = /usr/share/ssl/s/Cert.pem
ssl_key_file = /usr/share/ssl/s/PrivateKey.pem
default_mail_env = maildir:/var/mail/%d/%n/
protocol pop3
{
pop3_uidl_format = %v.%u
}
auth default
{
mechanisms = plain login cram-md5 digest-md5
passdb sql
{
args = /usr/local/etc/dovecot-sql.conf
}
userdb static
{
args = uid=5000 gid=5000 home=/var/mail/%d/%n
}
socket listen
{
client
{
user = postfix
group = postfix
path = /var/spool/postfix/private/auth
mode = 0660
}
}
}Notice: ensure that /var/spool/postfix is the path to your postfix runtime files
Notice: the mechanisms list may of course content less entries
Notice: Remember previous notice: if you don't like to use Maildir/ change here too!
Now you have to change the file you gave as argument above (here: /usr/local/etc/dovecot-sql.conf). Open or create it and insert following content:
driver = mysql connect = host=/var/lib/mysql/mysql.sock user=mysqluser password=mysqlpassword dbname=ccc default_pass_scheme = PLAIN password_query = SELECT password FROM emails WHERE account = '%n' AND domain = '%d' AND alias = 0
Notice: don't forget to change the mysql access information to fit your environment.
Notice: if you don't have a sock or don't want to use it you can set host to your mysqlhost (for example localhost)
You need to have a user owning /var/mail (or your mailbox base) with user id 5000 and group id 5000 - alternatively change uid and gid above and very much above in the postfix main configuration section.
groupadd -g 5000 mailowner useradd -g 5000 -u 5000 -d /var/mail -p somesecretpassword -s /bin/false mailowner chown -R mailowner:mailowner /var/mail
Notice: this user has no console (/bin/false) so there's no security danger - you don't have to set a password for it, but secure is secure ;-)
Get roundcube from http://roundcube.net/ and extract it to your htdocs root directory (common: /srv/www/htdocs):
wget http://puzzle.dl.sourceforge.net/sourceforge/roundcubemail/roundcubemail-0.1beta2.tar.gz tar xfz roundcubemail-0.1beta2.tar.gz cd roundcube/ cd config/ cp db.inc.php.dist db.inc.php cp main.inc.php.dist main.inc.php
Notice: you should create a new mysql database for the personal settings of your future users. See INSTALL for more informations.
Change these settings in config/main.inc.php:
$rcmail_config['smtp_server'] = 'localhost';
Make sure you've installed the MySQL databse and tables for roundcube. Instructions are in the INSTALL file.
Change these settings in config/db.inc.php:
$rcmail_config['db_dsnw'] = 'mysql://mysqluser:mysqlpassword@localhost/roundcube';
If you want, you can patch roundcube a bit so that your users can change their password in their user preferences. To do so edit the following two files:
First, open 'roundcube/program/steps/settings/func.inc' and search for 'function rcmail_user_prefs_form', then scroll down to the end of this function and add the following code before ' $out .= "\n</table>$form_end";'
// CCC addition
// show password form
$field_id = 'rcmfd_password';
$input_password = new textfield(array('name' => '_password', 'id' => $field_id, 'size' => 20));
$out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s (empty = unchanged)</td></tr>\n",
$field_id,
rep_specialchars_output(rcube_label('password')),
$input_password->show($CONFIG['password']));
// end CCC addition
Then open 'roundcube/program/steps/settings/save_prefs.inc' and insert the following after the line "$a_user_prefs['prefer_html'] = isset($_POST['_prefer_html']) ? TRUE : FALSE;":
// CCC addition
if ($_POST['_password'] != "")
{
mysql_query("UPDATE ccc.emails SET password = '".$_POST['_password']."' WHERE concat(account, '@', domain) = '".$_SESSION['username']."'")
or die(mysql_error());
$_SESSION['password'] = encrypt_passwd($_POST['_password']);
}
// end of CCC addition
Notice: change ccc.emails to yourdatabase.emails if needed!
Notice: the roundcubemail mysql user needs update permissions for the email table!
Get CCC from http://www.corvusmedia.de and extract it, start the setup and follow the instructions:
tar xfz ccc-beta0.4.1-XXX-bin.tar.gz cd ccc-beta0.4.1 ./CCC --setup
Notice: CCC is currently in public beta state.
Warning: you should never install ccc within your DocumentRoot!
Go to /srv/ccc (or the path you typed above) and open configs/ccc.cfg:
InstallDir /srv/ccc/ TmpDir /srv/ccc/sessions/ ApacheConf /etc/apache2/
Notice: be sure every path is correct!
Notice: The TmpDir contains session data (similar to php) - make sure you have write access
Go to configs/mysql.cfg now:
host:localhost user:mysqluser password:mysqlpassword auto-connect:true database:ccc
Notice: don't forget to use YOUR mysql access data
Now go back to your httpd.conf which should be located at /etc/apache2. Add the following line to the end of the file:
Include /srv/ccc/configs/apache.cfg
Notice: make sure the path is correct
Sound spacy but I just want you to run CCC once so it can configurate apache to enable the web-access to CCC:
cd /srv/ccc ./CCC --init
Notice: If there's any error, try to follow the instructions and repair it. Repeat this step until you get the message "Initialisation completed!"
Now you should create a cronjob which reloads the apache config every 2 minutes so your changes will have effect.
Therefore edit /etc/crontab and add
*/2 * * * * root /path/to/ccc/docron >/dev/null 2>&1
Notice: There are alternative ways, too, like mod_vhost_mysql for apache which allows dynamic vhost lookups against mysql, but I think it's better to reload apache every two minutes instead of do one mysql lookup per apache request (so for each element on every webpages - every image, stylesheet etc. will need an own mysql lookup)
Now you've finished everything. Lean back and hope that it works. Most times it doesn't, but don't worry and don't give up. Google, mailing list, boards, etc. will help you out.
To test if everything works we start with (re)starting everything:
/etc/init.d/mysql restart /etc/init.d/apache2 restart /etc/init.d/postfix restart /etc/init.d/dovecot restart /etc/init.d/pure-ftpd restart
Notice: if you're using pure-ftpd as part of (x)inetd you have to restart (x)inetd instead of pure-ftpd
Next we can test around:
Notice: the prefix # means a comment so just ignore if you like
Notice: the prefix $ means that the following is a command you should execute, everything else is output of the tested program or comment
Notice: If you're in a telnet session and want to quit it instantly just type CTRL-[+] (not the plus on numblock)
#testing mysql $ mysql -umysqluser -pmysqlpassword -Dccc Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 888 to server version: 4.1.13 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SELECT * FROM emails; Empty set (0.00 sec) mysql> QUIT Bye #ok mysql works
#testing apache2
$ wget localhost
--03:42:48-- http://localhost/
=> `index.html'
Auflösen des Hostnamen »localhost«.... 127.0.0.1, ::1
Verbindungsaufbau zu localhost|127.0.0.1|:80... verbunden.
HTTP Anforderung gesendet, warte auf Antwort... 200 OK
Länge: 288 [text/html]
100%[====================================>] 288 --.--K/s
03:42:48 (54.93 MB/s) - »index.html« gespeichert [288/288]
#ok apache works#testing postfix $ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 static.88-198-7-146.your-server.de ESMTP Postfix (2.3.3) HELO host 250 static.88-198-7-146.your-server.de MAIL FROM: root 250 2.1.0 Ok RCPT TO: <someaddress@thatyouown.tld> 250 2.1.5 Ok DATA 354 End data with <CR><LF>.<CR><LF> Subject: Test-Mail From: Tester Test-data . 250 2.0.0 Ok: queued as 27929ED806B QUIT 221 2.0.0 Bye Connection closed by foreign host. #ok postfix is online
Notice: check now if the mail arrived - if so, part 1 is accomplished. If not, check /var/log/mail for more information.
#testing pure-ftpd $ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220-Welcome to Pure-FTPd. 220-You are user number 1 of 10 allowed. 220-This is a private system - No anonymous login 220-IPv6 connections are also welcome on this server. 220 You will be disconnected after 15 minutes of inactivity. QUIT 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout. Connection closed by foreign host. #ok pure-ftpd is online
#testing dovecot $ telnet localhost 143 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. * OK Dovecot ready. ^] telnet> quit Connection closed. $ telnet localhost 110 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. +OK Dovecot ready. CAPA +OK CAPA TOP UIDL RESP-CODES PIPELINING STLS USER SASL PLAIN LOGIN CRAM-MD5 DIGEST-MD5 . QUIT +OK Logging out Connection closed by foreign host. #ok dovecot runs
#testing ccc
$ wget localhost/ccc/ccc.cgi
--03:45:54-- http://localhost/ccc/ccc.cgi
=> `ccc.cgi.1'
Auflösen des Hostnamen »localhost«.... 127.0.0.1, ::1
Verbindungsaufbau zu localhost|127.0.0.1|:80... verbunden.
HTTP Anforderung gesendet, warte auf Antwort... 200 OK
Länge: nicht spezifiziert [text/html]
[ <=> ] 721 --.--K/s
03:45:54 (62.51 MB/s) - »ccc.cgi« gespeichert [721]
#ok ccc works so farOpen a browser and surf to your IP-Adress or hostname, check if it works. Then surf to http://youraddress/ccc/ccc.cgi and login with the user we added in chapter 3 section 2. Then create some subdomains and for example an email-address info@example.com which is no alias and has the passwort "testing" without the quotes (of course).
Additionally add some FTP user, let's call him info@example.com, too. Take the same password.
$ ftp localhost Trying 127.0.0.1... Connected to localhost. 220-Welcome to Pure-FTPd. 220-You are user number 1 of 10 allowed. 220-This is a private system - No anonymous login 220-IPv6 connections are also welcome on this server. 220 You will be disconnected after 15 minutes of inactivity. Name (localhost:root): info@example.com 331 User info@example.com OK. Password required Password:testing 230-User info@example.com has group access to: users 230 OK. Current restricted directory is / Remote system type is UNIX. Using binary mode to transfer files. ftp> quit 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout.
You should run this test from a remote machine:
$ telnet youradress 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 static.88-198-7-146.your-server.de ESMTP Postfix (2.3.3) EHLO myhost 250-static.88-198-7-146.your-server.de 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH PLAIN LOGIN CRAM-MD5 DIGEST-MD5 250-AUTH=PLAIN LOGIN CRAM-MD5 DIGEST-MD5 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN AUTH LOGIN ZW1tZXJhbkBjb3J2dXNtZWRpYS5kZQ== TmlyaHRhaw==334 VXNlcm5hbWU6 334 UGFzc3dvcmQ6 MAIL FROM: <info@example.com> 535 5.7.0 Error: authentication failed: Invalid base64 data in continued response QUIT 221 2.0.0 Bye Connection closed by foreign host. suse10064lamp:/srv/ccc # telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 static.88-198-7-146.your-server.de ESMTP Postfix (2.3.3) EHLO myhost 250-static.88-198-7-146.your-server.de 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH PLAIN LOGIN CRAM-MD5 DIGEST-MD5 250-AUTH=PLAIN LOGIN CRAM-MD5 DIGEST-MD5 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN AUTH LOGIN 334 VXNlcm5hbWU6 aW5mb0BleGFtcGxlLmNvbQ== 334 UGFzc3dvcmQ6 dGVzdGluZw== 235 2.0.0 Authentication successful MAIL FROM: <info@example.com> 250 2.1.0 Ok RCPT TO: <someaddress@thatyouown.tld> 250 2.1.5 Ok DATA 354 End data with <CR><LF>.<CR><LF> Subject: Testmail From: Tester Test-info, part2 . 250 2.0.0 Ok: queued as 7A3BDED806B QUIT 221 2.0.0 Bye Connection closed by foreign host.
Notice: You can run this test with MS Outlook or Mozilla Thunderbird, too, if you like
Notice: We recommend to test this with wrong auth data, too, to check if it really works
To test those two programs just take a browser and open http://youradress/roundcube/. Then try to login with the mail user you created above (info@example.com)
You'll see if it works.
Congratulations, now you have a virtual multi domain server. You're welcome to send any feedback to emmeran@corvusmedia.de
If you have problem, please try to search the internet. I'm sure you find a solution.
If you can't find a solution, feel free to go to http://forum.corvusmedia.de/ and create there !after searching the forum! a new thread so maybe I can help you.
Have fun with your server and go to bed somewhen ;-)
Emmeran Sollner
Under special circumstances dovecot gets an Access Denied error from MySQL allthough all MySQL auth information is correct. To solve this problem you have to change the encryption of the passwort in the mysql database. Therefore execute this query:
SET PASSWORD FOR 'some_user'@'some_host' = OLD_PASSWORD('mypass');