Subfinder on Ubuntu 24.04 on Azure User Guide
Overview
Subfinder is ProjectDiscovery's fast passive subdomain enumeration tool. It discovers the valid subdomains of a domain by reading public passive sources - certificate-transparency logs, passive-DNS aggregators and web archives - and merges and de-duplicates them into a clean list. Because it is strictly passive it never sends a single packet to the target, so it is safe and non-intrusive to run against any domain you are authorised to assess.
The cloudimg image is a ready-to-run attack-surface-monitoring host, not just the binary. The upstream release binary is pinned and checksum-verified, a system provider-config lets you add optional API keys once so they apply everywhere (interactive shells, cron, systemd and CI), a daily timer can continuously enumerate the domains you list, and every run writes machine-readable JSONL and plain-text reports for the next tool to pick up. Backed by 24/7 cloudimg support.
What is included:
- Subfinder 2.14.0 (
/usr/local/bin/subfinder), installed from the official ProjectDiscovery release binary and verified against the upstream SHA256 checksum - A
/usr/local/bin/subfinderwrapper that makes the system provider-config (/etc/subfinder/provider-config.yaml) apply in every execution context, so API keys you add work under cron, systemd and CI, not just your login shell subfinder-enum-run+subfinder-enum.timer- daily passive enumeration of the domains in/etc/subfinder/targets.txt, writing JSONL + text reports withlatest-<domain>.*symlinks- A customer-configurable target list at
/etc/subfinder/targets.txt(ships empty) and appliance config at/etc/subfinder/enum.conf - 24/7 cloudimg support
This is a command-line product: no web UI, no listening service, no admin account and no password. SSH on port 22 is the only open port, and the SSH key you choose at launch is the only way in.
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point. NSG inbound: allow 22/tcp from your management network. No inbound application ports are needed. Outbound internet (HTTPS) is required so Subfinder can reach its passive sources.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Subfinder by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22). Then Review + create -> Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name subfinder \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
There is no password and no console to log in to - this product has no credentials at all. /etc/subfinder/credentials on the VM is an informational note that says exactly that, and points at the paths below.
Step 4 - Confirm Subfinder is installed
subfinder -version
[INF] Current Version: v2.14.0
/usr/local/bin/subfinder is a small cloudimg wrapper that resolves the system provider-config at /etc/subfinder/provider-config.yaml before handing off to the upstream binary at /usr/local/lib/subfinder/subfinder, so any API keys you add there apply in every context - not just a login shell.

Step 5 - Run a passive enumeration
Point Subfinder at a domain with -d. -silent prints just the discovered subdomains, one per line. This is the canonical upstream self-test domain and resolves entirely from free passive sources:
subfinder -silent -d hackerone.com | sort -u | head -20
a.ns.hackerone.com
api.hackerone.com
autodiscover.hackerone.com
b.ns.hackerone.com
docs.hackerone.com
gslink.hackerone.com
mail.hackerone.com
mail2.hackerone.com
managed.hackerone.com
mta-sts.forwarding.hackerone.com
mta-sts.hackerone.com
mta-sts.managed.hackerone.com
my.hackerone.com
ns.hackerone.com
ns2.hackerone.com
ns3.hackerone.com
support.hackerone.com
websockets.hackerone.com
www.hackerone.com
Nothing here touches the target: every name comes from a public passive source. Swap hackerone.com for any domain you own or are engaged to test.

Step 6 - Optional: add passive-source API keys
The free sources need no keys. To unlock higher-volume or premium passive sources, add your own keys to the system provider-config - they then apply everywhere, including the scheduled timer and any CI job:
sudo nano /etc/subfinder/provider-config.yaml
The file ships empty (comments only) with mode 0644 root:root - it holds your third-party keys and no credential is baked into the image. See the Subfinder configuration docs for the format.
Step 7 - Scheduled attack-surface monitoring
subfinder-enum-run is the scheduled entry point. It reads /etc/subfinder/enum.conf, enumerates every domain in /etc/subfinder/targets.txt (or one you pass as an argument), and writes both a JSONL and a plain-text report with latest-<domain>.* symlinks:
sudo subfinder-enum-run hackerone.com
[2026-07-19T13:37:26+0000] subfinder-enum-run: enumerating hackerone.com (passive)
[2026-07-19T13:37:27+0000] subfinder-enum-run: hackerone.com: 24 subdomain(s) -> /var/lib/subfinder/reports/subfinder-hackerone.com-20260719T133726Z.txt
The reports directory keeps dated files plus stable symlinks your CI can always read:
ls -l /var/lib/subfinder/reports/latest-hackerone.com.txt /var/lib/subfinder/reports/latest-hackerone.com.jsonl
The daily timer is enabled and armed out of the box:
systemctl list-timers subfinder-enum.timer --no-pager
NEXT LEFT UNIT ACTIVATES
Mon 2026-07-20 00:11:03 UTC 10h subfinder-enum.timer subfinder-enum.service

Step 8 - Configure your targets and read the JSONL reports
Add the domains you want continuously monitored to /etc/subfinder/targets.txt, one per line (it ships empty):
grep -vE '^[[:space:]]*#' /etc/subfinder/targets.txt | grep . || echo '(empty - add one domain per line)'
The appliance configuration lives in /etc/subfinder/enum.conf:
grep -vE '^[[:space:]]*#' /etc/subfinder/enum.conf | grep .
TARGETS_FILE="/etc/subfinder/targets.txt"
REPORT_DIR="/var/lib/subfinder/reports"
SOURCE_TIMEOUT=30
MAX_TIME_MINUTES=10
REPORT_RETENTION_DAYS=30
Each JSONL report is one JSON object per discovered subdomain, which pipes straight into jq or the next tool in your recon chain:
sudo subfinder-enum-run hackerone.com >/dev/null 2>&1; head -2 /var/lib/subfinder/reports/latest-hackerone.com.jsonl
{"host":"api.hackerone.com","input":"hackerone.com","source":"submd"}
{"host":"autodiscover.hackerone.com","input":"hackerone.com","source":"submd"}

Configuration
Everything lives in /etc/subfinder/enum.conf:
TARGETS_FILE- the file the daily enumeration reads, one domain per line.SOURCE_TIMEOUT- per-source timeout in seconds.MAX_TIME_MINUTES- overall enumeration cap per domain.REPORT_RETENTION_DAYS- dated reports older than this are pruned.
After editing, restart the timer:
sudo systemctl restart subfinder-enum.timer
Maintenance
- Scheduled enumeration: run daily by
subfinder-enum.timer; run one on demand withsudo subfinder-enum-run. Inspect history withjournalctl -u subfinder-enum.service. - Upgrades: download a newer release from the Subfinder releases, verify it against the published checksums, and replace
/usr/local/lib/subfinder/subfinder. - Security patches: unattended-upgrades remains enabled, so the OS continues to receive security updates automatically.
- Stay passive: this image runs Subfinder in its default passive mode only. It never sends traffic to the domains you enumerate.
Support
cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.