SpiderFoot
Overview
This guide covers the deployment and operation of SpiderFoot on Ubuntu 24.04 on Azure, using SecureAnyCloud Azure Marketplace images. SpiderFoot is an open source platform for OSINT automation and attack surface reconnaissance.
You give SpiderFoot a target: a domain name, an IP address or range, a hostname, an email address, a username or a person's name. It runs a library of over two hundred modules that gather what public sources already know about the target. It then correlates the findings into a picture of the target's exposed surface.
What it collects depends on the modules you enable. Typical results include DNS and WHOIS records, subdomains and netblocks, certificate transparency entries, open ports and service banners, appearances in breach and paste data, mentions in social media and code repositories, and hits in malicious activity feeds.
Every finding is stored as a typed event linked back to the source that produced it. You can trace any conclusion to where it came from, browse and filter the results, view them as a graph, and export them as CSV, JSON or GEXF.
Everything runs on your own VM. There is no cloud service in the middle, and no third party is told what you are investigating unless you deliberately enable a module that queries one.
You are responsible for what you scan
Only scan systems you own, or systems you have explicit, documented authorisation to test.
Scanning third-party systems without authorisation may be unlawful in your jurisdiction and in the target's, and may breach your agreement with Microsoft Azure. Some SpiderFoot modules connect directly to the target. Others ask third-party services about it, which discloses your interest in that target to those services.
This image ships with no target configured, no scan scheduled and no scheduler enabled. It does nothing until you tell it to. The same statement ships inside the image at /usr/share/spiderfoot/AUTHORISED-USE.
The SecureAnyCloud image ships the free and open source, MIT-licensed SpiderFoot from a reviewed upstream commit. It runs as a plain Python application under a dedicated account with no login. No password and no API key is baked into the image.
Two independent authentication layers are generated uniquely on each VM at first boot. The public listener does not start until first boot has proved that an unauthenticated request is answered with 401. The image is backed by 24/7 SecureAnyCloud support.
SpiderFoot is developed by Steve Micallef and is licensed under the MIT licence. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by the SpiderFoot project. It ships the free and open source software unmodified. The name is used here solely to identify the software this image contains.
What you get:
- SpiderFoot 4.0.0 from upstream commit
0f815a20, pinned by commit id, never by a moving tag. - The full module library, over two hundred modules, loaded and working with zero API keys configured.
- A dedicated
spiderfootservice account with no login shell, and a private0700data directory. - An nginx access gate on port
80, installed as a host package so that unattended security upgrades keep the internet-facing component patched. - SpiderFoot's own authentication left enabled as a genuine second layer, with a per-VM password.
- Embedded SQLite storage, with no database server of any kind on the instance and no container runtime.
- A shipped dependency licence inventory at
/usr/share/spiderfoot/dependency-licences.txtcovering all 62 Python distributions, plus third-party notices and a recorded source manifest.
Prerequisites
- An Azure subscription with permission to create VMs.
- A target you own or are explicitly authorised to test. Nothing is preconfigured, and you should not launch this image until you know what you are entitled to scan.
- A
Standard_B2msVM (2 vCPU, 8 GiB) or larger. Read Step 9, on sizing and the honest scan envelope, before you commit to a size. A broad scan is genuinely compute-hungry. - Inbound TCP
80open only to the networks your administrators connect from. Treat access to this appliance the way you would treat access to your own reconnaissance results. - An SSH key pair for administrative access.
Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for SpiderFoot | Support by SecureAnyCloud and select Create.
- Choose your subscription, resource group and region.
- Set the VM size to Standard_B2ms or larger.
- Under Administrator account, select SSH public key and supply your own key.
- Under Inbound port rules, allow HTTP (80) and SSH (22). Before the VM is created, tighten both rules to your own address ranges on the networking blade.
- Leave the OS disk at its default. Select Review + create.
Deploy from the Azure CLI
# Create the VM from the sac image.
az vm image terms accept --urn sac1647283583153:spiderfoot-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name my-spiderfoot \
--image sac1647283583153:spiderfoot-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
# Then open the two ports you need, scoped to YOUR OWN network rather than the
# internet. These commands run on your workstation, not on the appliance. MY_CIDR="203.0.113.0/24"
# replace with your own range
az network nsg rule create \
--resource-group my-resource-group \
--nsg-name my-spiderfootNSG \
--name allow-ssh-from-office --priority 1000 \
--source-address-prefixes "${MY_CIDR}" \
--destination-port-ranges 22 --protocol Tcp --access Allow
az network nsg rule create \
--resource-group my-resource-group \
--nsg-name my-spiderfootNSG \
--name allow-http-from-office --priority 1010 \
--source-address-prefixes "${MY_CIDR}" \
--destination-port-ranges 80 --protocol Tcp --access AllowConnect to your VM
ssh azureuser@<vm-ip>Confirm the services are running
First boot generates this VM's two credentials and proves the access gate before anything is allowed onto port 80. Give it a minute or so after the VM first comes up.
# All three must report active. spiderfoot-firstboot is a oneshot that stays
# "active (exited)" once it has completed successfully.
systemctl is-active spiderfoot.service spiderfoot-firstboot.service nginx.service
# The gate's own health literal. This is the ONLY unauthenticated route on the # appliance, and it never reaches SpiderFoot, so it discloses nothing.
curl -s http://127.0.0.1/nginx-health
# SpiderFoot must be on loopback only, and nginx must be the only listener on 80.
sudo ss -lntp | grep -E ':(80|5001)\b'You should see SpiderFoot on 127.0.0.1:5001 and nginx on 0.0.0.0:80. SpiderFoot is never published directly, and there is no route to it that skips the gate.
Read this VM's credentials
Both passwords were generated on this machine, at this boot, and exist nowhere else. Nothing in this file was baked into the image. Read the file:
sudo cat /root/spiderfoot-credentials.txtSPIDERFOOT_URL=http://<vm-ip> SPIDERFOOT_UNLOCK_URL=http://<vm-ip>/sac-unlock
# 1. The sac gate (the browser's FIRST prompt) GATE_USERNAME=sac GATE_PASSWORD=<GATE_PASSWORD> # 2. SpiderFoot's own sign-in (the SECOND prompt) SPIDERFOOT_USERNAME=sfadmin SPIDERFOOT_PASSWORD=<SPIDERFOOT_PASSWORD>Open the interface
Open http://<vm-ip>/sac-unlock first, not http://<vm-ip>/. Step 7 explains why. Following this order makes the sign-in flow work first time in every browser.
- Your browser prompts for the SecureAnyCloud gate credentials. Enter GATE_USERNAME and GATE_PASSWORD. You see a short confirmation page.
- Follow the Continue to SpiderFoot link. Your browser now prompts a second time. This prompt shows the realm as
127.0.0.1. This is correct: it is SpiderFoot identifying itself by the loopback address it is bound to. EnterSPIDERFOOT_USERNAMEandSPIDERFOOT_PASSWORD. - The SpiderFoot interface loads, with no scans, no targets and no API keys.
Understand the access model
This appliance has two independent authentication layers. Understanding them explains the two prompts and the unlock URL.
Why SpiderFoot must never run unauthenticated. SpiderFoot enables its own authentication only if a password file exists. Without one, it does not merely leave the UI open. Measured on the stock upstream project, an anonymous POST /startscan returns 303 and a scan actually starts. Anyone who could reach the port could make your VM scan anything, from your IP address. The requests that appear to be rejected are in fact missing-argument errors, not authentication denials.
This appliance therefore never runs SpiderFoot without its own password file. The service is held on a systemd condition that refuses to start it if that file is missing or malformed.
Layer 1: the SecureAnyCloud gate. nginx on port 80 is the sole ingress and denies by default at server scope, so every route inherits the gate: the interface, all forty-one of SpiderFoot's exposed endpoints, and its static assets. Exactly one route is unauthenticated, /nginx-health. It is a static literal that never reaches SpiderFoot.
Layer 2: SpiderFoot's own sign-in. It is left enabled, with a per-VM password. Passing the gate alone gets you SpiderFoot's own 401, and no further.
Why there is an unlock URL. SpiderFoot's own authentication is HTTP Digest, and the gate is HTTP Basic. Both schemes travel in the same Authorization request header, and a browser can send only one at a time. A gate that demanded Basic on every request would therefore deadlock. The browser sends Basic, and SpiderFoot demands Digest. The browser sends Digest and drops the Basic header, and the gate demands Basic. This repeats forever.
The gate solves this by making its Basic requirement conditional on a per-VM cookie that is issued when you authenticate. Visiting /sac-unlock obtains that cookie in one clean step. After that, the single Authorization header is free to carry SpiderFoot's Digest credentials, and the interface works normally.
None of this weakens the gate. You can prove that from the appliance itself:
# Every route is closed to an anonymous caller with exactly 401 — including the
# endpoint that starts scans, which stock upstream answers with 303 and a
# running scan. for p in / /modules /scanlist /startscan /optsraw /static/css/spiderfoot.css; do printf '%-32s %s\n' "$p" \
"$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1$p")" done
# The gate credential ALONE reaches SpiderFoot's own challenge and no further. # Expect 401, with a Digest challenge — that is layer 2 doing its job. GU=$(sudo grep -m1 '^GATE_USERNAME=' /root/spiderfoot-credentials.txt | cut -d= -f2-) GP=$(sudo grep -m1 '^GATE_PASSWORD=' /root/spiderfoot-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -D - -u "$GU:$GP" http://127.0.0.1/ | head -1
curl -s -D - -o /dev/null -u "$GU:$GP" http://127.0.0.1/ | grep -i '^www-authenticate'
# And a VALID SpiderFoot credential with no gate cookie is still refused, so the
# gate cannot be bypassed just by switching authentication scheme. Expect 401.
SU=$(sudo grep -m1 '^SPIDERFOOT_USERNAME=' /root/spiderfoot-credentials.txt | cut -d= -f2-)
SP=$(sudo grep -m1 '^SPIDERFOOT_PASSWORD=' /root/spiderfoot-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w '%{http_code}\n' --digest -u "$SU:$SP" http://127.0.0.1/Run your first scan
Re-read the authorisation notice at the top of this guide before you start. A good first target is a domain that you own.
- Select New Scan.
- Give the scan a name, and enter your target in Scan Target. SpiderFoot detects the target type automatically.
- Choose how to scan. By Use Case is the simplest starting point.
- Select Run Scan Now. The scan page updates as results arrive.
The use cases are:
- Passive: never contacts the target directly. Choose it when you want to stay entirely off the target's logs. It is also the right choice for a first run.
- Footprint: maps the target's externally visible network and web presence.
- Investigate: Footprint plus reputation and malicious activity checks.
- All: every module that applies. This is thorough, and by far the heaviest. See Step 9.
Results are grouped by type. Select any type to see the individual findings and, for each one, the module and source that produced it. Graph draws the relationships between findings, and the export buttons produce CSV, JSON or GEXF for tools such as Gephi.
A completed scan looks like this. Findings are grouped by type, with the number of unique results and the module that produced each one:
Start with Passive on a target you own. It gives you a feel for the output and the runtime without touching the target at all.
Sizing, and the honest scan envelope
Standard_B2ms (2 vCPU, 8 GiB) is the recommended size. A concrete measurement stands behind that recommendation, not a guess.
A single All use case scan on the build machine saturated both vCPUs hard enough to make other work on the VM sluggish. SpiderFoot runs many modules concurrently, and most of them are network-bound. But parsing, correlating and writing results is real CPU work, and a broad scan does a great deal of it.
The honest envelope for Standard_B2ms is:
- One scan at a time, with a moderate module selection (
Passive,Footprint, or a hand-picked module list). - An
Allscan completes, but expect the appliance to be busy for the duration. Do not plan to run anything else alongside it. - Do not run several scans concurrently on this size.
If you need concurrent scans, or routinely run All against large targets, move to Standard_B4ms (4 vCPU, 16 GiB) or larger. Scan storage is modest, because results are text in a SQLite database. CPU, not disk, is what you are buying.
# Watch what a scan is actually costing you while it runs. top -b -n 1 | head -15
# The database grows with results; check it between scans.
sudo du -sh /var/lib/spiderfoot/Adding your own API keys
A number of modules need an API key for a third-party service, and every key field in this image is empty. This is deliberate. SecureAnyCloud never bakes a credential into an image, and a shared key would be both a leaked secret and a rate limit that you would share with strangers.
SpiderFoot works well with no keys at all. The module library loads in full, and the passive and footprinting use cases are productive without any. To add your own keys:
- Open Settings.
- Find the module in the list on the left and enter your key in its API Key field.
- Select Save Changes.
Keys are stored in this VM's own SQLite database at /var/lib/spiderfoot/, which is 0700 and owned by the spiderfoot account, so other local users cannot read them.
Be aware of what a keyed module discloses. Querying a third-party service about a target tells that service that you are interested in that target. Choose your modules accordingly.
What is in the image, and under what licence
Everything below ships in the image, so you can audit it without contacting us.
# The exact upstream commit, tree, and a content manifest of the shipped source.
cat /usr/share/spiderfoot/source-provenance.txt
# Third party notices, including the two copyleft dependencies and the bundled
# wordlist's advertising acknowledgment obligation. less /usr/share/spiderfoot/THIRD-PARTY-NOTICES # Every Python distribution in the image and the licence signal it published. column -t -s $'\t' /usr/share/spiderfoot/dependency-licences.txt | less # The exact resolved version of every dependency.
cat /usr/share/spiderfoot/python-requirements.lock
# Re-run the licence gate yourself. It exits non-zero on any AGPL, SSPL, BUSL,
# Elastic v2, Commons Clause, non-commercial, PolyForm, Prosperity or RSAL
# licence, and fails closed on anything it cannot resolve.
sudo /opt/spiderfoot/venv/bin/python \
/usr/share/spiderfoot/spiderfoot-licence-gate.pyThe application is MIT licensed, Copyright 2022 Steve Micallef. MIT permits use, modification, distribution and sale, and the full text ships at /opt/spiderfoot/app/LICENSE.
The bundled ispell wordlist at /opt/spiderfoot/app/spiderfoot/dicts/ispell/ is four-clause BSD, Copyright 1993 Geoff Kuenning. Redistribution is permitted, but clause 4 requires an advertising acknowledgment. The shipped notices discharge this requirement, and the acknowledgment is reproduced here:
This product includes software developed by Geoff Kuenning and other unpaid contributors.
The Python dependencies were examined by an executable licence gate at build time: 62 distributions, zero restrictive licences, zero unresolved. Two carry file-level copyleft: certifi and publicsuffixlist, both MPL-2.0 and both unmodified. There is no AGPL code, and in particular no PyMuPDF. The PDF text extraction path in this image is PyPDF2, which is BSD-3-Clause.
One dependency was deliberately removed. Upstream's requirements.txt lists pygexf, which is GPL-3.0. Nothing in SpiderFoot imports it. The GEXF export you use is networkx's BSD-3-Clause writer, and pygexf is not even importable on Python 3.
Leaving it out removes a copyleft obligation at no functional cost, and the build proves that by generating a real GEXF graph without it. Your Graph view and GEXF export are unaffected.
Day to day operation
# Service control.
sudo systemctl restart spiderfoot.service
sudo systemctl status spiderfoot.service
sudo journalctl -u spiderfoot.service -n 100 --no-pager
# SpiderFoot's own logs.
sudo tail -n 50 /var/log/spiderfoot/spiderfoot.error.log
# The gate's logs — useful for spotting unauthenticated probing of port 80.
sudo tail -n 50 /var/log/nginx/spiderfoot-access.log
# Back up the results database. Stop the service first so SQLite is quiescent.
sudo systemctl stop spiderfoot.service
sudo cp /var/lib/spiderfoot/spiderfoot.db /root/spiderfoot-backup-$(date +%F).db
sudo systemctl start spiderfoot.serviceRotating either password. The two layers are independent, so rotate them independently.
# Layer 1, the sac gate. Dry-run the command shape against a scratch file
# first (note -c, which CREATES the file — without it htpasswd refuses), so a
# typo cannot lock you out of your own appliance.
sudo htpasswd -cbB /tmp/scratch.htpasswd sac '<new-password>'
sudo htpasswd -bB /etc/nginx/spiderfoot.htpasswd sac '<new-password>'
sudo rm -f /tmp/scratch.htpasswd
sudo systemctl reload nginx
# Layer 2, SpiderFoot's own sign in. Its password file is username:password, and # the password is necessarily stored in clear because HTTP Digest requires the # server to know it in order to compute HA1. Keep the file 0600 and owned by the # service account, and restart so SpiderFoot re-reads it. printf 'sfadmin:%s\n' '<new-password>' | \
sudo tee /var/lib/spiderfoot/passwd >/dev/null sudo chown spiderfoot:spiderfoot /var/lib/spiderfoot/passwd sudo chmod 0600 /var/lib/spiderfoot/passwd sudo systemctl restart spiderfoot.serviceNeither rotation updates /root/spiderfoot-credentials.txt. That file records what first boot generated, and a later rotation does not rewrite it. Update your own password manager, not that file.
Security hardening
- Keep port 80 restricted to the networks your administrators connect from. This appliance is a reconnaissance tool, and its results are sensitive.
- Put TLS in front of it if it will be reached across an untrusted network. Plain HTTP does not protect the credentials that either authentication layer sends. Basic sends them base64-encoded. Digest does not send the password itself, but still leaves the session in the clear. Terminate TLS on an Azure Application Gateway, or install a certificate on the appliance's own nginx.
- Do not remove SpiderFoot's password file. Without it, SpiderFoot disables authentication entirely. The service refuses to start rather than come up unauthenticated. This is the intended behaviour, so restore the file rather than working around the refusal.
- Unattended security upgrades are enabled and nginx is a host package, so the OS patches the internet-facing component.
- Review what your enabled modules disclose before scanning anything sensitive.
Troubleshooting
The browser asks for a password over and over. You went to / before obtaining the gate cookie, and the browser is caught between the two authentication schemes. Close the tab, open http://<vm-ip>/sac-unlock, and sign in there first. Step 7 explains why.
The interface returns 502. SpiderFoot is not answering yet. It loads its whole module library at startup, which takes a few seconds:
systemctl is-active spiderfoot.service
sudo journalctl -u spiderfoot.service -n 50 --no-pagerspiderfoot.service will not start. Its start conditions and its preflight guard both refuse to run it in a state where it would be unauthenticated. Ask the guard directly, and it prints the specific reason:
systemctl status spiderfoot.service --no-pager | head -20 sudo /usr/local/sbin/spiderfoot-preflight.sh --app; echo "guard exit: $?"nginx will not start. The same pattern applies to the gate.
sudo /usr/local/sbin/spiderfoot-preflight.sh --nginx; echo "guard exit: $?"
sudo nginx -tA scan produces very little. Check the use case you chose, because Passive is deliberately narrow. Then check the scan's own error log in the interface, and consider whether the modules you want need an API key that you have not supplied.
The appliance feels slow during a scan. This is expected on 2 vCPU with a broad module selection. See Step 9.
Support
SecureAnyCloud provides 24/7 support for this image. Raise a request at secureanycloud.com and include the output of systemctl status spiderfoot.service nginx.service and the relevant journal lines. Do not include your scan results or your API keys in a support request.
Deploy on Azure
Launch SpiderFoot on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com