Go to content Go to navigation Go to search

ProFTPD with virtual users

August 5th, 2010 by jde

Installation

# cd /usr/ports/ftp/proftpd-mysql
# make install clean

[ ] BAN              Include mod_ban (Requires CTRLS)
[ ] CLAMAV           Include mod_clamav
[ ] CTRLS            Include controls
[ ] EXEC             Include mod_exec
[X] HTMLDOCS         Include HTML documentation
[X] IFSESSION        Include mod_ifsession
[ ] IPV6             Use IPv6
[ ] LDAP             Use LDAP
[ ] LDAP_TLS         Use LDAP TLS (Requires LDAP, OPENSSL)
[X] MYSQL            MySQL auth
[X] NLS              Use nls (builds mod_lang)
[ ] ODBC             ODBC
[X] OPENSSL          Include mod_tls
[ ] PGSQL            Postgres auth
[X] QUOTA            Include mod_quota
[ ] QUOTATAB_RADIUS  include mod_quotatab_radius
[ ] SHAPER           Shaper module
[ ] SQLITE           SQLite auth
[X] RADIUS           Include mod_radius
[X] RATIO            Include mod_ratio
[X] README           Include mod_readme
[X] REWRITE          Include mod_rewrite
[ ] TLS_SHMCACHE     TLS SHM session cache (requires OPENSSL)
[ ] TDS              Include mod_sql_tds
[X] SFTP             Include mod_sftp
[X] SFTP_SQL         Include mod_sftp_sql
[ ] SFTP_PAM         Include mod_sftp_pam
[ ] SITE_MISC        Include mod_site_misc
[ ] SQL_PASSWD       Include mod_sql_passwd
[ ] UNIQUE           Include mod_unique_id
[X] WRAP             Include mod_wrap2
[ ] WRAP_FILE        Include mod_wrap2_file (requires WRAP)
[ ] WRAP_SQL         Include mod_wrap2_sql (requires WRAP)

After installation add this line to /etc/rc.conf:

proftpd_enable="YES"

As you probably know, this will ensure that ProFTPD is started automatically when the server is booted.

Dedicating a range of user id’s

You must decide on a range of user id’s which will be dedicated to ProFTPD and never be used for a unix user. Here is the rules I am following:

Range Used by…
0 – 199 the operating system. System privileged users.
200 – 999 various applications
1000 – 1999 Unix users. People with ssh access
2000 – 2999 virtual ProFTPD users

The above is just a guideline. You can of course decide on a range of your choice, but don’t mess with usernumbers below 200. As you can see I have dedicated the range 2000-2999 to virtual ProFTPD users.

Setup MySQL tables

If you wish to have ProFTPD related data in a seperate database (recommended), create the new database – remember to login to mysql first or use an interface like phpMyAdmin:

create database proftpd;

Create a mysql user for the proftpd daemon. The below will give access to all tables in the database, which is fine if you created the proftpd database. But if the tables is in an existing database, make sure that this user only has access to proftpd related tables.

GRANT SELECT , INSERT , UPDATE , DELETE ON `proftpd` . * TO 'proftpd'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

Remember to replace ‘password’ with one of your choice.

If you are in a mysql prompt, use this command to make sure you have selected the proftpd database, before you attempt to create the tables:

use proftpd;

Next create the necessary tables – just copy/paste the below into your mysql prompt or use it in your mysql interface (e.g. phpmyadmin):

CREATE TABLE ftpgroup (
groupname varchar(16) NOT NULL default '',
gid smallint(6) NOT NULL default '80',
members varchar(16) NOT NULL default '',
KEY groupname (groupname)
) TYPE=MyISAM COMMENT='ProFTP group table';

