ClamAV on Ubuntu 24.04 LTS on Azure
This image ships ClamAV 1.5.3 on Ubuntu 24.04 LTS, ready to scan from the first boot of every deployed virtual machine. ClamAV is installed unmodified from Ubuntu's own archive, so the engine stays patchable through the normal apt path for the life of the release.
ClamAV is an open source malware scanning engine. It provides clamd, a daemon that holds a signature set in memory and returns a verdict on any file handed to it, the clamscan and clamdscan command line scanners, and freshclam, which keeps the signature databases current.
What this appliance does and does not do
Read this section before you deploy. It is the difference between an appliance that does what you think it does and one that quietly does not.
The good news first. ClamAV's core mechanism works exactly as designed on Azure. Scanning a file is scanning a file: nothing about a virtual network, a software defined switch or a hypervisor changes how the engine reads bytes and matches them against signatures. That is not an assumption, it was verified during the build of this image with a real detection through the daemon socket, and you can reproduce that proof yourself in section 5 below.
Now the scope. ClamAV is a scanning engine, not a complete antivirus product. This image does not include, and ClamAV itself is not:
- a mail gateway or mail filter,
- an endpoint protection console or a management server,
- an agent that protects other machines,
- a web interface of any kind.
It does not automatically protect anything. It answers one question, reliably and at scale: is this file malicious. Four deployment patterns follow from that, and all four are real:
- Scan storage you attach to this machine. Mount an Azure Files share or a data disk here and let the scheduled sweep cover it. For most single machine deployments this is the useful pattern, and it is covered in section 6.
- Run a scanning service other workloads call. Your application hands a file to
clamdand gets a verdict back, so you do not need a scanner inside every application. Covered in section 7. - Scan this machine's own filesystem on demand or on a schedule. Works with no configuration.
- Build something on top of it. ClamAV is the engine underneath many mail filters and content adaptation gateways. The daemon and the libraries are here for you to integrate.
If what you need is a managed endpoint protection suite across a fleet of machines, this is not that, and no configuration of this image makes it that.
What makes this image different
Signatures are fetched on first boot, not baked in. A signature set frozen at image build time is stale the day you deploy it, and a scanner that reports healthy while missing everything published since then is worse than no scanner at all. Every virtual machine deployed from this image fetches a current signature set directly from the provider on its first boot, and keeps it current afterwards. cloudimg does not redistribute the signature databases: you receive them from their provider, under their terms. See section 11.
The image fails closed. clamd physically cannot start without a signature database, and no database ships. Two independent safeguards enforce that on every start, not merely the first, so an image that has not completed first boot cannot present a scanner that silently scans nothing.
The scanning daemon is not exposed to your network. clamd has no authentication of its own, so it listens on a local unix socket only. Section 7 shows how to open it to your own virtual network deliberately, if you need to.
There is no login and no password. ClamAV has no user database, no web interface and no credential of any kind. There is nothing here to rotate and nothing to leak. Administration is over SSH with your own key.
1. Deploy the virtual machine
Deploy the image from the Azure Marketplace. The defaults in this guide assume:
- Size:
Standard_B2s(2 vCPU, 4 GB) is sufficient and is what this image is validated on.clamdholds the signature set in memory and uses roughly 1 GB of that, leaving about 2.9 GB free. If you intend to scan large volumes concurrently, size up for throughput rather than for memory: see section 9. - Inbound ports: SSH (22) only. Nothing else needs to be open, and the scanning daemon must not be exposed. See section 7.
- Authentication: your own SSH public key.
2. Connect to the virtual machine
ssh azureuser@<vm-ip>
On first boot the machine fetches its signature databases before the scanner starts. That takes a minute or two on a new machine. If you connect immediately and the scanner is not up yet, that is first boot still working, and section 10 shows how to watch it.
3. Confirm the engine is running
clamscan --version
systemctl status clamav-daemon
You should see the engine version and a daemon that is active (running).

