ScanCode.io
Overview
ScanCode.io is the AboutCode server for automated software composition analysis. Give it a codebase, an archive or a container image, choose a pipeline, and it scans every file. It reports the detected licences and copyright notices, the packages and their declared dependencies, and the exact file each finding came from. You can browse results in a web interface, query them through a REST API, and export them as SPDX or CycloneDX to feed a software bill of materials.
The SecureAnyCloud image installs ScanCode.io 38.0.0 from the official published container image, pinned by digest, and runs it as a systemd service. A working SCA server is online within minutes of launch, with authentication already switched on.
What you get:
- ScanCode.io 38.0.0 (Apache-2.0), deployed from the official
ghcr.io/aboutcode-org/scancode.ioimage pinned by digest, so the appliance is reproducible and can never silently upgrade - Docker Engine (Docker CE) and the Docker Compose plugin, installed from the official Docker package repository
- The upstream Compose topology, with every image digest-pinned:
nginxon port 80,web(gunicorn serving the Django application),worker(the RQ pipeline worker),db(PostgreSQL 17.10) andredis(8.8.0, append-only persistence) - Authentication required out of the box (
SCANCODEIO_REQUIRE_AUTHENTICATION=True). ScanCode.io ships upstream with authentication off, which on a public VM would let anyone submit scan pipelines and run arbitrary workloads on your machine - A per-VM
adminaccount with a generated web password and a generated REST API key, created at first boot - A per-VM Django
SECRET_KEYand PostgreSQL password, both rotated at first boot - All stateful data (the PostgreSQL database, the Redis append-only file and the scan workspace) on a dedicated 64 GiB data disk mounted at
/var/lib/scancodeio. Docker's data-root is relocated there, and the disk is independently resizable and re-provisioned on every VM - A self-authored sample codebase and a one-command self-test that proves a full scan round trip on your own instance
- Two systemd units:
scancodeio.service(a oneshot wrapper arounddocker compose up -d) andscancodeio-firstboot.service - 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key, and a VNet and subnet.
Standard_B2s (2 vCPU / 4 GB RAM) is the recommended starting size. It is enough to evaluate ScanCode.io and to scan modest codebases. The idle stack uses roughly 1.3 GB, which leaves around 2.5 GB of headroom, and a 4 GiB swapfile on the data disk absorbs scan bursts.
Scanning is CPU and memory hungry, because each scan process loads a large licence index. To scan large codebases or container images, use a larger size. Standard_B4ms (4 vCPU / 16 GB) and Standard_D4s_v5 (4 vCPU / 16 GB) are sensible next steps. You can then raise the worker's parallelism (see Step 11).
In the NSG, allow inbound 22/tcp from your management CIDR for SSH and 80/tcp from the CIDR that needs the ScanCode.io web UI and API. Add 443/tcp if you enable HTTPS.
Connect over SSH
Replace <vm-ip> with the public IP of your VM. The default login user is azureuser.
ssh azureuser@<vm-ip>Confirm the services are active
sudo systemctl is-active docker.service scancodeio.serviceBoth services report active. scancodeio.service is a oneshot unit that brings the Docker Compose stack up, so active means the stack has started.
Confirm the stack containers are running
cd /opt/scancodeio && sudo docker compose --env-file docker.env ps --format '{{.Service}}\t{{.Status}}'All five services should appear: db, nginx, redis, web and worker. The db and redis services report (healthy).
Confirm the data disk is mounted
The database, the Redis append-only file and every scan workspace live on a dedicated data disk. The scan workspace grows the most, because it holds each uploaded and extracted codebase.
mountpoint /var/lib/scancodeio && df -h /var/lib/scancodeioSwap is provisioned on the same disk to absorb scan bursts. Check it with:
swapon --showCheck the ScanCode.io login page
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/accounts/login/The command returns 200. The login path is /accounts/login/.
Authentication is required, so the REST API refuses anonymous callers. The following command returns 401:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/api/projects/Read the per-VM credentials
Your instance's first boot generates a unique admin password, REST API key, Django secret key and database password. The user-facing credentials are written to a root-only file.
sudo ls -l /root/scancodeio-credentials.txtThe file has mode 0600 and is owned by root. Read it with:
sudo cat /root/scancodeio-credentials.txtThe file lists scancodeio.url (where to sign in), scancodeio.admin.user (admin), scancodeio.admin.pass and scancodeio.api.key. Store them somewhere safe.
Sign in to the ScanCode.io web UI
Browse to http://<vm-ip>/ and sign in with the username admin and the scancodeio.admin.pass from Step 6. The bundled nginx reverse proxy serves the UI and the API on port 80.
After you sign in, you land on the Projects list. Each project is one scan, showing its pipeline, its status, and the counts of packages, dependencies and resources it found.
Prove a full scan round-trip
The image ships a self-test that runs the whole job end to end. It creates a project, uploads the bundled sample codebase and runs the scan_codebase pipeline to completion. It then checks that the results contain the specific licences and package the sample was authored to carry, and confirms that anonymous API access is refused.
sudo /usr/local/sbin/scancodeio-selftest.shThe test finishes with SELFTEST_SUCCESS. It is a real scan, asserted on its content, not a liveness ping.
The sample codebase it scans lives at /opt/scancodeio/sample/ and is packaged at /opt/scancodeio/sac-sample-codebase.zip. SecureAnyCloud wrote every file in it specifically to exercise the scanner, with a known licence in each. List the files with:
ls -l /opt/scancodeio/sample/Scan your own code
In the web UI choose New Project, give it a name, pick the scan_codebase pipeline, and either upload an archive or give it a download URL. To do the same over the REST API, use the API key from Step 6:
KEY=$(sudo sed -n 's/^SCANCODEIO_API_KEY=//p' /root/scancodeio-credentials.txt | head -1)
CODE=$(curl -s -o /tmp/scio-new-project.json -w '%{http_code}' \
-H "Authorization: Token $KEY" \
-F "name=my-first-scan-$$" \
-F "pipeline=scan_codebase" \
-F "execute_now=True" \
-F "upload_file=@/opt/scancodeio/sac-sample-codebase.zip" \
http://127.0.0.1/api/projects/) [ "$CODE" = "201" ] || { echo "FAIL: project creation returned HTTP $CODE"; cat /tmp/scio-new-project.json; exit 1; } echo "created project HTTP $CODE"; head -c 200 /tmp/scio-new-project.jsonThe response includes the project uuid. Other useful pipelines beyond scan_codebase are scan_single_package (one package archive), inspect_packages (dependency manifests), analyze_docker (a container image) and load_sbom (import an existing SBOM).
Read the results
The Resources view lists every file with its detected licence expression, and the Packages view lists the packages discovered from manifests. Together they show evidence of what your codebase actually contains.
You can read the same data over the API. The following commands list your projects and print their package counts:
KEY=$(sudo sed -n 's/^SCANCODEIO_API_KEY=//p' /root/scancodeio-credentials.txt | head -1)
CODE=$(curl -s -o /tmp/scio-projects.json -w '%{http_code}' \
-H "Authorization: Token $KEY" 'http://127.0.0.1/api/projects/?page_size=5') [ "$CODE" = "200" ] || { echo "FAIL: API returned HTTP $CODE"; cat /tmp/scio-projects.json; exit 1; } python3 -c "import json;d=json.load(open('/tmp/scio-projects.json'));print('projects:',d['count']);[print(' -',p['name'],p.get('package_count'),'packages') for p in d['results']]"To export results as SPDX or CycloneDX for use as a software bill of materials, use the Export button in the UI. Alternatively, call the API's results_download endpoint with an output_format of json, xlsx, spdx or cyclonedx.
Manage and tune the stack
The whole stack is managed by the scancodeio.service systemd unit, which wraps docker compose under /opt/scancodeio.
sudo systemctl status scancodeio.service --no-pager | head -20To inspect logs for a specific service:
cd /opt/scancodeio && sudo docker compose --env-file docker.env logs --tail 30 workerConfiguration lives in /opt/scancodeio/docker.env. Two settings matter most if you move to a larger VM:
SCANCODEIO_PROCESSESsets how many parallel scan processes a pipeline may use. It ships as1to fit 4 GB of RAM. On a larger VM, raising it to the vCPU count speeds up big scans considerably.- The gunicorn
--workerscount in/opt/scancodeio/docker-compose.ymlships as2.
After editing either, restart the stack:
sudo systemctl restart scancodeio.serviceThe deliberate differences between this appliance and the stock upstream Compose file are documented on the VM. Read them with:
cat /opt/scancodeio/README.sacEnabling HTTPS on your own domain
The appliance serves plain HTTP on port 80. To put it behind TLS, terminate HTTPS in front of ScanCode.io with an Azure Application Gateway, a load balancer, or your own reverse proxy with a certificate. Point it at port 80 on this VM, and restrict the NSG so only your proxy can reach port 80.
Once TLS terminates in front of the application, harden the cookies. Set both SESSION_COOKIE_SECURE=True and CSRF_COOKIE_SECURE=True in /opt/scancodeio/docker.env and restart the service. They ship as False because a browser refuses to send a Secure cookie over plain HTTP, which would make signing in impossible on a stock HTTP deployment.
First-boot security model
Nothing secret is baked into the image. On the first boot of every VM, scancodeio-firstboot.service generates and applies:
- A fresh Django
SECRET_KEY. It signs session cookies and CSRF tokens, so a key shared between VMs would be a real cryptographic weakness. - A fresh PostgreSQL password.
- A fresh
adminaccount, with both a web password and a REST API key.
The service writes them to /root/scancodeio-credentials.txt (mode 0600, owned by root) and records /var/lib/sac/data/scancodeio-firstboot.done so that it never re-runs. Before finishing, it also verifies that the API accepts the new key and refuses anonymous callers.
Authentication is required by default. Keep it on for any internet-facing VM, because an open ScanCode.io lets anyone submit scan pipelines, which is arbitrary workload execution on your machine.
Support
Every SecureAnyCloud image comes with 24/7 support. To reach the team, email sales@secureanycloud.com.
Deploy on Azure
Launch ScanCode.io 38.0.0 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
Overview
This image runs ScanCode.io, the open-source server for automated software composition analysis from the AboutCode project. ScanCode.io runs configurable scan pipelines over any codebase, including source trees, package archives, Docker images and root filesystems. It reports the licenses, copyrights, packages and dependencies it finds, so you can produce accurate SBOMs and answer open-source compliance questions with file-level evidence.
ScanCode.io is deployed from the official upstream container image, pinned by digest, and runs as a managed appliance. The appliance reproduces upstream's supported production topology as a Docker Compose stack.
What you get:
- A PostgreSQL database, a Redis queue, a gunicorn web tier serving the Django application, an RQ worker that runs scan pipelines, and an nginx reverse proxy that publishes the web interface on port 80
- A single systemd service,
scancodeio.service, that supervises the whole stack and starts it on boot - All stateful data (the PostgreSQL database, the Redis append-only file and the scan workspace that holds every uploaded and extracted codebase) on a dedicated, independently resizable EBS data volume mounted at
/var/lib/scancodeio. Your scan data stays off the operating system disk and survives instance replacement. - Required authentication. ScanCode.io ships with authentication disabled by default, so this appliance sets
SCANCODEIO_REQUIRE_AUTHENTICATIONand every web view and REST API endpoint demands a login. An open scanner would let anyone submit scan pipelines, which is arbitrary workload execution on your instance. - A one-shot first-boot service that rotates every shared secret before the stack serves a single request. It creates a fresh Django secret key, a fresh database password, and a fresh administrator account with a unique password and REST API key. It writes them to
/root/scancodeio-credentials.txtwith mode 0600, so only the root user can read the file. Two instances launched from the same Amazon Machine Image never share a secret.
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network and port 80 for the web interface
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for ScanCode.io. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger. ScanCode.io runs PostgreSQL, Redis, a gunicorn web tier and a scan worker together, and scans are CPU and memory hungry because each scan process loads a large license index. For larger codebases, Docker image analysis and other heavy workloads, consider m5.xlarge or m5.2xlarge.
Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet, and either create or select a security group that opens port 22 from your management network and port 80 for the web interface.
Select Launch instance. First-boot initialisation rotates the secrets and starts the appliance. It takes a couple of minutes after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
The following command launches an instance from the SecureAnyCloud ScanCode.io Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 80 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=scancodeio}]'When the instance reaches the Running state and its status checks pass, note its public IP address or DNS name. You can read it from the EC2 console or with aws ec2 describe-instances.
Connect to Your Instance
Connect over SSH with your key pair. For the Ubuntu 24.04 variant, the SSH login user is ubuntu:
ssh -i <key-name>.pem ubuntu@<public-ip>Retrieve the Administrator Password and API Key
The first boot generated an administrator password and REST API key that are unique to your instance. Read them as root:
sudo cat /root/scancodeio-credentials.txtThe file lists the ScanCode.io URL, the admin user, the generated web password and the generated REST API key. Keep these somewhere safe.
Sign In to the Web Interface
nginx serves the ScanCode.io web interface on port 80 and reverse proxies the gunicorn application. In a browser, go to:
http://<instance-public-ip>/Sign in as admin with the password from the credentials file. Authentication is required, so the sign-in page is the first thing you see.
After you sign in, you land on the Projects list, which shows every scan project and its pipeline status.
Create a Project and Run a Scan
Select New Project, give it a name, add an input by uploading a codebase archive or supplying a download URL or Docker image reference, choose a pipeline such as scan_codebase, and enable Execute pipeline now. The RQ worker runs the pipeline in the background, and the project page updates as it progresses.
When the pipeline finishes, the project page summarises the results. It shows the packages, dependencies and resources discovered and the unique license detections. You can export the results in one click as an SBOM in SPDX, CycloneDX, XLSX, JSON and attribution formats.
Open the Resources view to see the evidence behind the scan. It lists the detected license expression, programming language, mime type and package for every file the pipeline analysed.
Confirm ScanCode.io Is Running
Over SSH, confirm the appliance service is active and that the web interface answers on port 80:
sudo systemctl is-active scancodeio.service curl -s -o /dev/null -w 'login page HTTP %{http_code}\n' http://127.0.0.1/accounts/login/The service reports active and the login page returns HTTP 200. The appliance runs its whole stack as Docker Compose services supervised by systemd. List the running containers with:
cd /opt/scancodeio && sudo docker compose --env-file docker.env ps --status running --format '{{.Service}} {{.Status}}'The db, redis, web, worker and nginx services should all be running.
Prove a Full Scan Round Trip
The appliance ships a self-test that proves a real scan round trip end to end. It creates a project and uploads a small sample codebase that SecureAnyCloud authored with known planted licenses. It runs the scan_codebase pipeline to completion and asserts that the planted Apache-2.0, MIT and BSD-3-Clause licenses and the npm package are detected. It then confirms that unauthenticated API access is refused and removes the project it created:
sudo /usr/local/sbin/scancodeio-selftest.shA healthy instance prints SELFTEST_SUCCESS on the last line.
The Stack and the Data Volume
ScanCode.io stores its database, its Redis queue and every codebase you scan on a dedicated EBS volume mounted at /var/lib/scancodeio. This keeps them off the operating system disk and lets you resize or snapshot them independently. The Docker data root is relocated onto this volume, so all container data lands there. Confirm the mount with:
df -h /var/lib/scancodeioTo grow the scan storage, expand the EBS volume in the AWS console, then grow the filesystem on the instance with sudo resize2fs on the underlying device.
The appliance also keeps a 4 GiB swapfile on this volume, so a memory-hungry scan cannot trigger the kernel out-of-memory killer.
Use the REST API
ScanCode.io exposes a REST API on the same port 80, under /api/. The credentials file contains a per-instance API key. Send it in an Authorization: Token <key> header. For example, from outside the instance, list your projects with curl -H "Authorization: Token <your-token>" http://<instance-public-ip>/api/projects/.
Use the API to create projects, upload inputs, start pipelines and download SBOMs. You can then wire scans into CI/CD and gate releases on license policy.
Add a Custom Domain and Enable HTTPS
The appliance accepts requests on any host name, so it works immediately on the instance's public IP. nginx terminates HTTP on port 80 inside the bundled nginx container and reverse proxies the gunicorn application.
The simplest way to serve ScanCode.io on your own domain over HTTPS is to place the instance behind an AWS Application Load Balancer. Use an AWS Certificate Manager certificate that terminates TLS and forwards to port 80. Point a DNS record at the load balancer, and restrict the security group so that only the load balancer can reach port 80.
When you put ScanCode.io behind TLS, set SESSION_COOKIE_SECURE=True and CSRF_COOKIE_SECURE=True in /opt/scancodeio/docker.env and restart the appliance with sudo systemctl restart scancodeio.service. The appliance sets both to False so that browser login works over plain HTTP by IP. Turn them back on once TLS terminates in front of the application.
Backup and Maintenance
Back up ScanCode.io by snapshotting the /var/lib/scancodeio EBS volume. One snapshot captures the PostgreSQL database, the Redis append-only file and every scan workspace.
Apply operating system security updates with sudo apt-get update && sudo apt-get upgrade, and reboot when a new kernel is installed. The ScanCode.io appliance starts automatically on boot. The container images are pinned by digest, so the appliance never changes version unexpectedly.
Support
SecureAnyCloud publishes and supports this image. Support covers deployment, pipeline configuration, REST API integration, SBOM export, custom domains, TLS, data volume resizing and scaling. Contact SecureAnyCloud through the support channel listed on the AWS Marketplace listing.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch ScanCode.io on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com