CREATE TABLE ftpquotalimits (
name varchar(30) default NULL,
quota_type enum('user','group','class','all') NOT NULL default 'user',
per_session enum('false','true') NOT NULL default 'false',
limit_type enum('soft','hard') NOT NULL default 'soft',
bytes_in_avail int(10) unsigned NOT NULL default '0',
bytes_out_avail int(10) unsigned NOT NULL default '0',
bytes_xfer_avail int(10) unsigned NOT NULL default '0',
files_in_avail int(10) unsigned NOT NULL default '0',
files_out_avail int(10) unsigned NOT NULL default '0',
files_xfer_avail int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM;

CREATE TABLE ftpquotatallies (
name varchar(30) NOT NULL default '',
quota_type enum('user','group','class','all') NOT NULL default 'user',
bytes_in_used int(10) unsigned NOT NULL default '0',
bytes_out_used int(10) unsigned NOT NULL default '0',
bytes_xfer_used int(10) unsigned NOT NULL default '0',
files_in_used int(10) unsigned NOT NULL default '0',
files_out_used int(10) unsigned NOT NULL default '0',
files_xfer_used int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM;

CREATE TABLE ftpuser (
id int(10) NOT NULL auto_increment,
userid varchar(32) NOT NULL default '',
passwd varchar(32) NOT NULL default '',
uid smallint(6) NOT NULL default '',
gid smallint(6) NOT NULL default '80',
homedir varchar(255) NOT NULL default '',
shell varchar(16) NOT NULL default '/sbin/nologin',
count int(11) NOT NULL default '0',
accessed datetime NOT NULL default '0000-00-00 00:00:00',
modified datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id),
UNIQUE KEY userid (userid)
) TYPE=MyISAM COMMENT='ProFTP user table';

Note that the gid field in the ftpgroup and ftpuser tables are set to be 80 by default. Change this to reflect the group id of your systems webserver user.

Configure ProFTPD

Open /usr/local/etc/proftpd.conf and uncomment this line:

DefaultRoot ~

If you do not want or have support for IPv6, comment this line:

#UseIPv6 on

Add this at the end of the file and replace password with the one you chose for the proftpd user (see SQLConnectInfo):

# The passwords in MySQL are encrypted using CRYPT
SQLAuthTypes Plaintext Crypt
SQLAuthenticate users* groups*

# used to connect to the database
# databasename@host database_user user_password
SQLConnectInfo proftpd@localhost proftpd password

# Here we tell ProFTPd the names of the database columns in the "usertable"
# we want it to interact with. Match the names with those in the db
SQLUserInfo ftpuser userid passwd uid gid homedir shell

# Here we tell ProFTPd the names of the database columns in the "grouptable"
# we want it to interact with. Again the names match with those in the db
SQLGroupInfo ftpgroup groupname gid members

# set min UID and GID - otherwise these are 999 each
SQLMinID 2000

# create a user's home directory on demand if it doesn't exist. Create it with 755 permission (rwx-r-x-r-x)
CreateHome on dirmode 755

# Update count every time user logs in
SQLLog PASS updatecount
SQLNamedQuery updatecount UPDATE "count=count+1, accessed=now() WHERE userid='%u'" ftpuser

# Update modified everytime user uploads or deletes a file
SQLLog STOR,DELE modified
SQLNamedQuery modified UPDATE "modified=now() WHERE userid='%u'" ftpuser

# User quotas
# ===========
QuotaEngine on
QuotaDirectoryTally on
QuotaDisplayUnits Mb
QuotaShowQuotas on

SQLNamedQuery get-quota-limit SELECT "name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail FROM ftpquotalimits WHERE name = '%{0}' AND quota_type = '%{1}'"

SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used, bytes_out_used, bytes_xfer_used, files_in_used, files_out_used, files_xfer_used FROM ftpquotatallies WHERE name = '%{0}' AND quota_type = '%{1}'"

SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used = files_out_used + %{4},files_xfer_used = files_xfer_used + %{5} WHERE name = '%{6}' AND quota_type = '%{7}'" ftpquotatallies

SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" ftpquotatallies

QuotaLimitTable sql:/get-quota-limit
QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally

RootLogin off
RequireValidShell off

Create an ftp user

Before you can test your setup, let’s create an ftp user.:

First create a row in the ftpgroup table. Remember to change the values to reflect your webservers unix user:

INSERT INTO ftpgroup (groupname, gid, members) VALUES ('www', 80, 'www');

You only have to run the above query once. The inserts below is the ones you’ll use every time you add a new ftp user:

INSERT INTO ftpquotalimits (name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail) VALUES ('username', 'user', 'true', 'hard', 15728640, 0, 0, 0, 0, 0);

INSERT INTO ftpuser (userid, passwd, uid, gid, homedir, shell, count, accessed, modified) VALUES ('username', 'password', 2000, 80, '/usr/local/www/domain.tld', '/sbin/nologin', 0, '', '');

Remember to make any changes to reflect your own settings. Each field of the ftpquotalimits and ftpuser tables are explained at the bottom of this page.

Next time you create an ftp user, you’ll set the user id to 2001 and so forth.

If the home directory (homedir) is not created yet, ProFTPD will do this automatically. But if it exist, you must ensure that it has the correct user and group. The following command will set user id to 2000 and group to www recursively:

chown -R 2000:www /usr/local/www/domain.tld

Testing…

Start ProFTPD:

# /usr/local/etc/rc.d/proftpd start

Fire up your favorite ftp client from your desktop and try to connect to your server.

ftpuser and ftpquotalimits explained

This is the fields which you’ll fill when creating a new user. Don’t touch any other fields, since they are handled by MySQL or Proftpd automatically

ftpuser table:

* userid: The name of the virtual Proftpd user (e.g. exampleuser).
* passwd: The unencrypted (i.e., clear-text) password of the user.
* uid: The users id (e.g. 2000, 2001 an so forth).
* gid: The groupid of the systems webserver (e.g. 80).
* homedir: The home directory of the virtual Proftpd user (e.g. /usr/local/www/domain.tld). If it does not exist, it will be created when the new user logs in the first time via FTP. The virtual user will be jailed into this home directory, i.e., he cannot access other directories outside his home directory.
* shell: It is ok if you fill in /sbin/nologin here by default. Ftp users do not need a shell.

ftpquotalimits table:

* name: The name of the virtual Proftpd user (e.g. exampleuser).
* quota_type: user or group. Normally, we use user here.
* per_session: true or false. true means the quota limits are valid only for a session. For example, if the user has a quota of 15 MB, and he has uploaded 15 MB during the current session, then he cannot upload anything more. But if he logs out and in again, he again has 15 MB available. false means, that the user has 15 MB at, no matter if he logs out and in again.
* limit_type: hard or soft. A hard quota limit is a never-to-exceed limit, while a soft quota can be temporarily exceeded. Normally you use hard here.
* bytes_in_avail: Upload limit in bytes (e.g. 15728640 for 15 MB). 0 means unlimited.
* bytes_out_avail: Download limit in bytes. 0 means unlimited.
* bytes_xfer_avail: Transfer limit in bytes. The sum of uploads and downloads a user is allowed to do. 0 means unlimited.
* files_in_avail: Upload limit in files. 0 means unlimited.
* files_out_avail: Download limit in files. 0 means unlimited.
* files_xfer_avail: Tranfer limit in files. 0 means unlimited.

The ftpquotatallies table is used by Proftpd internally to manage quotas so you do not have to make entries there.

Troubleshooting

If you need to debug, run the daemon in the foreground as shown here. I will output information to your screen:

#proftpd -n -d 9
- mod_tls/2.1.2: using OpenSSL 0.9.7e-p1 25 Oct 2004
- SQLAuthenticate: use of * in SQLAuthenticate has been deprecated. Use AuthOrder for setting authoritativenes
- SQLAuthenticate: use of * in SQLAuthenticate has been deprecated. Use AuthOrder for setting authoritativeness
- warning: the SQLHomedirOnDemand directive is deprecated, and will be removed in the next release
your.hostname.tld -
your.hostname.tld - Config for ProFTPD Default Installation:
your.hostname.tld - Limit
your.hostname.tld - DenyAll
your.hostname.tld - DefaultServer
[...]

In this example the loglevel is set to the highest possible value (9).

Press [CTRL]+[C] to exit and stop the proftpd daemon.

Thanks to Howto forge – Virtual Hosting With Proftpd And MySQL

9. Roundcube webmail

August 3rd, 2010 by jde

Postfix Tutorial – Step 9

Roundcube webmail

Roundcube is a modern webmail GUI with sieve support.

Install Roundcube webmail:

# cd /usr/ports/mail/roundcube
# make install clean

Options for roundcube 0.4.b,1 

[X] MYSQL     Use MySQL backend
[ ] PGSQL     Use PostgreSQL backend
[ ] SQLITE    Use SQLite backend
[X] SSL       Enable SSL support (imaps or google spellcheck)
[X] LDAP      Enable LDAP support (address book)
[X] PSPELL    Enable PSpell support (internal spellcheck)
[X] NSC       Install network spellchecker
[X] AUTOCOMP  Enable autocomplete in login form

Connect to mysql, create a user and a database for rundcube. Then run the initial sql script:
Remember to replace username and password with something else.

 # mysql -u root -p
Enter password:

mysql> CREATE DATABASE roundcubemail;
mysql> GRANT ALL PRIVILEGES ON roundcubemail.* TO username@localhost IDENTIFIED BY 'password';
mysql> FLUSH PRIVILEGES;
mysql> USE roundcubemail;
mysql> SOURCE /usr/local/www/roundcube/SQL/mysql.initial.sql

Open the Roundcube database configuration file /usr/local/www/roundcube/config/db.inc.php and edit the database connection string:

$rcmail_config['db_dsnw'] = 'mysql://username:password@localhost/roundcubemail';

Open the Roundcube main configuration file /usr/local/www/roundcube/config/main.inc.php and activate the sieve plugin:

$rcmail_config['plugins'] = array('managesieve');

This plugin presents itself in the GUI with a ‘Filter’ tab under “Personal settings”.

The login form includes a ‘Server’ field. You can remove it by setting ‘default_host’:

$rcmail_config['default_host'] = 'mail.example.com';

8. Server-side mail filtering

August 3rd, 2010 by jde

Postfix Tutorial – Step 8

Server-side mail filtering

Many people maintain a set of filtering rules in their email clients. Incoming emails from grandma are automatically moved to the ‘family’ folder, and emails from your ex is moved to ‘trash’. Whatever suits your needs. This is a neat way of keeping things in order… but only until you start reading mail on your smart phone, netbook or use a webmail. With server side filters, no matter where you are or what gadget you use to fetch your mail, the same filters are applied.

Dovecot comes with a Sieve plugin to make this happen.

At the end of /usr/local/etc/dovecot.conf you will find a plugin section. Within that section locate the commented section about Sieve and add this line:

sieve_global_path=/usr/local/virtual/globalsieverc

In the protocol lda section uncomment this line (or add it if it’s not there):

mail_plugins = sieve

The globalsieverc file is a set of global filtering rules which applies to all users until they create their own rules.

Create /usr/local/virtual/globalsieverc with the following content:

require ["fileinto"];
# Move spam to spam folder
if header :contains "X-spam-flag" ["YES"] {
  fileinto "spam";
  stop;
}

Make the file readable by the vmail user:

# chown vmail /usr/local/virtual/globalsieverc

Restart Dovecot:

# /usr/local/etc/rc.d/dovecot restart
Stopping dovecot.
Waiting for PIDS: 56704.
Starting dovecot.

!!NOTE!! The name of the folder is case sensitive and if the folder does not exist, Dovecot will not fail or report it in the log. The folder is just created.

Send a spam mail to one of your accounts. It should be delivered in the spam folder of the account.

# sendmail my@examplemail.com < gtube.txt

Watch the dovecot-deliver.log:

Info: sieve: msgid=<GTUBE1.1010101@example.net>: stored mail into mailbox 'spam'

7. Spam and virus detection

August 1st, 2010 by jde

Postfix Tutorial – Step 7

Spam and virus detection

AMaViS (A Mail Virus Scanner) gives you protection against spam through Spamassassin and virus protection with Clamav (optional):

Let’s install AMaViS:

# cd /usr/ports/security/amavisd-new/
# make install clean

Options for amavisd-new 2.6.4_7,1

[X] BDB           Use BerkeleyDB for nanny/cache/snmp
[ ] SNMP          Install amavisd snmp subagent
[ ] SQLITE        Use SQLite for lookups
[X] MYSQL         Use MySQL for lookups/logging/quarantine
[ ] PGSQL         Use PgSQL for lookups/logging/quarantine
[ ] LDAP          Use LDAP for lookups
[ ] SASL          Use SASL authentication
[X] MILTER        Sendmail milter support
[X] SPAMASSASSIN  Use mail/p5-Mail-SpamAssassin
[ ] P0F           Passive operating system fingerprinting
[ ] ALTERMIME     Use AlterMime for defanging/disclaimers
[X] FILE          Use newer file(1) utility from port
[ ] RAR           RAR support with archivers/rar
[X] UNRAR         RAR support with archivers/unrar
[X] ARJ           ARJ support with archivers/arj
[ ] UNARJ         ARJ support with archivers/unarj
[X] LHA           LHA support with archivers/lha
[X] ARC           ARC support with archivers/arc
[ ] NOMARCH       ARC support with archivers/nomarch
[X] CAB           CAB support with archivers/cabextract
[X] RPM           RPM support with archivers/rpm2cpio
[X] ZOO           ZOO support with archivers/zoo
[ ] UNZOO         ZOO support with archivers/unzoo
[X] LZOP          LZOP support with archivers/lzop
[X] FREEZE        FREEZE support with archivers/freeze
[X] P7ZIP         P7ZIP support with archivers/p7zip
[X] MSWORD        Ms Word support with textproc/ripole
[ ] TNEF          Add external tnef decoder converters/tnef

Some time during the installation, you will also be prompted for SpamAssassin options:

Options for p5-Mail-SpamAssassin 3.3.1

[X] AS_ROOT        Run spamd as root (recommended)
[X] SPAMC          Build spamd/spamc (not for amavisd)
[ ] SACOMPILE      sa-compile
[X] DKIM           DKIM/DomainKeys Identified Mail
[X] SSL            Build with SSL support for spamd/spamc
[X] GNUPG          Install GnuPG (for sa-update)
[X] MYSQL          Add MySQL support
[ ] PGSQL          Add PostreSQL support
[X] RAZOR          Add Vipul's Razor support
[ ] SPF_QUERY      Add SPF query support
[ ] RELAY_COUNTRY  Relay country support
[ ] DCC            Add DCC support (see LICENSE)

Install Clamav:

# cd /usr/ports/clamav/
# make install clean

Options for clamav 0.96.1

[X] ARC           Enable arch archives support
[X] ARJ           Enable arj archives support
[X] LHA           Enable lha archives support
[X] UNZOO         Enable zoo archives support
[X] UNRAR         Enable rar archives support
[X] LLVM          Enable JIT Bytecode compiler
[ ] MILTER        Compile the milter interface
[ ] LDAP          libmilter was built with LDAP
[ ] ICONV         Enable ICONV support
[ ] STDERR        Print logs to stderr instead of stdout
[ ] EXPERIMENTAL  Build experimental code

In /etc/rc.conf:

amavis_milter_enable="YES"
amavisd_enable="YES"
clamav_clamd_enable="YES"
clamav_freshclam_enable="YES"
spamd_enable="YES"

Run sa-update to download configuration files (rules, scores, etc,) for SpamAssassin (Read more…), then start AMaViS and make sure it starts up correctly:

# rehash
# sa-update
# /usr/local/etc/rc.d/amavisd start
Starting amavisd.
# ps -ax | grep amavis
55743  ??  Ss     0:02.77 amavisd (master) (perl)
55744  ??  I      0:00.01 amavisd (virgin child) (perl)
55745  ??  I      0:00.01 amavisd (virgin child) (perl)
# netstat -p tcp -a | grep 10024
tcp4       0      0 localhost.10024        *.*                    LISTEN

Note that the startup command for AMaViS may fail silently, so if you don’t see it listening consult /var/log/maillog.

In /usr/local/etc/postfix/main.cf add these lines:

# Amavis content filtering
content_filter=smtp-amavis:[127.0.0.1]:10024
receive_override_options=no_address_mappings

In /usr/local/etc/postfix/master.cf add these lines:

smtp-amavis unix -       -       n       -       2       smtp
    -o smtp_data_done_timeout=1200
    -o smtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20
127.0.0.1:10025 inet n  -       -       -       -       smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=reject_unauth_pipelining
    -o smtpd_end_of_data_restrictions=
    -o mynetworks=127.0.0.0/8
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
    -o local_header_rewrite_clients=

Reload Postfix:

# postfix reload
postfix/postfix-script: refreshing the Postfix mail system

Add clamav user to the vscan group in /etc/group:

Find these lines:

vscan:*:110:
clamav:*:106:

Change them to:

vscan:*:110:clamav
clamav:*:106:vscan

Start clamav (be patient, it may take a while before you get the prompt back):

# /usr/local/etc/rc.d/clamav-clamd start
Starting clamav_clamd.
LibClamAV Warning: **************************************************
LibClamAV Warning: ***  The virus database is older than 7 days!  ***
LibClamAV Warning: ***   Please update it as soon as possible.    ***
LibClamAV Warning: **************************************************

You can ignore this warning since clamav-freshclam will take care of that from now on. Let’s start it:

# /usr/local/etc/rc.d/clamav-freshclam start

Open /usr/local/etc/amavisd.conf and locate the @lookup_sql_dsn section. Edit it so that it looks like this:

@lookup_sql_dsn = (
     ['DBI:mysql:database=postfix;host=127.0.0.1;port=3306',
      'postfix',
      'password']);

$sql_select_policy = 'SELECT domain as name FROM domain WHERE CONCAT("@",domain) IN (%k)';

Also locate the @av_scanners section, and make sure clamav is uncommented:

### http://www.clamav.net/
['ClamAV-clamd',
   \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"],
   qr/\bOK$/m, qr/\bFOUND$/m,
   qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

Also tell AMaViS to let spam pass … It will be deliveret to the users inbox and then each user can set their own “Sieve” options.
Whatever you do, do not set $final_spam_destiny to D_BOUNCE. Spam is never sent from the spammers own email address, to you’ll just end up annoying (innocent) people.

$final_spam_destiny = D_PASS;
$spam_quarantine_to = undef;

Restart AMaViS:

# /usr/local/etc/rc.d/amavisd restart
Stopping amavisd.
Waiting for PIDS: 55743 55744 55745, 55743.
Starting amavisd.

Test AMaViS spam detection with this message: spamassassin.apache.org/gtube/gtube.txt
Replace my@examplemail.com with an existing mail account on your server.

# fetch http://spamassassin.apache.org/gtube/gtube.txt
# sendmail my@examplemail.com < gtube.txt

Your maillog should look something like this:

postfix/pickup[59535]: 13CF27CD: uid=0 from=<root>
postfix/cleanup[59586]: 13CF27CD: message-id=<GTUBE1.1010101@example.net>
postfix/qmgr[59173]: 13CF27CD: from=<root@examplemail.com>, size=938, nrcpt=1 (queue active)
postfix/smtpd[59590]: connect from unknown[127.0.0.1]
postfix/smtpd[59590]: 28DC17C8: client=unknown[127.0.0.1]
postfix/cleanup[59586]: 28DC17C8: message-id=<GTUBE1.1010101@example.net>
postfix/qmgr[59173]: 28DC17C8: from=<root@examplemail.com>, size=1673, nrcpt=1 (queue active)
amavis[59204]: (59204-01) Passed SPAM, <root@examplemail.com> -> <my@examplemail.com>, Message-ID: <GTUBE1.1010101@example.net>, mail_id: x1U2T7du28CF, Hits: 1005.069, size: 938, queued_as: 28DC17C8, 42885 ms
postfix/smtp[59588]: 13CF27CD: to=<my@examplemail.com>, relay=127.0.0.1[127.0.0.1]:10024, delay=50, delays=0.62/0.26/11/38, dsn=2.0.0, status=sent (250 2.0.0 from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 28DC17C8)
postfix/qmgr[59173]: 13CF27CD: removed
postfix/pipe[59592]: 28DC17C8: to=<my@examplemail.com>, relay=dovecot, delay=3, delays=0.17/0.27/0/2.6, dsn=2.0.0, status=sent (delivered via dovecot service)
postfix/qmgr[59173]: 28DC17C8: removed
clamav:*:106:

5. SMTP authentication

August 1st, 2010 by jde

Postfix Tutorial – Step 5

SMTP authentication

You need to effectively prevent spammers from abusing your mail server. SASL (Simple Authentication and Security Layer) is an Internet standard method for adding authentication support to connection-based protocols such as SMTP. Dovecot includes a SASL framework that Postfix can use and therefore SMTP authentication has become very easy to setup.

Open /usr/local/etc/postfix/main.cf and set these values:

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sender_login_maps = mysql:/usr/local/etc/postfix/smtpd_sender_login_maps.cf
smtpd_sender_restrictions =
   reject_sender_login_mismatch
smtpd_recipient_restrictions =
   permit_mynetworks,
   permit_sasl_authenticated,
   reject_unauth_destination,
   reject_non_fqdn_hostname,
   reject_non_fqdn_sender,
   reject_non_fqdn_recipient,
   reject_unauth_pipelining,
   reject_invalid_hostname,
   reject_rbl_client sbl-xbl.spamhaus.org,
   reject_rbl_client korea.services.net,
   reject_rhsbl_sender dsn.rfc-ignorant.org

The first three lines enables Postfix to use dovecot SASL authentication. Line 7 (smtpd_recipient_restrictions) includes some other restrictions that will make it hard to deliver spam to local accounts. Later we will also add content checking with Spamassassin. Below you’ll find a short explanation for each of the above lines.:

  • smtpd_sasl_type
    Tell postfix to use dovecot for smtp authentication
  • smtpd_sasl_path
    Path to Dovecot SASL socket. Make sure the path is equal to ‘path’ in the ‘socket listen’->’client’ section of dovecot.conf
  • smtpd_sasl_auth_enable
    Tell postfix to enable SASL authentication
  • smtpd_sender_login_maps
    Look up allowed sender addresses in the database
  • smtpd_sender_restrictions
    Restrictions specific to the sender address received with the MAIL FROM command

    • reject_sender_login_mismatch
      Reject sender if the address in MAIL FROM command is not listed in smtpd_sender_login_maps
  • smtpd_recipient_restrictions
    Rules applied right after Postfix receives the `rcpt to` command:
    • permit_mynetworks
      Permit senders in the local network (mynetworks)
    • permit_sasl_authenticated
      Permit authenticated senders (users with a local mail account)
    • reject_unauth_destination
      Reject mail to unknown accounts. Or said in another way: Permit only mail destined to a user of a domain that is a local or virtual domain on this system (mydestination, virtual_alias_domains or virtual_mailbox_domains).
    • reject_non_fqdn_hostname:
      Reject the request when the HELO or EHLO hostname is not in fully-qualified domain form, as required by the RFC.
    • reject_non_fqdn_sender:
      Reject the request when the MAIL FROM address is not in fully-qualified domain form, as required by the RFC
    • reject_non_fqdn_recipient:
      Reject the request when the RCPT TO address is not in fully-qualified domain form, as required by the RFC
    • reject_invalid_hostname:
      Reject the request when the HELO or EHLO hostname syntax is invalid
    • reject_rbl_client sbl-xbl.spamhaus.org:
      Reject the request when the reversed client network address is listed with any A record under the specified rbl domain.
    • reject_rhsbl_sender dsn.rfc-ignorant.org:
      Reject the request when the MAIL FROM domain is listed with any A record under the specified rbl domain. Use it with care… You will most likely miss mail from Exchange servers and/or other people who misconfigured their mail setup.

Create the file /usr/local/etc/postfix/smtpd_sender_login_maps.cf with the following content:

user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT username envelope FROM mailbox WHERE username = '%s' UNION SELECT address envelope FROM alias WHERE goto='%s'

This query creates a list of allowed sender addresses which lets the user send mail from the actual account and any address aliases pointing to that account.

Restart Postfix and let’s test to see if SMTP authentication works:

# postfix reload

# telnet localhost smtp
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.server.com ESMTP Postfix
ehlo example.com
250-mail.server.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
auth plain am5pQG5lcmRnaXJsLmRrAGpuaUBuZXJkZ2lybC5kawBqbjAzMDM3MQ==
235 2.7.0 Authentication successful
quit
221 2.0.0 Bye
Connection closed by foreign host.

For this test you need to Base64-encode the password. Let’s say the account is julia@example.com and the password is love2bicycle. The encoding is then done like this:

# perl -MMIME::Base64 -e \
'print encode_base64("julia\@example.com\0julia\@example.com\0love2bicycle")';
anVsaWFAZXhhbXBsZS5jb20AanVsaWFAZXhhbXBsZS5jb20AbG92ZTJiaWN5Y2xl

If the test above was successfull, you can test your server against mail-abuse.org:

# telnet relay-test.mail-abuse.org

A series of tests are performed and the output shows the result. At the end – if your server has successfully denied all relay attempts – you should see this message:

Tested host banner: 220 mail.example.com ESMTP Postfix
System appeared to reject relay attempts
Connection closed by foreign host.

6. Secure connections with TLS

August 1st, 2010 by jde

Postfix Tutorial – Step 6

Secure connections with TLS

It is extremely important to communicate over a secture (encrypted) connection. Especially if you plan use your mail accounts on wireless public networks (trains, libraries, restaurants, schools etc). If you don’t you are practically shouting out your password to the world.

On this page you’ll see how to setup Dovecot to offer SSL connections (imaps and pops), and TLS for SMTP connections to Postfix.

First generate a self-signed certificate that will be used for both Dovecot and Postfix:

Prepare directories for the certificates…

# cd /etc/mail/
# mkdir CA
# cd CA
# chmod 700 .
# mkdir certs crl newcerts private
# echo "01" > serial
# touch index.txt
# ln -s ../CA demoCA

Configure yourself as a CA (Certificate Authority).

# openssl req -nodes -new -days 3650 -x509 -keyout private/cakey.pem -out cacert.pem
Generating a 1024 bit RSA private key
.++++++
....++++++
writing new private key to 'private/cakey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DK
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:Copenhagen
Organization Name (eg, company) [Internet Widgits Pty Ltd]: MeAndMy Server
Organizational Unit Name (eg, section) []:SSL Certs
Common Name (eg, YOUR name) []:mail.example.org
Email Address []:postmaster@example.org

Create a certificate:

# openssl req -nodes -new -x509 -keyout server.key -out server.ucrt
Generating a 1024 bit RSA private key
...................................................................++++++
................++++++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DK
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:Copenhagen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MeAndMy Server
Organizational Unit Name (eg, section) []:SSL Cert
Common Name (eg, YOUR name) []:mail.example.org
Email Address []:postmaster@example.org

Create the certificate request:

# openssl x509 -x509toreq -in server.ucrt -signkey server.key -out server.csr
Getting request Private Key
Generating certificate request

Sign the request with the CA certificate:

# openssl ca -policy policy_anything -days 3650 -out server.crt -infiles server.csr
Using configuration from /etc/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
   Serial Number: 1 (0x1)
   Validity
       Not Before: Jul 31 21:56:02 2010 GMT
       Not After : Jul 28 21:56:02 2020 GMT
   Subject:
       countryName               = DK
       localityName              = Lille Skensved
       organizationName          = NerdGirl
       organizationalUnitName    = SSL Cert
       commonName                = gudinde.nerdgirl.dk
       emailAddress              = jette@nerdgirl.dk
   X509v3 extensions:
       X509v3 Basic Constraints:
           CA:FALSE
       Netscape Comment:
           OpenSSL Generated Certificate
       X509v3 Subject Key Identifier:
           F9:CA:02:AE:EA:A5:74:A9:FE:16:39:54:E7:DA:4D:B2:BC:CF:F1:89
       X509v3 Authority Key Identifier:
           keyid:64:3F:F5:19:E2:D9:00:D9:AB:C3:5B:5A:49:62:0F:39:1D:79:40:42
Certificate is to be certified until Jul 28 21:56:02 2020 GMT (3650 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
chmod o= private/cakey.pem

In /usr/local/etc/dovecot.conf find an edit these lines:

protocols = imap imaps managesieve
ssl = yes
ssl_cert_file = /etc/mail/CA/cacert.pem
ssl_key_file = /etc/mail/CA/private/cakey.pem

Restart Dovecot:

# /usr/local/etc/rc.d/dovecot restart
Stopping dovecot.
Starting dovecot.

In /usr/local/etc/postfix/main.cf add these lines:

smtpd_tls_cert_file= /etc/mail/CA/cacert.pem
smtpd_tls_key_file=/etc/mail/CA/private/cakey.pem
smtpd_tls_security_level = may

The smtpd_tls_security_level is set to ‘may’ which means that Postfix does not force it on clients. Users are offered tls as an optional feature.

# postfix reload
postfix/postfix-script: refreshing the Postfix mail system

If Postfix does not announce the TLS option some mail clients will refuse to use TLS. Therefore it is important to check that STARTTLS shows up after the ehlo greeting:

# telnet localhost smtp
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.nerdgirl.dk ESMTP Postfix
ehlo example.com
250-mail.nerdgirl.dk
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.

Edit your mail client preferences and set it up to use TLS. You may have to restart it to make the change take effekt. You will probably be informed that the signature isn’t valid, but that’s because you signed it your self.

4. Dovecot – imap/pop3

July 30th, 2010 by jde

Postfix Tutorial – Step 4

Dovecot – imap/pop3

Dovecot is probably already installed, because we added the Dovecot opton for Postfix. For Dovecot I added the MANAGESIEVE option but still dovecot-managesieve was not installed as a dependency :-| So let’s install the sieve ports…

# cd /usr/ports/mail/dovecot-sieve/
# make install clean
# cd ../dovecot-managesieve/
# make install clean

Add the vmail user:

# adduser
Username: vmail
Full name: vmail
Uid (Leave empty for default): 5000
Login group [vmail]:
Login group is vmail. Invite vmail into other groups? []:
Login class [default]:
Shell (sh csh tcsh nologin) [sh]: nologin
Home directory [/home/vmail]: /usr/local/virtual
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]: yes
Lock out the account after creation? [no]:
Username   : vmail
Password   :
Full Name  : vmail
Uid        : 5000
Class      :
Groups     : vmail
Home       : /usr/local/virtual
Home Mode  :
Shell      : /usr/sbin/nologin
Locked     : no
OK? (yes/no): yes
adduser: INFO: Successfully added (vmail) to the user database.
Add another user? (yes/no): no
Goodbye!

Create dovecot’s logfiles:

# mkdir /var/log/dovecot
# touch /var/log/dovecot/dovecot-deliver.log
# touch /var/log/dovecot/dovecot.log
# chown -R vmail:vmail /var/log/dovecot

Open /usr/local/etc/dovecot.conf

And make sure you edit these sections:

protocols = imap imaps managesieve

disable_plaintext_auth = no

log_path = /var/log/dovecot/dovecot.log

ssl = no

mail_location = maildir:/usr/local/virtual/%d/%n/Maildir

protocol lda {
  log_path = /var/log/dovecot/dovecot-deliver.log
  auth_socket_path = /var/run/dovecot/auth-master
  postmaster_address = postmaster@yourdomain.com
  #mail_plugins = sieve

  [other stuff here....]
}

auth default {
  mechanisms = plain login
  passdb sql {
    args = /usr/local/etc/dovecot-sql.conf
  }
  userdb static {
    args = uid=5000 gid=5000 home=/usr/local/virtual/%d/%n allow_all_users=yes
  }

  socket listen {
    master {
      path = /var/run/dovecot/auth-master
      mode = 0600
      user = vmail
      #group =
    }
    client {
      path = /var/run/dovecot/auth-client
      mode = 0660
      user = postfix
      group = postfix
    }
  }
}

auth_verbose = yes
auth_debug = yes
auth_debug_passwords = yes

Fiks permissions on the file:

# chgrp vmail /usr/local/etc/dovecot.conf
# chmod g+r /usr/local/etc/dovecot.conf

Create /usr/local/etc/dovecot-sql.conf with the following content:

driver = mysql
connect = host=127.0.0.1 dbname=postfix user=postfix password=secret_password
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password FROM mailbox WHERE username='%u';

Make sure that both postfix and dovecot are enabled in /etc/rc.conf

posfix_enable="YES"
dovecot_enable="YES"

Start them:

# /usr/local/etc/rc.d/postfix start
# /usr/local/etc/rc.d/dovecot start

3. Postfix

July 30th, 2010 by jde

Postfix Tutorial – Step 3

Postfix

Install postfix:

# cd /usr/ports/mail/postfix
# make install clean

Options for postfix 2.7.1,1 

[X] PCRE       Perl Compatible Regular Expressions
[ ] SASL2      Cyrus SASLv2 (Simple Auth. and Sec. Layer)
[X] DOVECOT    Dovecot SASL authentication method
[ ] SASLKRB5   If your SASL req. Kerberos5 select this option
[ ] SASLKMIT   If your SASL req. MIT Kerberos5 select this option
[X] TLS        Enable SSL and TLS support
[ ] BDB        Berkeley DB (choose version with WITH_BDB_VER)
[X] MYSQL      MySQL maps (choose version with WITH_MYSQL_VER)
[ ] PGSQL      PostgreSQL maps (choose with DEFAULT_PGSQL_VER)
[ ] OPENLDAP   OpenLDAP maps (choose ver. with WITH_OPENLDAP_VER
[ ] CDB        CDB maps lookups
[ ] NIS        NIS maps lookups
[ ] VDA        VDA (Virtual Delivery Agent 32Bit)
[ ] TEST       SMTP/LMTP test server and generator
[ ] INST_BASE  Install into /usr and /etc/postfix

In /etc/rc.conf

postfix_enable="YES"

Sendmail is the standard MTA of various UNIX platforms. Since I am using Postfix instead, let’s disable it:

Open /etc/rc.conf and add:

sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"

Also disable some Sendmail-specific daily maintenance routines in your /etc/periodic.conf file (If you don’t have a periodic.conf file in /etc, you must create it by making a copy of /etc/default/periodic.conf):

daily_clean_hoststat_enable="NO"
daily_status_mail_rejects_enable="NO"
daily_status_include_submit_mailq="NO"
daily_submit_queuerun="NO"

Find any running sendmail processes an kill them. Here’s an example:

# ps -ax | grep sendmail
440 ?? Ss 0:56.33 sendmail: accepting connections (sendmail)
444 ?? Is 0:00.81 sendmail: Queue runner@00:30:00 for /var/spool/clientmqueue (sendmail)
# kill -9 440
# kill -9 444

FreeBSD generates daily mails with system information to the root user. You must redirect these mails to an actual mail account:

# cd /etc/mail/
# vim aliases

Find root: me@my.domain and correct the address to reflect one of the email accounts you’ve just created in the mailbox table.

Next you must run the newaliases command. It creates both /etc/aliases.db and /etc/mail/aliases.db and therefore we will convert the one in /etc to a soft link that points to the one in /etc/mail.

# newaliases
# rm /etc/aliases.db
# ln -s /etc/mail/aliases.db /etc/aliases.db

Configure main.cf

# vim /usr/local/etc/postfix/main.cf

Change myhostname and mydomain, and uncomment the rest of the lines show here:

myhostname = example.domain.tld
mydomain = domain.tld
myorigin = $mydomain

mydestination = $myhostname, localhost.$mydomain, localhost
local_recipient_maps = unix:passwd.byname $alias_maps

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases

home_mailbox = Maildir/

#Pipe mail per receipient
default_destination_recipient_limit = 1

#Pass incoming mail to dovecot
virtual_transport=dovecot
dovecot_destination_recipient_limit = 1

# configuration related to MySQL.
virtual_alias_maps = mysql:/usr/local/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:5000
virtual_mailbox_base = /usr/local/virtual
virtual_mailbox_domains = mysql:/usr/local/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_mailbox_limit = 51200000
virtual_minimum_uid = 5000
virtual_uid_maps = static:5000

Virtual maps

The three settings: virtual_alias_maps, virtual_mailbox_domains and virtual_mailbox_maps each refer to a file. Create these files in /usr/local/etc/postfix/ with the following content (remember to replace password with the password for the ‘postfix’ database user):

mysql_virtual_alias_maps.cf

user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s'

mysql_virtual_domains_maps.cf:

user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT description FROM domain WHERE domain='%s'

mysql_virtual_mailbox_maps.cf

user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s'

You can check your maps like this:

# postmap -q nerdgirl.dk mysql:/usr/local/etc/postfix/mysql_virtual_domains_maps.cf
NerdGirl

Make sure that only ‘root’ and the ‘postfix’ user can read the “.cf” files – after all your database password is stored there:

# cd /usr/local/etc/postfix/
# chgrp postfix mysql_virtual_*.cf
# chmod u=rw,g=r,o= mysql_virtual_*.cf

Configure master.cf

Add these lines in /usr/local/etc/postfix/master.cf

dovecot   unix  -       n       n       -       -       pipe
   flags=DRhu user=vmail:vmail argv=/usr/local/libexec/dovecot/deliver -d ${recipient}

The second line must be indended with spaces.

1. Mail setup considerations

July 30th, 2010 by jde

Postfix Tutorial – Step 1

Mail setup considerations

Before you enter the exciting world of MTA, SMTP, IMAP, POP and all there happy little friends you must consider the fact that running a mail server these days is fairly complicated. Sending and receiving email isn’t that hard, but you’ll realize that…

  • an open relay is a bad thing …
  • emails contain virus and spam…
  • sending passwords in clear text is a security risk…
  • it’s nice to have webmail access…
  • filtering rules are better if they are handled by the server and not the client…

Soon you will find your self buried in a pile of software like Postfix, Amavis, Spamassassin and Dovecot, trying to make them all play nicely together.

Consider yourself warned!

Choosing MTA

An MTA (Mail Transfer Agent)  is a program that transfers mail between computers. The MTA works behind the scenes, while the user usually interacts with another program, the mail user agent (MUA).

There’s a lot of MTA’s to choose from. FreeBSD comes with Sendmail, the standard MTA under most variants of the Unix operating system. Sendmail is too old and too complicated and therefore not recommended. There a plenty of others to choose from (Exim, Postfix, Qmail and so on).

As a newbie it is almost impossible to make a sensible choice. My advice to you is: ask your friends or consult homepages and newsgroups via Google. Use words like “MTA”, “MTS” and “review” in your search. When you have an idea of which MTA you want, check for howto’s and tutorials that will help you get started. If you only find little or nothing, you might have to reconsider.

Virtual users vs. local users

A local user, is a user with a physical account on the server. These users are created with `adduser`.

A virtual user does not exist on the server. These users often reside in a database.

If your mailusers don’t need direct access to the server, for example via ssh, there’s no need to clutter the system with homedirs. Physical users is also always a security risk. Only server administrators should have physical accounts.

Virtual users is a bit more difficult to setup initially, but since they don’t have access to the server, you don’t have to worry about them.

There’s a lot of other advantages when using virtual users, that I’m sure you’ll discover along the way.

Email storage – mbox vs. maildir

The mbox format concatenates individual messages together in a single file. Only one process can access the mbox file in read/write mode, which means everyone else has to wait for an update to complete (file locking).

The maildir type stores each message in a file of its own. No locking is required. Multiple processes can use maildirs at the same time.

Both have advantages and disadvantages, but as I understand the maildir format is the safest and fastest. If you want to read more about this topic, make a “mbox vs maildir” -Google search

A third but not widely used method is to store mail in a database. But reading a file is much faster than reading from a database, which is probably the reason people avoid this.

SMTP authentication and TLS

In the “old” days, users only authenticated themselves when receiving mail via POP3/IMAP. As a result of that, POP3 and IMAP has built in support for authentication. But to effectively prevent spammers from relaying through your mailserver, it is necessary also to authenticate when sending mail and thus ensuring that everyone using your system, is a legal user.

But when users login, the information is transported to the server in clear text. Someone “listening” to the communication could grab the information and exploit the user account. This means that any communication between client and server should be enctrypted. For that purpose you can use TLS (Transport Layer Security).

The final setup

I have decided to go with this setup:

MTA Postfix using maildir, virtual users and support for Dovecot, TLS and MySQL
Virtual users Every mail user is stored in the database.
IMAP Dovecot – A feature rich and flexible IMAP and POP3 server
Mail filter Dovecot Sieve plugin
Virus scanner Clamav – A high performance virus scanner
Spam filter Spamassassin – A powerfull spam killer
Webmail Roundcube – A modern webmail client written in PHP

Note: I have an older tutorial with Courier IMAP instead of Dovecot, which is still available here.

2. Database preparations

July 30th, 2010 by jde

Postfix Tutorial – Step 2

Database preparations

This mail setup is based on virtual users stored in a MySQL database. If MySQL is not installed yet, please do so and return to this page when you’re done.

The database is identical to the one I used with my old setup. It works, but some of the fields are not in use any more.

The following queries will create the postfix database and the database user ‘postfix’.

Instead of the command prompt, you may want to use phpMyAdmin for this.

Replace secret_pass with a password of your choice.

CREATE DATABASE postfix;

CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'secret_pass';
GRANT SELECT ON `postfix` . * TO 'postfix'@'localhost';
FLUSH PRIVILEGES;

USE postfix;

CREATE TABLE 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(4) NOT NULL default '1',
 PRIMARY KEY (address),
 KEY address (address)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Aliases';

CREATE TABLE domain (
 domain varchar(255) NOT NULL default '',
 description varchar(255) NOT NULL default '',
 aliases int(10) NOT NULL default '-1',
 mailboxes int(10) NOT NULL default '-1',
 maxquota int(10) NOT NULL default '-1',
 created datetime NOT NULL default '0000-00-00 00:00:00',
 modified datetime NOT NULL default '0000-00-00 00:00:00',
 active tinyint(4) NOT NULL default '1',
 PRIMARY KEY (domain),
 KEY domain (domain)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Domains';

CREATE TABLE 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 int(10) 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(4) NOT NULL default '1',
 PRIMARY KEY (username),
 KEY username (username)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Mailboxes';

Heres an example of how to use the above tables:

The table ‘domain’, contains the domains hosted on your server. Replace domain.tld with one of your own domains:

INSERT INTO domain (domain,description) VALUES ('domain.tld','Description of your choice');

The next step demonstrates how to create a mailuser belonging to the above domain. Replace user@domain.tld, Full name and secret_pass with values of your choice. First you need to generate an MD5-crypt password (MD5 is too easy to crack, and therefore MD5-crypt is better). Dovecot has a function to generate such a password, but since you have not installed Dovecot yet please go to step three, install Postfix (which will also install Dovecot) and then continue from here:

# rehash
# dovecotpw -s MD5-CRYPT -p secret_pass
{MD5-CRYPT}$1$7KAL0/7C$xpACuJX5DarLgFH.tGV6M/

You are now ready to add the new account in the mailbox table:

INSERT INTO mailbox (username,password,name,maildir)
VALUES ('user@domain.tld','{MD5-CRYPT}$1$7KAL0/7C$xpACuJX5DarLgFH.tGV6M/',
'Full name','user@domain.tld/');

The table architecture is mainly a copy of my old setup, and therefore some of the fields are not used any more. But it works as is. Remove unused table fields.

« Previous Entries