ClamAV can be run within a Docker container. This provides isolation from other processes by running it in a containerized environment. If new or unfamiliar with Docker, containers or cgroups see docker.com.
ClamAV image tags on Docker Hub follow this naming convention:
clamav/clamav:<version>: A release preloaded with signature databases.
Using this container will save the ClamAV project some bandwidth. Use this if you will keep the image around so that you don't download the entire database set every time you start a new container. Updating with FreshClam from existing databases set does not use much data.
clamav/clamav:<version>_base: A release with no signature databases.
Use this container only if you mount a volume in your container under
/var/lib/clamav to persist your signature database databases.
This method is the best option because it will reduce data costs for ClamAV
and for the Docker registry, but it does require advanced familiarity with
Linux and Docker.
Caution: Using this image without mounting an existing database directory will cause FreshClam to download the entire database set each time you start a new container.
You can use the unstable version (i.e. clamav/clamav:unstable or
clamav/clamav:unstable_base) to try the latest from our development branch.
While it is recommended to pull the image from our Docker Hub registry, some may want to build the image locally instead.
To do this, you will need to get the Dockerfile and the supporting scripts/
directory from the
clamav-docker Git repository.
Be sure to select the correct one for this ClamAV release.
Tip: For unreleased ClamAV versions, such as when building from the
maingit branch, you should select the files from theclamav-docker/clamav/unstable/<distro>directory.
Place the Dockerfile and scripts/ directory in the ClamAV source directory.
Then you can build the image. For example, run:
docker build --tag "clamav:TICKET-123" .
in the current directory. This will build the ClamAV image and tag it with the name "clamav:TICKET-123". Any name can generally be used and it is this name that needs to be referred to later when running the image.
To run clamd in a Docker container, first, an image either has to be built
or pulled from a Docker registry.
To pull the ClamAV "unstable" image from Docker Hub, run:
docker pull clamav/clamav:unstable
Tip: Substitute
unstablewith a different version as needed.
To pull and run the official ClamAV images from the Docker Hub registry, try the following command:
docker run \
--interactive \
--tty \
--rm \
--name "clam_container_01" \
clamav/clamav:unstable
The above creates an interactive container with the current TTY connected to
it. This is optional but useful when getting started as it allows one to
directly see the output and, in the case of clamd, send ctrl-c to close the
container. The --rm parameter ensures the container is cleaned up again after
it exits and the --name parameter names the container, so it can be
referenced through other (Docker) commands, as several containers of the same
image can be started without conflicts.
Note: Pulling is not always required.
docker runwill pull the image if it cannot be found locally.docker run --pull alwayswill always pull beforehand to ensure the most up-to-date container is being used. Do not use--pull alwayswith the larger ClamAV images.Tip: It's common to see
-itinstead of--interactive --tty.
In some situations it may be desirable to set (any of) the containers to a
specific timezone. The --env parameter can be used to set the TZ variable
to change the default of Etc/UTC.
You can run a container using an image built locally (see "Building the ClamAV Image"). Just run:
docker run -it --rm \
--name "clam_container_01" \
clamav:TICKET-123
The virus database in /var/lib/clamav is by default unique to each container
and thus is normally not shared. For simple setups this is fine, where only one
instance of clamd is expected to run in a dockerized environment. However
some use cases may want to efficiently share the database or at least persist
it across short-lived ClamAV containers.
To do so, you have two options:
docker volume command.
Volumes are completely managed by Docker and are the best choice for
creating a persistent database volume.For example, create a "clam_db" volume:
bash
docker volume create clam_db
Then start one or more containers using this volume. The first container
to use a new database volume will download the full database set. Subsequent
containers will use the existing databases and may update them as needed:
bash
docker run -it --rm \
--name "clam_container_01" \
--mount source=clam_db,target=/var/lib/clamav \
clamav/clamav:unstable_base
Run the container with these arguments to mount the a directory from your host
environment as a volume in the container.
bash
--mount type=bind,source=/path/to/databases,target=/var/lib/clamav
When doing this, it's best to use the <version>_base image tags so as to
save on bandwidth. E.g.:
bash
docker run -it --rm \
--name "clam_container_01" \
--mount type=bind,source=/path/to/databases,target=/var/lib/clamav \
clamav/clamav:unstable_base
Disclaimer: When using a Bind Mount, the container's entrypoint script will change ownership of this directory to its "clamav" user. This enables FreshClam and ClamD with the required permissions to read and write to the directory, though these changes will also affect those files on the host.
If you're thinking about running multiple containers that share a single database volume, here are some notes on how this might work.
Scanning files using clamscan or clamdscan is possible in various ways with
Docker. This section briefly describes them, but the other sections of this
document are best read before hand to better understand some of the concepts.
One important aspect is however to realize that Docker by default does not have access to any of the hosts files. And so to scan these within Docker, they need to be mounted with a bind mount to be made accessible.
For example, running the container with these arguments ...
--mount type=bind,source=/path/to/scan,target=/scandir
--mount type=bind,source=/path/to/scan,target=/scandir
... would make the hosts file/directory /path/to/scan available in the
container as /scandir and thus invoking clamscan would thus be done on
/scandir.
Note that while technically possible to run either scanners via docker exec
this is not described as it is unlikely the container has access to the files
to be scanned.
Using clamscan outside of the Docker container is how normally clamscan is
invoked. To make use of the available shared dockerized resources however, it
is possible to expose the virus database and share that for example. E.g. it
could be possible to run a Docker container with only the freshclam daemon
running, and share the virus database directory /var/lib/clamav. This could
be useful for file servers for example, where only clamscan is installed on
the host, and freshclam is managed in a Docker container.
Note: Running the
freshclamdaemon separated fromclamdis less recommended, unless theclamdsocket is shared withfreshclamasfreshclamwould not be able to informclamdof database updates.
To run clamscan in a Docker container, the Docker container can be invoked
as:
docker run -it --rm \
--mount type=bind,source=/path/to/scan,target=/scandir \
clamav/clamav:unstable \
clamscan /scandir
However, this will use whatever signatures are found in the image, which may be
slightly out of date. If using clamscan in this way, it would be best to use
a database volume that is
up-to-date so that you scan with the latest signatures. E.g.:
docker run -it --rm \
--mount type=bind,source=/path/to/scan,target=/scandir \
--mount type=bind,source=/path/to/databases,target=/var/lib/clamav \
clamav/clamav:unstable_base \
clamscan /scandir
As with clamscan, clamdscan can also be run when installed on the host, by
connecting to the dockerized clamd. This can be done by either pointing
clamdscan to the exposed TCP/UDP port or unix socket.
Running both clamd and clamdscan is also easily possible, as all that is
needed is the shared socket between the two containers. The only caveat here
is to:
1. mount the files to be scanned in the container that will run clamd, or
2. mount the files to be scanned in the container that will clamdscan run if
using clamdscan --stream. The --stream option will be slower, but
enables submitting files from a different machine on a network.
For example:
docker run -it --rm \
--mount type=bind,source=/path/to/scan,target=/scandir \
--mount type=bind,source=/var/lib/docker/data/clamav/sockets/,target=/run/clamav/
clamav/clamav:unstable
docker run -it --rm \
--mount type=bind,source=/path/to/scan,target=/scandir \
--mount type=bind,source=/var/lib/docker/data/clamav/sockets/,target=/run/clamav/
clamav/clamav:unstable_base \
clamdscan /scandir
The ClamAV container actually runs both freshclam and clamd daemons by
default. Optionally available to the container is ClamAV's milter daemon.
To control the behavior of the services started within the container, the
following flags can be passed to the docker run command with the
--env (-e) parameter.
clamd.
(default: start clamd)freshclam daemon.
(default: start the freshclam daemon)clamav-milter daemon.
(default: start the clamav-milter daemon )clamd to start.
(default: 1800)freshclam daily update frequency.
(default: once per day)So to additionally also enable clamav-milter, the following flag can be
added:
--env 'CLAMAV_NO_MILTERD=false'
Further more, all of the configuration files that live in /etc/clamav can be
overridden by doing a volume-mount to the specific file. The following argument
can be added for this purpose. The example uses the entire configuration
directory, but this can be supplied multiple times if individual files deem to
be replaced.
--mount type=bind,source=/full/path/to/clamav/,target/etc/clamav
Note: Even when disabling the
freshclamdaemon,freshclamwill always run at least once during container startup if there is no virus database. While not recommended, the virus database location itself/var/lib/clamav/could be a persistent Docker volume. This however is slightly more advanced and out of scope of this document.
To connect to a running ClamAV container, docker exec can be used to run a
command on an already running container. To do so, the name needs to be either
obtained from docker ps or supplied during container start via the --name
parameter. The most interesting command in this case can be clamdtop.
docker exec --interactive --tty "clamav_container_01" clamdtop
Alternatively, a shell can be started to inspect and run commands within the container as well.
docker exec --interactive --tty "clamav_container_01" /bin/sh
The default socket for clamd is located inside the container as
/run/clamav/clamd.sock and can be connected to when exposed via a Docker
volume mount. To ensure, that clamd within the container can freely create
and remove the socket, the path for the socket is to be volume-mounted, to
expose it for others on the same host to use. The following volume can be used
for this purpose. Do ensure that the directory on the host actually exists and
clamav inside the container has permission to access it.
Caution is required when managing permissions, as incorrect permission could
open clamd for anyone on the host system.
--mount type=bind,source=/var/lib/docker/data/clamav/sockets/,target=/run/clamav/
With the socket exposed to the host, any other service can now talk to clamd
as well. If for example clamdtop where installed on the local host, calling
clamdtop "/var/lib/docker/data/clamav/sockets/clamd.sock"
should work just fine. Likewise, running clamdtop in a dif
$ claude mcp add clamav \
-- python -m otcore.mcp_server <graph>