The version string looks like ClamAV 1.5.3/28062/Thu Jul 16 06:25:13 2026. The middle number is the signature database version and the date is when that database was published, which is a quick way to see how current your signatures are.
4. Confirm the signatures are current
ls -lh /var/lib/clamav/*.cvd
sigtool --info /var/lib/clamav/daily.cvd | sed -n '1,5p'

Three databases are fetched: main.cvd (the large base set), daily.cvd (the frequently updated set) and bytecode.cvd. Together they carry several million signatures. The Build time on daily.cvd should be within a day or so of when your machine first booted, because it was fetched then, not when the image was built.
freshclam runs as a service and keeps these current from then on:
systemctl status clamav-freshclam
5. Prove the scanner actually detects something
Do not take "the service is running" as proof that a scanner works. Prove it detects.
The EICAR test file is the industry standard way to do this. It is a harmless 68 byte text string, defined specifically so that antivirus engines can be tested without anyone handling real malware. It is not malware and it cannot do anything.
cd /tmp
printf 'X5O!P%%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > eicar-test.txt
printf 'an ordinary, harmless file\n' > report.txt
clamdscan --fdpass eicar-test.txt report.txt
echo "clamdscan exit code: $? (1 = malware found, 0 = clean, 2 = error)"
Note that clamdscan exits 1 when it finds something. That is success, not an error: it is how you detect a detection from a script. Only exit code 2 means something went wrong.

You should see exactly this shape of result:
eicar-test.txt: Eicar-Test-Signature FOUND
report.txt: OK
The second line matters as much as the first. It is the control: it proves the scanner is actually discriminating, rather than flagging everything it sees.
--fdpass sends the file through the daemon, so this exercises clamd and its in memory signature set, not a separate one shot scan. Exit codes are what you script against:
0clean1malware found2an error occurred
Clean up the test files when you are done:
rm -f /tmp/eicar-test.txt /tmp/report.txt
6. Scan storage attached to this machine
This is the pattern most single machine deployments want. Mount your storage here, then point the scheduled sweep at it.
To mount an Azure Files share:
sudo mkdir -p /mnt/share
sudo mount -t cifs //your-storage-account.file.core.windows.net/your-share /mnt/share \
-o vers=3.0,username=your-storage-account,password=<storage-key>,serverino
Scan it once, immediately:
clamdscan --fdpass --multiscan /mnt/share
Then enable the daily sweep. The sweep ships wired and enabled but deliberately does nothing until you tell it what to scan, because guessing where your data is and spending your CPU uninvited would be a poor default:
sudo nano /etc/cloudimg/clamav-scan.conf
Set:
SCAN_PATHS="/mnt/share"
QUARANTINE_ENABLED="no"
With QUARANTINE_ENABLED="no" detections are reported and logged only, and nothing is moved. Set it to yes to move detected files to /var/lib/clamav-quarantine. Start with no until you trust the results on your own data.
Run the sweep now rather than waiting for the timer:
sudo systemctl start clamav-scan.service
cat /var/log/clamav/cloudimg-sweep.log
The timer runs daily:
systemctl list-timers clamav-scan.timer
7. Run a scanning service for other workloads
clamd listens on a unix socket only by default:

Any process on this machine can use it with no further configuration. That covers the case where your application runs here.
To let other machines submit files, read this first. clamd has no authentication whatsoever. Anything that can reach its port can submit content to it. Its job is to parse untrusted file formats, which is exactly the code you least want reachable. So:
- Never expose port 3310 to the internet, or to
0.0.0.0/0, under any circumstances. - Open it only to the specific private address range that needs it.
If you accept that, enable it deliberately:
sudo nano /etc/clamav/clamd.conf
Add, scoping the bind address to this machine's private network address:
TCPSocket 3310
TCPAddr <this-vm-private-ip>
This image ships a guard that refuses to start clamd if a TCPSocket directive appears, precisely so that this cannot happen by accident. Enabling the service on purpose means removing that guard:
sudo rm /etc/systemd/system/clamav-daemon.service.d/10-cloudimg-firstboot.conf
sudo systemctl daemon-reload
sudo systemctl restart clamav-daemon
Note that this also removes the first boot safeguard, so only do it on a machine that has completed first boot and has its signatures.
Then open the port in your network security group to your own address range only:
az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
--name allow-clamd-vnet --priority 200 \
--source-address-prefixes <your-vnet-cidr> \
--destination-port-ranges 3310 --access Allow --protocol Tcp
From another machine in that range, submit a file with ClamAV's INSTREAM protocol, which is what libraries such as pyclamd, clamav-client and nodejs-clamscan speak.
8. Scanning scope and authorisation
Scan only storage you are authorised to scan. Malware scanning reads the full content of every file it examines, including personal data, and in many jurisdictions and organisations that is subject to policy. That is your responsibility, not something this image can decide for you.
9. Sizing and memory
clamd loads the entire signature set into memory. On the validated Standard_B2s (4 GB) that is about 1 GB resident, leaving roughly 2.9 GB free, which is comfortable.
This image sets ConcurrentDatabaseReload no deliberately. The ClamAV default holds two complete copies of the signature set in memory while it swaps in an update, which roughly doubles peak memory and can trigger an out of memory kill on a 4 GB machine at the exact moment the scanner is updating itself. The trade is a brief pause in scanning while a reload happens, which is the right trade at this size.
Scale for throughput, not for memory. The signature set does not grow with your workload, but scanning is CPU bound and file I/O bound: if you are sweeping a large share or serving many concurrent scan requests, move to a size with more vCPUs, such as Standard_D2s_v5 or larger.
10. Logs and troubleshooting
First boot fetches the signatures. To watch it:
journalctl -u clamav-firstboot --no-pager | tail -n 20
Ordinary logs:
sudo tail -n 20 /var/log/clamav/clamav.log # the daemon
sudo tail -n 20 /var/log/clamav/freshclam.log # signature updates
sudo tail -n 20 /var/log/clamav/cloudimg-sweep.log # the scheduled sweep
The scanner will not start. That is by design if first boot has not completed: it means no signature database is present, and this image refuses to run a scanner that would scan nothing. Check:
systemctl status clamav-firstboot
ls -l /var/lib/clamav/
The usual cause is that the machine could not reach the signature provider over HTTPS on its first boot. Fix the outbound path, then:
sudo systemctl restart clamav-firstboot
sudo systemctl restart clamav-daemon
Signatures are out of date. Force an update:
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
11. Licence
The engine. ClamAV is licensed under the GNU General Public License, version 2, with an OpenSSL linking exception. The licence text is on the image:
cat /usr/share/doc/clamav/copyright
This image installs ClamAV unmodified from Ubuntu's public archive, and cloudimg has made no change to the program. The complete corresponding source for the exact binaries installed is published by that same archive:
sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
sudo apt-get update
apt-get source clamav
Independently of that, a written offer valid for three years ships on the image:
cat /usr/share/doc/cloudimg/CLAMAV-GPL-2-WRITTEN-OFFER.txt
The signature databases are separate, and are not ours to give you. main.cvd, daily.cvd and bytecode.cvd are the content of Cisco Systems and Talos. They are not covered by the ClamAV engine's GPL-2 licence, and they are not covered by cloudimg's written offer. cloudimg does not redistribute them: no signature data ships on this image at all. Your machine fetches them at first boot directly from their provider, and your use of them is governed by that provider's own terms.
This is deliberate on both counts. It means you receive current threat intelligence rather than a frozen snapshot, and it means the databases reach you from the people who publish them.
Trademarks. ClamAV is a trademark of Cisco Systems, Inc. The name is used here only to identify the software this image packages. cloudimg is not affiliated with, endorsed by, or sponsored by Cisco Systems, Inc.
Support
Every cloudimg image is backed by 24/7 support. If something in this guide does not behave as described, contact support@cloudimg.co.uk.