1. Introduction
Après avoir déja rédigé une documentation sur la réalisation d’un serveur pour gérer au niveau dns, mail et ftp plusieurs domaines virtuels stockés dans une base LDAP, voici la même chose mais en se basant cette fois sur une base de données MySQL.
Prérequis :
Une Debian proprement installée avec juste ce qu’il faut (c’est à dire vim et ssh 🙂
Un serveur Mysql, personnellement je me base sur la version 5 qui sera éventuellement installée sur le même serveur. Je n’entrerai absolument pas dans le paramétrage du serveur Mysql ni dans la sécurisation des accès à celui-ci. Pour des raisons de performances dans la montée en charge, les tables seront toutes au format InnoDB, il faudra donc veiller à ce que le support InnoDB soit présent.
2. Serveur DNS Powerdns
2.1 Installation
Pour installer les paquets, rien de particulier sur une Debian :
# apt-get install pdns-server pdns-recursor pdns-backend-mysql
Structure de la base de données DNS gérant les noms de domaine :
CREATE TABLE IF NOT EXISTS `domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL, `master` varchar(20) default NULL, `last_check` int(11) default NULL, `type` varchar(6) NOT NULL, `notified_serial` int(11) default NULL, `account` varchar(40) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `name_index` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `records` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) default NULL, `name` varchar(255) default NULL, `type` varchar(6) default NULL, `content` varchar(255) default NULL, `ttl` int(11) default NULL, `prio` int(11) default NULL, `change_date` int(11) default NULL, PRIMARY KEY (`id`), KEY `rec_name_index` (`name`), KEY `nametype_index` (`name`,`type`), KEY `domain_id` (`domain_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `supermasters` ( `ip` varchar(25) NOT NULL, `nameserver` varchar(255) NOT NULL, `account` varchar(40) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
2.2 Paramétrage de PowerDNS
Fichier /etc/powerdns/pdns.conf :
allow-axfr-ips=allow-recursion=127.0.0.1/8, /32 config-dir=/etc/powerdns daemon=yes disable-axfr=no disable-tcp=no guardian=yes lazy-recursion=no local-address= local-port=53 master=yes module-dir=/usr/lib/powerdns recursor=127.0.0.1:5353 setgid=pdns setuid=pdns slave=yes socket-dir=/var/run version-string=powerdns include=/etc/powerdns/pdns.d launch=gmysql gmysql-host=127.0.0.1 gmysql-user=pdns gmysql-password=secret gmysql-dbname=DNS
Fichier /etc/powerdns/recursor.conf :
allow-from=127.0.0.0/8,/32 daemon=yes delegation-only=com,net local-address=127.0.0.1 local-port=5353 quiet=yes
2.3 Remplissage du DNS
On utilise une base SQL donc la création d’une zone ou la modification d’un enregistrement se fait en SQL c’est logique. Après, libre à vous de choisir la ligne de commande mysql, phpmyadmin, un script php fait la main… Voici quelques exemples. Le reste est classique, ça reste du DNS tout ce qu’il y a de plus habituel
Ajout d’une zone maitre :
INSERT INTO domains (name, type, notified_serial) VALUES ('morot.fr', 'MASTER', '2008050201')
Ajout de différent champs :
Le champs SOA : INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'morot.fr','SOA','ns1.morot.fr hostmaster.morot.fr 2008050201 10800 3600 604800 600','600','10',NOW()); Puis les serveurs de nom de cette zone : INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'morot.fr','NS','ns1.morot.fr','600','10',NOW()); INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'morot.fr','NS','ns2.toto.org','600','10',NOW()); Bien entendu nous avons un serveur de mail : INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'morot.fr','MX','mail.morot.fr','600','10',NOW()); Deux champs A : INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'mail.morot.fr','A','192.168.69.1','600','10',NOW()); INSERT INTO `records` (domain_id,name,type,content,ttl,prio,change_date) values (1,'www.morot.fr','A','192.168.69.1','600','10',NOW()); Et un ALIAS : (1,'ftp.morot.fr','CNAME','www.morot.fr', '600','10',NOW());
3. Serveur FTP Pure-ftpd
3.1 Installation
Installation :
# apt-get install pure-ftpd-common pure-ftpd-mysql
Structure de la base MySQL VFTP :
CREATE TABLE IF NOT EXISTS `ftpd` ( `User` varchar(16) NOT NULL default '', `status` enum('0','1') NOT NULL default '0', `Password` varchar(64) NOT NULL default '', `Uid` varchar(11) NOT NULL default '-1', `Gid` varchar(11) NOT NULL default '-1', `Dir` varchar(128) NOT NULL default '', `ULBandwidth` smallint(5) NOT NULL default '0', `DLBandwidth` smallint(5) NOT NULL default '0', `comment` tinytext NOT NULL, `ipaccess` varchar(15) NOT NULL default '*', `QuotaSize` smallint(5) NOT NULL default '0', `QuotaFiles` int(11) NOT NULL default '0', PRIMARY KEY (`User`), UNIQUE KEY `User` (`User`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Ajout d’un compte FTP :
INSERT INTO `ftpd` (`User`, `status`, `Password`, `Uid`, `Gid`, `Dir`, `ULBandwidth`, `DLBandwidth`, `comment`, `ipaccess`, `QuotaSize`, `QuotaFiles`) VALUES ('morot', '0', 'secret', '2001', '2001', '/home/www/morot.fr/', 500, 500, '', '*', 0, 0);
Création du compte virtuel :
addgroup --gid 2001 vftp adduser --home /dev/null --shell /bin/false --no-create-home --uid 2001 --disabled-password --ingroup vftp --disabled-login vftp
3.2 Paramétrage
Fichier /etc/pure-ftpd/db/mysql.conf
:
MYSQLServer 127.0.0.1 MYSQLPort 3306 MYSQLSocket /var/run/mysqld/mysqld.sock MYSQLUser pureftpd MYSQLPassword secret MYSQLDatabase VFTP MYSQLCrypt cleartext MYSQLGetPW SELECT Password FROM ftpd WHERE User="L" MYSQLGetUID SELECT Uid FROM ftpd WHERE User="L" MYSQLGetGID SELECT Gid FROM ftpd WHERE User="L" MYSQLGetDir SELECT Dir FROM ftpd WHERE User="L" MySQLGetQTAFS SELECT QuotaFiles FROM ftpd WHERE User="L" MySQLGetQTASZ SELECT QuotaSize FROM ftpd WHERE User="L" MySQLGetBandwidthUL SELECT ULBandwidth FROM ftpd WHERE User="L" MySQLGetBandwidthDL SELECT DLBandwidth FROM ftpd WHERE User="L" MySQLTransactions On
Paramétrages supplémentaires :
echo "yes" > /etc/pure-ftpd/conf/ChrootEveryone echo "yes" > /etc/pure-ftpd/conf/CreateHomeDir echo "no" > /etc/pure-ftpd/conf/UnixAuthentication echo "no" > /etc/pure-ftpd/conf/PAMAuthentication echo "yes" > /etc/pure-ftpd/conf/NoAnonymous
4 Le serveur Mail
4.1Création des bases
Voici le schéma SQL sur lequel je me base. Les tables alias et forward sont redondates et je pourrais m’en passer. Cependant, j’apprécie assez d’avoir une distinction entre ce qui est redirigé sur une adresse virtuelle locale et ce qui est transmis à une adresse extérieure.
CREATE TABLE IF NOT EXISTS `alias` ( `address` varchar(255) NOT NULL default '', `goto` text NOT NULL, `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`address`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `domain` ( `domain` varchar(255) NOT NULL default '', `description` varchar(255) NOT NULL default '', `aliases` int(10) NOT NULL default '0', `mailboxes` int(10) NOT NULL default '0', `maxquota` bigint(20) NOT NULL default '0', `quota` bigint(20) NOT NULL default '0', `transport` varchar(255) default NULL, `backupmx` tinyint(1) NOT NULL default '0', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`domain`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `forward` ( `address` varchar(255) NOT NULL default '', `goto` text NOT NULL, `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`address`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `mailbox` ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `name` varchar(255) NOT NULL default '', `maildir` varchar(255) NOT NULL default '', `quota` bigint(20) NOT NULL default '0', `antivirus` enum('0','1') NOT NULL default '1', `antispam` enum('0','1') NOT NULL default '1', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
4.2 Création des comptes
Ajout d’un domaine :
INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `maxquota`, `quota`, `transport`, `backupmx`, `created`, `modified`, `active`) VALUES ('domaine.com', 'Mon domaine à moi que j'ai', 0, 0, 0, 0, '', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1);
Ajout d’un compte :
INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `antivirus`, `antispam`, `domain`, `created`, `modified`, `active`) VALUES ('julien@domaine.com', 'secret', 'Julien MOROT', 'morot.fr/julien@morot.fr/', 512000, '1', '1', 'morot.fr', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1);
Ajout d’un alias :
INSERT INTO `alias` (`address`, `goto`, `domain`, `created`, `modified`, `active`) VALUES ('jaune@domaine.com', 'julien@domaine.com', 'domaine.com', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1);
5 Paramétrage du SMTP Postfix
L’essentiel du paramétrage consiste à indiquer à Postfix dans le fichier /etc/postfix/main.cf comment se connecter pour aller chercher les informations sur les comptes virtuels. Par la suite il faut créer le contenu des fichiers contenant la méthode utilisée pour récupérer les informations souhaitées.
virtual_uid_maps = static:2000 virtual_gid_maps = static:2000 virtual_transport = dovecot virtual_mailbox_limit = 0 virtual_alias_maps = proxy:mysql:/etc/postfix/mysql/virtual_alias_maps.cf, proxy:mysql:/etc/postfix/mysql/virtual_forward_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql/virtual_domains_maps.cf virtual_mailbox_base = /home/vmails relay_domains = proxy:mysql:/etc/postfix/mysql/virtual_relay_domains_maps.cf proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks
Fichier /etc/postfix/mysql/virtual_alias_maps.cf
user = postfix password = secret dbname = VMAILS query = SELECT goto FROM alias WHERE address='%s' hosts = 127.0.0.1
Fichier /etc/postfix/mysql/virtual_domains_maps.cf
user = postfix password = secret dbname = VMAILS query = SELECT domain FROM domain WHERE domain='%s' AND active=1 hosts = 127.0.0.1
Fichier /etc/postfix/mysql/virtual_forward_maps.cf
user = postfix password = secret dbname = VMAILS query = SELECT goto FROM forward WHERE address='%s' hosts = 127.0.0.1
Fichier /etc/postfix/mysql/virtual_mailbox_maps.cf
user = postfix password = secret dbname = VMAILS query = SELECT CONCAT(maildir, '/Maildir/') FROM mailbox WHERE username='%s' AND active=1 hosts = 127.0.0.1
Fichier /etc/postfix/mysql/virtual_relay_domains_maps.cf
user = postfix password = secret dbname = VMAILS query = SELECT domain FROM domain WHERE domain='%s' AND active=1 AND backupmx=1 hosts = 127.0.0.1
Pour certaines raisons (support de Sieve et des quotas, je souhaite utiliser le LDA de Dovecot, il faut donc paramétrer postfix pour qu’il sache comment gérer le paramètre virtual_transport définit précédemment. Il faut donc rajouter dans le fichier master.cf ceci :
dovecot unix - n n - - pipe flags=DRhu user=vmails:vmails argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
Création du compte virtuel :
addgroup --gid 2000 vmails adduser --home /dev/null --shell /bin/false --no-create-home --uid 2000 --disabled-password --ingroup toto --disabled-login vmails
6 Paramétrage du serveur POP/IMAP Dovecot
Installation :
# apt-get install dovecot-common dovecot-imapd dovecot-pop3d
Fichier /etc/dovecot/dovecot.conf : Rien de spécial, on active simplement les modules et le support des protocoles que l’on souhaite que dovecot gère.
protocols = imap pop3 managesieve disable_plaintext_auth = no log_timestamp = "%Y-%m-%d %H:%M:%S " mail_privileged_group = mail mail_debug = yes protocol imap { mail_plugins = quota imap_quota acl imap_client_workarounds = outlook-idle delay-newmail } protocol pop3 { pop3_uidl_format = %08Xu%08Xv mail_plugins = quota pop3_client_workarounds = outlook-no-nuls oe-ns-eoh } protocol lda { postmaster_address = postmaster@example.com mail_plugin_dir = /usr/lib/dovecot/modules/lda auth_socket_path = /var/run/dovecot/auth-master mail_plugins = cmusieve quota } auth_verbose = yes auth_debug = yes auth default { mechanisms = plain login passdb sql { args = /etc/dovecot/dovecot-sql.conf } userdb sql { args = /etc/dovecot/dovecot-sql.conf } user = root socket listen { master { path = /var/run/dovecot/auth-master mode = 0600 user = vmails group = vmails } client { path = /var/run/dovecot/auth-client mode = 0660 } } } dict { } plugin { quota = maildir } protocol managesieve { sieve=~/.dovecot.sieve sieve_storage=~/sieve }
Fichier /etc/dovecot/dovecot-sql.conf : il un point particulier dans ce fichier. Comme je souhaite utiliser sieve pour traiter les messages via le LDA de dovecot, il faut que je retourne un répertoire personnel pour le compte mail d’où le home renvoyé par la user_query :
default_pass_scheme = PLAIN password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = 1 user_query = SELECT CONCAT('/home/vmails/', maildir) AS home, CONCAT('maildir:/home/vmails/', maildir, '/Maildir/') AS mail, CONCAT('maildir:storage=', quota) AS quota, 2000 AS uid, 2000 AS gid FROM mailbox WHERE username = '%u'
7 Authentification SMTP
Installation des paquets nécessaires :
# apt-get install sasl2-bin libsasl2-modules
Comme on se basera sur le démon saslauthd et que l’on utilisera PAM pour s’authentifier, il faut paramétrer ce démon comme il se doit. Tout se fait dans le fichier /etc/default/saslauthd
:
START=yes MECHANISMS="pam" MECH_OPTIONS="" THREADS=5 OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"
Le paramètre -m est indispensable car comme postfix est chrooté par défaut sous Debian, il faut qu’il puisse communiquer avec saslauthd.
Donc comme je disais que saslauthd utilisera PAM pour s’authentifier, il faut bien un fichier /etc/pam.d/smtp proprement paramétré.
auth required pam_nologin.so auth required pam_mysql.so user=postfix passwd=secret host=localhost db=VMAILS table=mailbox usercolumn=username passwdcolumn=password crypt=0 #auth required pam_unix.so auth required pam_env.so # [1] account sufficient pam_mysql.so user=postfix password=secret host=localhost db=VMAILS table=mailbox usercolumn=username passwdcolumn=password crypt=1 account required pam_unix.so
Le reste est des plus clasique pour toute personne ayant déja paramétré Postfix pour qu’il support SASL donc rien de plus à préciser.
Ajouter au fichier /etc/postfix/main.cf :
broken_sasl_auth_clients = yes smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination smtpd_sasl_auth_enable = yes smtpd_sasl_local_domain = $mydomain smtpd_sasl_security_options = noanonymous
Et créer un fichier /etc/postfix/sasl/smtpd.conf contenant :
pwcheck_method: saslauthd auxprop mech_list: login plain auxprop_plugin: sql sql_engine: mysql sql_hostnames: localhost sql_user: postfix sql_database: VMAILS sql_passwd: secret sql_select: select password from mailbox where username = '%u@%r'
8 Conclusion
J’ai donné assez peu d’explications car au final l’essentiel du paramétrage se résume à indiquer où chercher les données dans la base SQL. L’important étant d’avoir un schéma de base de données propre et clair permettant de tout bien structurer.