Mailcow ClamAV Virenscanner auslagern

Ich gehe hier darauf ein, wie man Mailcow: dockerized einen "externen" ClamAV als E-Mail Virenscanner geben kann. ClamAV ist sehr hungrig nach RAM, deshalb macht es Sinn auf einem kleinen System nur einen ClamAV als Shared Service laufen zu lassen.

ClamAV Shared Docker Container

Ich baue bei mir den ClamAV Container in meinen Toolstack mit ein. In diesem sind bereits einige Container, u.a.:

mkdir /opt/tools
cd /opt/tools

legt dort dann das .env und docker-compose.yml an, oder erweitert beides entsprechend: .env

# Config File for Tools Application

# Docker Compose Project Name
# max length 11 characters
PROJECT_NAME=tools

# ClamAV Exposed Port Configuration
CLAMAV_PORT=3310

# Timezone
TZ=Europe/Berlin

docker-compose.yml

services:
  clamav:
    image: clamav/clamav-debian:${CLAMAV_VERSION:-stable}
    restart: unless-stopped
    ports:
      - ${CLAMAV_PORT}:3310
    volumes:
      - clamav_db:/var/lib/clamav
      # if you want to use custom clamd.conf, uncomment the following line
      - ./data/clamav/conf/clamd.conf:/etc/clamav/clamd.conf:ro
    environment:
      - TZ=${TZ:-UTC}
    labels:
      com.centurylinklabs.watchtower.enable: true
    healthcheck:
      # Checks: clamd answers PONG to PING
      test: ["CMD-SHELL", "echo PING | nc -w 5 127.0.0.1 3310 | grep -q PONG"]
      interval: 30s
      timeout: 10s
      retries: 5
    networks:
      app-nw:
      
volumes:
  clamav_db:

networks:
  app-nw:
    internal: false
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: app-${PROJECT_NAME}

Dann legen wir noch die ClamAV Konfigdatei an. Könnt ihr auch einfach vom Mailcow kopieren /opt/mailcow-dockerized/data/conf/clamav/clamd.conf. hier aber eine Beispiel Konfiguration: /opt/tools/data/clamav/conf/clamd.conf

#Debug true
#LogFile /dev/null
LogTime yes
LogClean yes
ExtendedDetectionInfo yes
PidFile /run/clamav/clamd.pid
OfficialDatabaseOnly no
LocalSocket /run/clamav/clamd.sock
TCPSocket 3310
StreamMaxLength 100M
MaxThreads 10
ReadTimeout 10
CommandReadTimeout 3
SendBufTimeout 200
MaxQueue 80
IdleTimeout 20
SelfCheck 3600
User clamav
Foreground yes
DetectPUA yes
# See https://github.com/vrtadmin/clamav-faq/blob/master/faq/faq-pua.md
#ExcludePUA NetTool
#ExcludePUA PWTool
#IncludePUA Spy
#IncludePUA Scanner
#IncludePUA RAT
HeuristicAlerts yes
ScanOLE2 yes
AlertOLE2Macros no
ScanPDF yes
ScanSWF yes
ScanXMLDOCS yes
ScanHWP3 yes
ScanMail yes
PhishingSignatures no
PhishingScanURLs no
HeuristicScanPrecedence yes
ScanHTML yes
ScanArchive yes
MaxScanSize 100M
MaxFileSize 100M
MaxRecursion 5
MaxFiles 200
Bytecode yes
BytecodeSecurity TrustSigned
BytecodeTimeout 1000
ConcurrentDatabaseReload no

und startet am Ende den Stack:

docker compose up -d

Mailcow Konfiguration

Es empfiehlt sich den Mailcow Stack als erstes einmal komplett zu stoppen:

cd /opt/mailcow
docker compose down

nun deaktivieren wir den Mailcow eigenen ClamAV Container: /opt/mailcow/mailcow.conf

SKIP_CLAMD=y

und konfigurieren unseren Shared ClamAV Container: /opt/mailcow/data/conf/rspamd/local.d/antivirus.conf

  servers = "<FQDN-HOSTNAME>:3310";

Hinweis: Nutz hierfür den Fully Qualified Domain Name eures Docker Host Systems. Nun können wir den Stack wieder hochfahren:

docker compose up -d

Testen

Testen könnt ihr die Konfiguration mittels EICAR Test File . Schickt einfach eine Mail mit einem der Test Dateien an eure E-Mail Adresse. Ihr solltet dann zum Beispiel im Log des ClamAV Containers folgendes sehen:

clamav-1  | Sun Nov  9 12:04:31 2025 -> instream(172.21.0.1@34464): Eicar-Signature FOUND

das Log bekommt ihr so:

cd /opt/tools/
docker compose logs clamav