Installing clamav-milter from FreeBSD Ports

Weldon Whipple <>



The open-source ClamAV (Clam Anti-Virus) virus scanner can be invoked in a variety of ways. This updated version of the document describes my experience installing ClamAV version 0.86.2_1 as a sendmail milter, using the FreeBSD ports collection as of 14 September 2005. My OS version is FreeBSD 5.4-RELEASE The setup I describe doesn't require the MIMEDefang (or any other) milter.

FreeBSD's sendmail executable is compiled to support milters by default. There should be no need to recompile sendmail to support milters unless you are using a non-standard executable for some reason.

To verify that your sendmail supports MILTERS, issue the following command as root:

# sendmail -d0.1 -bt < /dev/null | grep MILTER

You should see a line of output that includes the word "MILTER".

Before you begin, make sure that your FreeBSD ports tree is up-to-date.

I know of some service providers that automatically update the ports tree for their customers. If your provider does that already, you probably don't want to update ports yourself!
I update my ports as follows (as root, of course):

# cd
# cvsup -L2 -g portsupfile
where my /root/portsupfile looks like:

*default tag=.
*default release=cvs
*default base=/usr/local/etc/cvsup
*default prefix=/usr
*default delete
*default use-rel-suffix
*default compress


Step-by-Step Instructions

1. Install clamav from ports

Issue the following commands as root:

# cd /usr/ports/security/clamav

Be sure to specify the "-DWITH_MILTER" command line option to make. Otherwise clamav won't run as a stand-alone sendmail milter.

If you don't specify "-DWITH_MILTER" and are installing clamav for the first time, a configuration menu will prompt you for options and let you to select the MILTER option by pressing the space bar to make an "X" to the left of "MILTER", then press tab and Enter.

The install "remembers" what you specified the first time you installed clamav and uses those options for all subsequent clamav builds. If you prefer using the menu interface and want to revisit that menu, you can instead issue the following commands:

# cd /usr/ports/security/clamav
# make config

When the compilation completes, issue the following command to install clamav:

# make install 
If you have installed an earlier version of clamav, the above will tell you about it, asking you to issue the commands "make deinstall" followed by "make reinstall". If that happens to you, issue both commands.
The installation should add a user and group named clamav. You can verify that this happened by examining /etc/passwd and /etc/group after the installation completes.
The make install should install these executables:


as well as the following startup files:


documentation at:


and a few other files. (If your shell is csh or tcsh, you might need to type "rehash" to let "which" find them.)

Additionally, make install will install the following pairs of (duplicate, initially) configuration files:


2. Edit the clamd configuration file

The clamd configuration file has changed significantly over time. Formerly named clamav.conf, it was recently renamed to clamd.conf. At about the same time, it became unnecessary to edit the configuration file in most cases--and this step (step 2) became unnecessary.

Previous to ClamAV version 0.80_1, it was necessary to uncomment the line "StreamSaveToDisk" in /usr/local/etc/clamav.conf (now named /usr/local/etc/clamd.conf). A September 2004 note in the change log states that clamav-milter no longer checks StreamSaveToDisk, and that clamd has removed the "obsolete StreamSaveToDisk directive.") You might, however, want to browse the clamd.conf file to see what sorts of directives are there.

3. Verify that the installation downloaded the virus database using freshclam

One of ClamAV's strengths is freshclam daemon, which periodically updates the ClamAV virus signatures. The ports installation should have automatically installed an initial set of virus signatures in the directory /var/db/clamav.

To verify the installation of initial virus signatures, issue these commands:

# cd /usr/ports/security/clamav/work/clamav-0.86.2/test
Your clamav version number in the above directory name will likely be more recent than the one above.

# clamscan
You can replace with clam.exe, clam.exe.bz2, clam.rar,, or mbox; the test should produce similar results.

The test should produce output something like the following:

test1: ClamAV-Test-Signature FOUND

----------- SCAN SUMMARY -----------
Known viruses: 36934
Engine version: 0.86.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.00 MB
Time: 6.186 sec (0 m 6 s)

4. Start the clamd daemon

The setup described in this document uses three daemons: The first (clamd) scans the mail. It communicates with a second daemon (clamav-milter) via a unix-domain socket. The clamav-milter daemon communicates with sendmail using a second unix-domain socket. The third (freshclam) was just mentioned above.

To start the clamd daemon, issue the command:

# clamd

When clamd starts, it creates the unix-domain socket /var/run/clamav/clamd.

If you prefer another socket name, you can specify it in the /usr/local/etc/clamd.conf file by modifying the line:

LocalSocket /var/run/clamav/clamd

Alternately, you can add a line to /etc/rc.conf that reads:


The startup file in /usr/local/etc/rc.d/ (invoked when the server boots up) reads the above value if specified in /etc/rc.conf. (See 9. Modify server startup files below.)

The clamd daemon also creates the file /var/run/clamav/, which contains the process ID (pid) of the clamd daemon.

5. Configure clamav-milter in the

Edit your sendmail macro configuration (mc) file and insert the following line:

