Virtual Hosting Howto With Virtualmin On CentOS 5.1 - Page 5

Clamav Milter Setup

  • Edit /etc/sysconfig/clamav-milter:
  • Patch the init file to fix socket permissions:

patch /etc/init.d/clamav-milter < clamav-milter.patch


MySQL Setup

Basic Config

  • Listen only to the localhost, edit /etc/my.cnf under the mysqld section:
bind-address =


Set Root Password

  • Set the root password:

service mysqld start
mysqladmin -u root password NEWPASSWORD


SpamAssassin Setup

Basic Config

required_hits 5
report_safe 0
rewrite_header Subject [SPAM]


Create MySQL Database

  • Create the database:

mysqladmin -p create bayes

  • Populate the database:

mysql -p bayes < /usr/share/doc/spamassassin-$(rpm --qf %{VERSION} -q spamassassin)/sql/bayes_mysql.sql

  • Create the user:

mysql -p
mysql> GRANT ALL ON bayes.* TO bayes@localhost IDENTIFIED BY 'password';


Configure To Use DB

  • Edit the file /etc/mail/spamassassin/ and add:
bayes_store_module  Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn       DBI:mysql:bayes:localhost
bayes_sql_override_username bayes
bayes_sql_username  bayes
bayes_sql_password  password


Configure FuzzyOCR

We will be storing the image hashes in a mysql database to improve on performance such that images that we have already scanned do not get scanned again as OCR is a resource intense activity.


Create MySQL Database

  • The sql script creates the database and tables and adds a user fuzzyocr with the password fuzzyocr:

mysql -p < /usr/local/src/devel/FuzzyOcr.mysql

  • Change the password:

mysqladmin -u fuzzyocr -p fuzzyocr password


Basic Settings

  • Edit /etc/mail/spamassassin/ and set the basic options:
focr_path_bin /usr/bin:/usr/local/bin
focr_minimal_scanset 1
focr_autosort_scanset 1
focr_enable_image_hashing 3
focr_logfile /tmp/FuzzyOcr.log


Make FuzzyOCR Use The Database

  • Edit the file /etc/mail/spamassassin/ and add:
focr_mysql_db FuzzyOcr
focr_mysql_hash Hash
focr_mysql_safe Safe
focr_mysql_user fuzzyocr
focr_mysql_pass password
focr_mysql_host localhost
focr_mysql_port 3306
focr_mysql_socket /var/lib/mysql/mysql.sock


SARE Rule Updates

  • Import the GPG key used to sign the rules:

mkdir /etc/mail/spamassassin/sa-update-keys/
chmod 700 /etc/mail/spamassassin/sa-update-keys/
sa-update --import GPG.KEY

  • Create the channels file /etc/mail/spamassassin/sare-sa-update-channels.txt:
  • Create an update script /usr/local/bin/update-sa:
sa-update -D --channelfile /etc/mail/spamassassin/sare-sa-update-channels.txt --gpgkey 856AA88A &>/var/log/sa-updates.log
  • Make it executable and add to cron:

chmod +x /usr/local/bin/update-sa
ln -s /usr/local/bin/update-sa /etc/cron.daily/
ln -s /usr/local/bin/update-sa /etc/cron.hourly/


Spamass-milter Setup

Basic Configuration

  • Edit /etc/sysconfig/spamass-milter:
EXTRA_FLAGS="-m -r 8"



We need to patch the init file to fix the permissions of the socket created such that postfix is able to use the socket.

patch /etc/rc.d/init.d/spamass-milter < spamass-milter.patch


Apache Setup

Disable Modules

We will disable some modules that we are not using thus freeing up memory and also improving security.

  • Edit /etc/httpd/conf/httpd.conf and comment out the modules as below.
#LoadModule ldap_module modules/
#LoadModule authnz_ldap_module modules/
#LoadModule dav_module modules/
#LoadModule status_module modules/
#LoadModule dav_fs_module modules/
#LoadModule proxy_module modules/
#LoadModule proxy_balancer_module modules/
#LoadModule proxy_ftp_module modules/
#LoadModule proxy_http_module modules/
#LoadModule proxy_connect_module modules/
#LoadModule cache_module modules/
#LoadModule disk_cache_module modules/
#LoadModule file_cache_module modules/
#LoadModule mem_cache_module modules/
  • Edit /etc/httpd/conf.d/proxy_ajp.conf and comment out as below:
#LoadModule proxy_ajp_module modules/


Listen To One IP For HTTPS

Apache has to be configured to listed to one address for port 443 as webmin will be using the same port. Edit /etc/httpd/conf.d/ssl:

Listen 192,168.1.6:443


Enable Gzip Compression

We setup gzip compression via the mod_deflate module to improve web server performance and to cut down on bandwidth usage by compressing responses to the client.

SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary

Set up logging for the deflate module:

DeflateFilterNote deflate_ratio
LogFormat "%v %h %l %u %t \"%r\" %>s %b mod_deflate: %{deflate_ratio}n pct." vhost_with_deflate_info
CustomLog logs/deflate_access_log vhost_with_deflate_info


Increase PHP Max Memory

Edit the file /etc/php.ini and set the following:

memory_limit = 64M


Enable Virtual Hosting

NameVirtualHost *:80


Create Default Virtual Host

This needs to be the first virtual host, it will be the default on the server the equivalent of the server with out virtual hosting.

<VirtualHost *:80>
        Servername localhost.localdomain
        Serveradmin root@localhost.localdomain


Roundcube Webmail Setup

Create Database

  • Create the database and add the roundcube user.

mysqladmin -p create roundcube
mysql -p
mysql> GRANT ALL ON roundcube.* TO roundcube@localhost IDENTIFIED BY 'password';

  • Initialize the database:

mysql -u roundcube -p roundcube < /usr/share/doc/roundcube-0.1/SQL/mysql5.initial.sql


Basic Config

  • Configure database DSN in /var/www/roundcube/config/
$rcmail_config['db_dsnw'] = 'mysql://roundcube:password@localhost/roundcube';
  • Configure roundcube in /var/www/roundcube/config/
$rcmail_config['default_host'] = 'localhost';
$rcmail_config['default_port'] = 143;
$rcmail_config['virtuser_file'] = '/etc/postfix/virtual';
$rcmail_config['smtp_server'] = 'localhost';
$rcmail_config['smtp_port'] = 25;
$rcmail_config['smtp_helo_host'] = 'localhost';


Set Up Catch All Virtualhost

As we will be providing webmail for all domains that are created on the system we need to setup a catch all virtualhost that can display roundcube when ever a user accesses http://webmail.domainname. Edit /etc/httpd/conf/httpd.conf and append:

<VirtualHost *:80>
ServerAlias webmail.*
DocumentRoot /var/www/roundcube
<Directory /var/www/roundcube>
Options -Indexes IncludesNOEXEC FollowSymLinks
allow from all


Firewall Setup


This is a basic firewall it may not suit your needs, firewalling is an art so i recommend to read into it to improve on this basic one.


Basic Config

Add these rules in your configuration file /etc/sysconfig/iptables:

-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -p tcp -m multiport -j ACCEPT --dports 80,443,25,110,143,53
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p icmp -m icmp -m limit --icmp-type 8 --limit 5/min -j ACCEPT


Activate Config

service iptables restart

Share this page:

17 Comment(s)

Add comment


From: Anonymous at: 2008-10-21 17:17:16

Kudo's to Andrew and his howto for virtualmin.  I have utilized this in the past to install virtualmin and it works well.  However, since the latest version of virtualmin, there really isn't any need anymore.  Download the script from there site and it will download every needed package and configure them for virtualmin.  Just a little heads up. 

From: Anonymous at: 2009-02-20 07:35:08

I tired the installation script on Fresh CentOS 5.2 , the installation went well and the sctipt logs shows successful but it dont allow you to log in to the virtualmin. I think its only for liecenced users.

From: Anonymous at: 2009-02-21 10:02:13

The installation script work perfectly on a clean CentOS 5 or 5.2. Make sure you have clean copy of Cent OS , rest the script do everything. I have tested it by myself today and now its working perfectly.

** Its awesome, replaced this whole tutorial with one command and FREE Official Virtualmin script available at Enjoy **

From: at: 2008-03-25 05:19:39

Great tutorial, a real real real time saver!

On the RPMForge setup, point people to

Especially if they are using x86_64 or a different distro.


From: at: 2009-03-26 19:12:15

I would take things one step further and follow the directions here:

By using the priorities plugin for yum, you will not need to disable the rpmforge repo (i.e. the 'enable=0' step above) and then constantly use '--enablerepo=rpmforge' when installing packages from rpmforge.  Furthermore, you can just do one 'yum update' to update everything from the base and the rpmforge repositories...just make sure to make the rpmforge lower priority than base!



From: at: 2008-03-25 05:23:07

/etc/yum.repos.d for me

From: Anonymous at: 2011-04-01 02:33:32

rpm -Uvh

is no long working any alternatives?


Thanks Kyle.

From: at: 2008-03-26 08:00:58

It's really a very good tutorial, it just might need some tuning ... anyway I suggest those modifications to for better performance ... this is a modified copy of with modifications applied .. Modification are mainly to allow non-tls smtp authentication and to stop buggy slow recipient address verification and use "reject_unlisted_recipient" instead ..

