VulnerableCode on Ubuntu 24.04 on Azure User Guide
Overview
This image runs VulnerableCode 40.0.1, the open source database of software package vulnerabilities from nexB and the AboutCode project, on Ubuntu 24.04 LTS. VulnerableCode aggregates and correlates vulnerability advisories from many upstream sources into a single, package centric model, and exposes it through a browsable web UI and a full REST API, so you can look up which versions of which packages are affected by which vulnerabilities and integrate that intelligence into your own tooling.
cloudimg delivers the VulnerableCode web application fully installed and reverse proxied behind nginx, with the gunicorn application server and PostgreSQL 16 already configured and managed by systemd, so the web UI and API answer within minutes of launch.
What is included:
- VulnerableCode 40.0.1 installed from the official release into
/opt/vulnerablecode, running in a dedicated Python 3.12 virtual environment - PostgreSQL 16 as the database
- gunicorn serving the Django application on
127.0.0.1:8000, fronted by nginx on port80(nginx serves/static/directly) - Three systemd units enabled and active:
postgresql,vulnerablecodeandnginx - Secure by default: no administrator account and no shared secret ship in the image. On first boot a unique Django secret key, a unique application HMAC key, a unique database password, a unique administrator account and a REST API token are generated and written to a root only file
- A migrated but empty database, ready for you to populate with the vulnerability import pipelines you choose
- A fully patched Ubuntu 24.04 LTS base with unattended security upgrades enabled
- 24/7 cloudimg support
The database ships empty by design. VulnerableCode's import pipelines download large volumes of vulnerability data over an extended period, so cloudimg does not run them at build time. The web UI and API are fully functional immediately; searches simply return no results until you run the importers (see Step 6).

Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size for evaluation and the web app; if you plan to run large import pipelines choose a size with more memory and disk. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web interface. VulnerableCode serves plain HTTP on port 80; for production or shared access, terminate TLS in front of it with your own domain (see the final step).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for VulnerableCode 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) and HTTP (80). Then Review + create then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name vulnerablecode \
--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
# Open the HTTP port so you can reach the web interface
az vm open-port --resource-group <your-rg> --name vulnerablecode --port 80 --priority 900
Step 3 - Retrieve the per VM admin credentials
Nothing secret is baked into the image. On the very first boot, a one shot service (vulnerablecode-firstboot.service) generates a fresh Django secret key, a fresh application HMAC key, a fresh database password, a unique administrator account and a REST API token, all unique to your instance. It writes them to /root/vulnerablecode-credentials.txt, readable only by root. SSH in as azureuser and read them:
$ sudo cat /root/vulnerablecode-credentials.txt
# VulnerableCode - generated on first boot by vulnerablecode-firstboot.service.
# These credentials are unique to THIS VM. Store them somewhere safe.
vulnerablecode.url=http://<vm-ip>/
vulnerablecode.admin.user=admin
vulnerablecode.admin.pass=<VULNERABLECODE_ADMIN_PASSWORD>
vulnerablecode.api.email=api@cloudimg.local
vulnerablecode.api.token=<VULNERABLECODE_API_TOKEN>
VULNERABLECODE_ADMIN_PASSWORD=<VULNERABLECODE_ADMIN_PASSWORD>
VULNERABLECODE_API_TOKEN=<VULNERABLECODE_API_TOKEN>
The first-boot service that rotates these per VM secrets is installed and enabled:

Step 4 - Browse the web UI
Open http://<vm-ip>/ in your browser. The home page is a search interface over packages and advisories.

On a freshly deployed instance the database is empty, so searches return no results until you run the import pipelines (Step 6). The search page is protected by a lightweight proof of work challenge (ALTCHA) that your browser solves automatically to deter scraping. Once you have imported data, searching returns the matching packages with their vulnerability status and risk score:

Selecting a package opens its detail page listing the advisories that affect it and the ones it fixes, each linked to its CVE aliases:

The public web UI, the interactive API docs and the staff sign-in page all answer through nginx:

Staff sign-in is at http://<vm-ip>/admin/login/; sign in as admin with the password from the credentials file to reach the Django admin (/admin/) and the pipeline dashboard. The login form is captcha protected.
Step 5 - Call the REST API
The REST API is served under /api/v3/. Two things are required by default: the VCIO_API_AGENT User-Agent header (the API rejects generic clients; the interactive docs at /api/docs/ are exempt), and a per VM API token (this image ships with API authentication enabled). Use the token from the credentials file:
# List the package ecosystems the instance supports (a GET endpoint)
curl -s -A "VCIO_API_AGENT" \
-H "Authorization: Token <VULNERABLECODE_API_TOKEN>" \
http://<vm-ip>/api/v3/package-types/ | head -c 400; echo
Expected output (a JSON list of supported package types such as pypi, npm, deb, maven):
{"package_types":["alpine","apache","cargo","composer","conan","deb","gem","generic","github","golang","hex","maven","npm","nuget","pypi","rpm", ...]}
The interactive API documentation at http://<vm-ip>/api/docs/ documents every endpoint, the required User-Agent, and the request bodies for the POST bulk-lookup endpoints (packages, advisories):

Because API authentication is enabled by default, a request with the correct User-Agent but no token is rejected, while the same request with the per VM token succeeds:

The API requires a token by default (secure by default). To make the API fully open and read only, set VULNERABLECODEIO_REQUIRE_AUTHENTICATION=False in /opt/vulnerablecode/.env and restart the service:
sudo systemctl restart vulnerablecode
Step 6 - Populate the database with the import pipelines
The image ships with an empty, migrated database. Populate it with the importers you need. These pipelines download large volumes of data and can run for a long time - run them in a tmux/screen session or as a scheduled job, not interactively over a fragile connection.
First list the available import and enrichment pipelines:
sudo vc-manage import --list
sudo vc-manage improve --list
Then run a specific pipeline by name. For example, to import the nginx advisories and compute risk scores: sudo vc-manage import nginx_importer_v2 followed by sudo vc-manage improve unfurl_version_range_v2 and sudo vc-manage improve compute_package_risk_v2. After an import completes, the same packages and advisories become searchable in the web UI (Step 4) and queryable through the REST API (Step 5).
Step 7 - Administer the instance
vc-manage is a thin wrapper around Django's manage.py, run as the vulnerablecode service user with the instance environment:
# Create an additional administrator
sudo vc-manage createsuperuser
# Create an additional API user + key
sudo vc-manage create_api_user --email <your-email>
# Open a Django shell
sudo vc-manage shell
Configuration lives in /opt/vulnerablecode/.env; restart vulnerablecode after editing it.
Step 8 - Enable HTTPS with your own domain
For production, put your own domain in front and terminate TLS. Point a DNS A record at the VM, then add your host to ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS in /opt/vulnerablecode/.env, and obtain a certificate with certbot against the nginx site:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
sudo systemctl restart vulnerablecode
Support
Every cloudimg image is backed by 24/7 support. Contact us for help with deployment, upgrades, TLS termination, scheduling the import pipelines, API integration and scaling.