INPUT_MAIL_FILTER(`clmilter',`S=local:/var/run/clamav/clmilter.sock, F=, T=S:4m;R:4m')
Note: If your configuration includes more than one milter and you are uncertain about their interactions or sequencing, search on INPUT_MAIL_FILTER, MAIL_FILTER and confINPUT_MAIL_FILTER in the cf/README or consult the "Bat" book. Configuring multiple milters is beyond the scope of this tutorial.

If you're new to the FreeBSD procedure for modifying, click here.

Then rebuild and install your, and restart sendmail:

# cd /etc/mail
# make
# make install
# make restart

6. Start the clamav-milter daemon

Before starting the clamav-milter, you should probably designate a directory as a "quarantine" directory. (If you don't do so, clamav-milter will issue a start-up "suggestion" that such a directory "may improve performance.") I designated /var/mail/quarantine as my quarantine directory by issuing the commands:

# mkdir -p /var/mail/quarantine
# chown clamav:clamav /var/mail/quarantine
# chmod 700 /var/mail/quarantine

Then issue the following command to start the clamav-milter daemon:

# clamav-milter --postmaster-only --local --outgoing --max-children=50 --quarantine-dir=/var/mail/quarantine --timeout=0 /var/run/clamav/clmilter.sock 
In earlier versions of clamav-milter, the "--timeout=0" option wasn't necessary. Without it, the current version of clamav-milter won't start at all. The timeout value of 0 causes clamav-milter to use sendmail's timeout settings.

When I issued the above command the first time, clamav-milter responded with:

/var/log/clamav/clamd.log: Permission denied
I responded with the commands:

# cd /var/log/clamav
# chown clamav clamd.log
then reissued the clamav-milter command (above).

I changed (slightly) the location of the local socket through which clamav-milter communicates with sendmail. Instead of the default (/var/run/clmilter.sock), I use /var/run/clamav/clmilter.sock, to overcome apparent directory ownership problems that cause clamav-milter to silently exit when started.

The above will notify the postmaster when viruses are detected and will scan local and outgoing e-mail (as well as incoming e-mail). It communicates with sendmail through the local socket named /var/run/clamav/clmilter.sock.

If you are concerned about inundating the postmaster with virus detection messages, replace the option --postmaster-only with --quiet to receive no notification at all.

With two daemons running, you should see two sockets in /var/run/clamav:

# pwd
# ls -l
total 2
srwxrwxrwx  1 clamav  clamav  0 Mar 10 13:39 clamd
-rw-rw----  1 clamav  clamav  5 Mar 10 13:39
srwxr-xr-x  1 clamav  clamav  0 Mar 10 13:39 clmilter.sock
The "s" at the beginning of the lines for clamd and clmilter.sock shows that those as local sockets.

7. Test clamav-milter

Clamav includes several "test" viruses that you can use to make sure that clamav is scanning your incoming mail. The test files are in the directory /usr/ports/security/clamav/work/clamav-0.86.2/test.

In the past, I issued the following commands to test clamav-milter--but they no longer give correct results (at least, not on my servers).

This doesn't work:

# cd /usr/ports/security/clamav/work/clamav-0.86.2/test
# cat | mail root -s "Testing"

When I look in /var/log/maillog (near the bottom) for a report that ClamAV detected a virus and handled it, I see this (alarming) entry:

Sep 16 03:01:24 gabriel sm-mta[6999]: j8G91NhL006999: Milter add: header: X-Virus-Status: Clean

This test does, however, work:

I was recently informed that the mail program doesn't take kindly to having binary data piped to it. To make it work correctly, try uuencoding it first:

# cd /usr/ports/security/clamav/work/clamav-0.86.2/test
# cat | uuencode | mail root -s "Testing"

This test also works:

Try copying one of the test files to another server and sending it as an e-mail attachment to the server being tested. When I try it, I see a more convincing entry in /var/log/maillog:

Sep 16 00:26:55 gabriel sm-mta[5039]: j8G6QsT5005039: Milter add: header: X-Virus-Status: Infected with ClamAV-Test-File

In addition to the above tests, be sure to verify that sendmail can still send and receive e-mail!

8. Start the freshclam daemon

The freshclam daemon regularly updates the virus signatures that clamav compares with incoming e-mail.

In the past, it was necessary to add a crontab entry to periodically invoke freshclam. Recent versions of clamav run freshclam as a daemon that checks for updates a specified number of times in a 24-hour period. It is still possible to run freshclam from cron, if you prefer.

The following command will start the freshclam daemon and make it check for updated virus signatures every two hours (12 times in every 24-hour period):

# freshclam --daemon --checks=12
I have never modified the /usr/local/etc/freshclam.conf file. I'm not certain if freshclam uses it or not.

9. Modify server startup files

You should find three startup files in the startup directory /usr/local/etc/rc.d:, and

You can change the behavior of the startup files either by editing the three files above (probably less desirable) or by adding lines to the file /etc/rc.conf (more desirable). These instructions show how I modified my /etc/rc.conf file.

  1. Enable the three clamav daemons by adding the following three lines to /etc/rc.conf:
  2. Optionally add clamd-specific options to /etc/rc.conf:
    In my configuration, I don't add the two lines above, since I am satisfied with the defaults in /usr/local/etc/rc.d/ If you browse near the bottom of /usr/local/etc/rc.d/, you will see the defaults (to the right of ':-'):
  3. Add clamav-milter-specific options to /etc/rc.conf:
    clamav_milter_flags="--postmaster-only --local --outgoing --max-children=50 --quarantine-dir=/var/mail/quarantine --timeout=0"
    The above lines in /etc/rc.conf are necessary to duplicate the clamav-milter options I used when I started clamav-milter earlier in this document.
  4. Add freshclam-specific options to /etc/rc.conf:
    I added the above line to /etc/rc.conf because one virus signature check per day isn't sufficient for me. (If you check /usr/local/etc/rc.d/clamav-freshclam-sh, you will see that one check is the default!).

After editing the /etc/rc.conf file, you will probably want to reboot the server (with the "reboot" command as root) to verify that the three daemons start up as expected.


This document is a work in progress. Please send corrections or suggestions to me!