command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
#mydomain =
#myorigin = $mydomain
unknown_local_recipient_reject_code = 550
unverified_recipient_reject_code = 550
unverified_sender_reject_code = 550
mynetworks =
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual
canonical_maps = hash:/etc/postfix/canonical
sender_canonical_maps = hash:/etc/postfix/canonical
recipient_canonical_maps = hash:/etc/postfix/canonical
#address_verify_map = btree:/var/spool/postfix/verify
smtpd_sender_restrictions = hash:/etc/postfix/sender_access
mail_spool_directory = /var/spool/mail
home_mailbox = Maildir/
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_use_tls = yes
smtpd_tls_key_file = /etc/pki/postfix/smtpd.key
smtpd_tls_cert_file = /etc/pki/postfix/smtpd.crt
smtpd_tls_CAfile = /etc/pki/postfix/cacert.pem
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_session_cache_database = btree:/var/spool/postfix/smtpd_tls_cache
smtp_use_tls = yes
smtp_tls_key_file = /etc/pki/postfix/smtpd.key
smtp_tls_cert_file = /etc/pki/postfix/smtpd.crt
smtp_tls_CAfile = /etc/pki/postfix/cacert.pem
smtp_tls_session_cache_database = btree:/var/spool/postfix/smtp_tls_cache
smtp_tls_note_starttls_offer = yes
smtpd_tls_auth_only = no
tls_random_source = dev:/dev/urandom
smtpd_sasl_auth_enable = yes
debug_peer_level = 2
debugger_command =
         xxgdb $daemon_directory/$process_name $process_id & sleep 5
sendmail_path = /usr/sbin/sendmail.postfix
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
setgid_group = postdrop
html_directory = no
manpage_directory = /usr/share/man
sample_directory = /usr/share/doc/postfix-2.3.3/samples
readme_directory = /usr/share/doc/postfix-2.3.3/README_FILES
smtpd_banner = tds mail cluster
smtpd_helo_required = yes
disable_vrfy_command = yes
show_user_unknown_table_name = no
policy_time_limit = 3600
smtpd_milters = unix:/var/clamav/clmilter.socket unix:/var/run/spamass.sock
non_smtpd_milters = unix:/var/clamav/clmilter.socket unix:/var/run/spamass.sock
smtpd_error_sleep_time = 5s
smtpd_soft_error_limit = 10
smtpd_hard_error_limit = 20
smtpd_data_restrictions = reject_unauth_pipelining
smtpd_recipient_restrictions =
        check_recipient_access hash:/etc/postfix/access
        check_policy_service unix:private/spfpolicy 

From: at: 2008-03-26 10:59:22

reject_unlisted_recipient seems like a good idea i will update the sample config Actually i have smtp auth over tls only on purpose due to the fact that LOGIN and PLAIN authentication methods which are used by M$ clients are not secure and can lead to the user details being captured by anyone who is eaves dropping on the traffic, but i guess getting users to setup TLS on the client side is a pain at times.

From: at: 2008-07-28 12:12:52

You've done a great job here.  I ran across some errors, but worked through each so far.  

I need some clarification on one point, though:

You appear to be configuring postfix to use secure authentication.  As the hosting provider, my domain may be, but my clients will all have their own domains which will use mail under each.

So, as I follow your tutorial, should I be using my own host name (i/e in place of, when creating server certificates, and/or generating keys for DKIM?

Will I have to manually configure each client this way?

Please excuse my ignorance, but this is all very new to me.





From: at: 2008-07-30 08:19:28

1. Yes for outbound mail they will have to use your domain name as the smtp server hostname as the certificate will hold your name, for receiving however they can use their own domain name for the imap/pop3 server hostname.

2. As for DKIM you can have multiple keys so you can sign mail for all your customers domains.

From: at: 2009-04-10 20:29:17

It seems that in Centos 5.3, the clamav-milter daemon periodically reloads and loses the group permission that the clamav-milter.patch sets up.  In other words, it's reverts back to the clamav group which causes a permission problem with Postfix.  The easiest fix is to make the postfix user a member of the clamav group.

From: Acorp Computers at: 2008-09-19 02:45:25

In case it helps anyone else, my "Spamassassin Basic Config" was located in:



From: Pawel at: 2009-02-08 14:43:36

/etc/httpd/conf.d/ssl.conf in CentOS 5.2

 Great tutorial!

From: at: 2008-11-01 15:35:33

the vsftp has some mistake ,the virtualmin can't write the new user to the choort_list_user ?just keep the chroot_local=yes.

From: ??? at: 2008-11-05 09:02:03

what about the suexec home? now i have a web ,and the upload file such as picture .it's groups is apache not the site user.

and i run suexec -V the home is /var/www/   it's the problem?

From: Tanczos Andras at: 2009-02-15 21:34:52

rcpt to: instead of rcpt: at postfix tests