VCF 9.1 - Setting up an Offline Repository


Introduction

We’ve all been there: you have multiple LAB installations in different states and versions, you live in Germany, and you only have what’s known as a “bamboo” internet connection - or, as a friend of mine once put it, “you with your McDonald’s hotspot internet.” Ouch!

Unfortunately, even in 2026, I still don’t have fiber-optic internet, and on some days it’s faster to download files via my backup 5G router than through my primary connection. Sounds like fun, right? Okay, and another reason is what’s known as a “dark site” - when the actual VCF installation or the installer can’t or isn’t allowed to connect to the internet.

Since I have to reinstall my vDefend Test VCF Lab installation every 90 days due to a lack of vDefend licenses, I just don’t feel like downloading 120+ GB onto a new machine every time. On top of that, I have various VCF installers - yes, I realize it sounds like a first-world problem, but it is what it is. Today, we’ll learn how to configure a basic Apache server, create certificates, use the VCF Download Tool, and—hopefully—end up with a ready-to-use Linux VM containing all the relevant data needed to update or redeploy a VCF installation. So, let’s get started.

Preparation

The only preparation needed is a reasonably up-to-date Ubuntu installation with internet access, SSH, and enough disk space. I’m using Ubuntu 26.04 Server and have set up a 35 GB boot partition and a 1 TB data partition. 2 vCPUs and 4 GB of RAM are sufficient. My VM runs on a Proxmox management server, but you can also run the VM on a NAS - the main thing is that the machine is accessible in the end. For the TLS certificate, you should have a suitable DNS entry; my repository VM listens to the wonderful FQDN repo.home.lab.

VCF Download Tool

The process for obtaining the binaries has changed slightly again with VCF 9.1, as a download token is no longer required - or rather, can no longer be used. Instead, the VCF Download Tool must now be registered in the VCF Business Service Console. This is done in a similar way to onboarding VCF Operations, but more on that later.

The VCF Download Tool can be downloaded from the Broadcom Support Portal. The easiest way to do this is to go to “My Downloads” and search for “Cloud Foundation.” Once you’ve navigated to the latest VCF version, you’ll find the tool under “Driver & Tools” -> VCF Download Tool.

After downloading the file—which is just over 500 MB—the tool must be copied to the future repository VM and extracted. I like to use my Mac’s built-in SCP support for this.

scp ~/Downloads/vcf-download-tool-9.1.0.0400.tar.gz daniel@repo.home.lab:/home/vcf/

Next, the tool must be extracted to the correct directory. In my case, /home is located on the 1 TB hard drive. The actual executable files we need will then be located in /home/vcf/vcf-download-tool/bin

tar -xzf vcf-download-tool-9.1.0.0400.*.tar.gz -C /home/vcf/vcf-download-tool --strip-components=1
cd /home/vcf/vcf-download-tool/bin

As mentioned earlier, to use the download tool, it must be registered in the VCF Business Service Console. To begin this process, you must first generate a software depot ID. You can do this using the following command.

./vcf-download-tool configuration generate --software-depot-id

If everything went well, you should end up with a unique ID like this one: 78849cfe-****-47fd-99e6-*********** This ID must be copied and then entered under Software Depot Registration -> New Registration in the VCF Business Service Console. In response, you will receive an activation code. This code replaces the download token and must be saved to a file on the repository server.

echo 'ACTIVATION-CODE' > /home/vcf/vcf-activation-code.txt

If you want, you can set this file to read-only, or—if there are multiple users set up on the system—configure the permissions so that only authorized users can read the file. Since this is a lab installation for me, I’ll skip that step. Next, I’ll create the “depot” folder where all the files will be saved, and then the fun of downloading can really begin. Ideally, your folder structure should look like this:

/home/vcf/
├── depot/
├── vcf-activation-code.txt
├── vcf-download-tool/
└── vcf-download-tool-9.1.0.0400.25570101.tar.gz

Download the installation binaries

To save storage space, you can limit the versions when using the download tool. In my case, I only need the 9.1.0 files with day 2 optional Components. But I could also filter for a specific express patch version or only download the installation binaries. run the following command for the full installation package:

./vcf-download-tool binaries download --vcf-version 9.1.0 --sku VCF --type=INSTALL --depot-download-activation-code-file /home/vcf/vcf-activation-code.txt --depot-store /home/vcf/depot/

Key Parameters:

  • binaries download Downloads VCF product binaries into the local software depot.

  • --vcf-version 9.1.0 Specifies VMware Cloud Foundation version 9.1.0.

  • --sku VCF Selects the VMware Cloud Foundation product SKU.

  • --type INSTALL Downloads binaries required for installation and Day-0 deployment.

  • --depot-download-activation-code-file Specifies the file containing the Software Depot Activation Code used for authentication.

  • --depot-store Specifies the root directory of the local offline depot where the binaries are stored.

For companies that use proxies, the proxy parameters might still be of interest.

  • --proxy-server, --proxy-https, --proxy-user, --proxy-user-password-file

I think they’re pretty self-explanatory and don’t need to be explained in more detail.

If the repo is only to be used for deployment, no further downloads are needed at this point. If upgrades are to be enabled, additional files will need to be downloaded.

Download the upgrade binaries

To use our repository for upgrades as well, we still needed the upgrade binaries. These are loaded in exactly the same way as the installation binaries, except that the type is set to UPGRADE.

./vcf-download-tool binaries download --vcf-version 9.1.0 --sku VCF --type=UPGRADE --depot-download-activation-code-file /home/vcf/vcf-activation-code.txt --depot-store /home/vcf/depot/

Download the ESX binaries and metadata

In addition to the VCF components, you’ll also need the ESX upgrade files. You can do this using the download tool as well, but the command is slightly different. By default, the Download Tool downloads patches up to ESXi 6.7 here. We should change that to a more appropriate level.

You can use this command to check the current configuration. All possible versions should still be configured here.

./vcf-download-tool esx configuration -G
embeddedEsx-6.7-INTL
embeddedEsx-7.0-INTL
embeddedEsx-8.0-INTL
embeddedEsx-9.0-INTL
embeddedEsx-9.1-INTL
esxio-8.0-INTL
esxio-9.0-INTL
esxio-9.1-INTL
armEsx-9.1-INTL

As for me, I only need the VCF 9.1 ESX patches for Intel. That’s why I’m disabling everything except embeddedEsx-9.1-INTL.

./vcf-download-tool esx configuration \
-D embeddedEsx-6.7-INTL \
-D embeddedEsx-7.0-INTL \
-D embeddedEsx-8.0-INTL \
-D embeddedEsx-9.0-INTL \
-D esxio-8.0-INTL \
-D esxio-9.0-INTL \
-D esxio-9.1-INTL \
-D armEsx-9.1-INTL

Before running the download command, you should double-check to make sure all unnecessary patches have been removed. After that, I use the following command to download the approximately 4 GB of patches.

./vcf-download-tool esx download \
--depot-download-activation-code-file /root/vcf-activation-code.txt \
--depot-store /home/vcf/depot/

If everything went through successfully, the repository directory should look something like this:

/home/vcf/depot/
├── PROD
│   ├── COMP
│   │   ├── DEPOT_SERVICE
│   │   ├── ESX_HOST
│   │   ├── HCX
│   │   ├── NSX_ALB
│   │   ├── NSX_T_MANAGER
│   │   ├── SDDC_MANAGER_VCF
│   │   ├── TELEMETRY_ACCEPTOR
│   │   ├── VCENTER
│   │   ├── VCFDT
│   │   ├── VCF_FLEET_LCM
│   │   ├── VCF_LICENSE_SERVER
│   │   ├── VCFMS_METRICS_STORE
│   │   ├── VCF_OBSERVABILITY_DATA_PLATFORM
│   │   ├── VCF_OPS_CLOUD_PROXY
│   │   ├── VCF_SALT
│   │   ├── VCF_SALT_RAAS
│   │   ├── VCF_SDDC_LCM
│   │   ├── VCF_SERVICE_VCD_MIGRATION_BACKEND
│   │   ├── VIDB
│   │   ├── VRA
│   │   ├── VRLI
│   │   ├── VRNI
│   │   ├── VROPS
│   │   ├── VSAN_FILE_SERVICES
│   │   └── VSP
│   ├── metadata
│   │   ├── Compatibility
│   │   ├── manifest
│   │   ├── productVersionCatalog
│   │   └── vsan
│   └── vsan
│       └── hcl
└── umds-patch-store -> /home/vcf/depot/PROD/COMP/ESX_HOST/patch-store

Installing and Configuring the apache Server

Now that we’ve gotten the fun download part out of the way, let’s move on to actually setting up the repo. To do this, I’ll install a apache server and set up a minimal configuration for it. In production environments, of course, apache should be hardened.

sudo apt update
sudo apt install apache2 openssl apache2-utils unzip

Next, I’ll create an OpenSSL config file. I’m using my Windows CA to generate the certificate. However, you can also create a self-signed certificate. Regardless of how you create your certificate, it must be imported into the VCF installer later.

[ req ]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req

[ dn ]
C = DE
ST = RLP
L = NW
O = SDN-Warrior
OU = SDN-Warrior
CN = repo.home.lab

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = repo.home.lab
IP.1 = 192.168.5.6

I create a new folder in the Apache directory where I store my TLS files—namely, the private key, the CSR request, and, finally, the generated certificate.

sudo mkdir /etc/apache2/ssl/

To generate my certificate request and private key, I run the following command:

sudo openssl req -nodes \
  -newkey rsa:4096 \
  -keyout /etc/apache2/ssl/vcf.key \
  -out /etc/apache2/ssl/vcf.csr \
  -config /home/vcf/openssl.cnf

If you want to use a self-signed certificate instead, you can do so with this command:

 sudo openssl req -x509 -nodes \
  -days 365 \
  -newkey rsa:4096 \
  -keyout /etc/apache2/ssl/vcf.key \
  -out /etc/apache2/ssl/vcf.crt \
  -config /home/vcf/openssl.cnf

Next, you’ll need a user for Apache’s basic authentication. I’m going to create a user named vcf here. After running the command, you’ll need to set a password for the user. The same applies here: in a production environment, you should set a strong password. Additionally, basic authentication is unencrypted, so you must use HTTPS.

sudo htpasswd -c /etc/apache2/.htpasswd vcf

Next, Apache needs to be configured. To do this, I cleared the original file and replaced it with my configuration.

sudo nano /etc/apache2/sites-available/default-ssl.conf

Apache configuration:

<VirtualHost *:443>
    ServerAdmin sdnwarrior@localhost
    DocumentRoot /home/vcf/depot

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/vcf.crt
    SSLCertificateKeyFile /etc/apache2/ssl/vcf.key
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    RequestHeader unset Proxy early

    <Directory /home/vcf/depot>
        Options Indexes FollowSymLinks
        AllowOverride None
        AuthType Basic
        AuthName "VCF Depot"
        AuthUserFile /etc/apache2/.htpasswd
        Require valid-user
    </Directory>
</VirtualHost>

The most important thing here is the DocumentRoot, and that the paths to the certificate and the private key are correct. After that, just start the services, and the repository should be accessible.

sudo a2enmod ssl headers
sudo a2ensite default-ssl
sudo systemctl restart apache2

Well, that was easy. However, there’s still one problem: the VCF Installer won’t accept the certificate. Now you have two options: either import the repository certificate into the VCF Installer, or - like I normally do - use an NGINX proxy with Cert Manager. I have this service running on my NAS as a Docker container and use my local DNS server with split DNS. This way, my repository gets a valid Let’s Encrypt certificate via the proxy, and thanks to Cert Manager, I don’t have to deal with renewing Let’s Encrypt certificates. In most cases, this solution probably won’t be feasible - and let’s just say it’s more of a specialized solution for the SDN-Warrior Lab - so I’ll also show you how to configure the repository certificate in the VCF Installer, since unfortunately it can’t be done via the UI.

Importing the Repo Certificate

To do this, I first need to build a valid certificate chain. In my case, this means creating a cert.pem file in the /tmp directory on the VCF installer and copying the root CA certificate and the repository certificate into it to create a valid certificate chain. Then I import the certificate using the Java Keytool.

Between versions 9 and 9.1 of the VCF installer, the Java version was changed, so the keychains for the VCF 9.1 installer are located in a different directory (oh yeah, the fun with certificates—we love it).

For the 9.0 installer, use the following command:

keytool -import -trustcacerts -file /tmp/cert.pem -keystore /usr/lib/jvm/openjdk-java17-headless.x86_64/lib/security/cacerts -alias repo.home.lab -storepass changeit

For 9.1, please use this command:

keytool -import -trustcacerts -file /tmp/cert.pem -keystore /usr/lib/jvm/openjdk-java21-headless.x86_64/lib/security/cacerts -alias repo.home.lab -storepass changeit

After that, all you have to do is restart the services:

echo ‘y’ | /opt/vmware/vcf/operationsmanager/scripts/cli/sddcmanager_restart_services.sh

As a final step, you can now configure the offline repository in the VCF Installer.

Final words

It takes quite a bit of effort to get this up and running. If you want to make things easier on yourself, you should check out the VCF Infrastructure Services (VIS) Appliance for VCF 9.1 Lab/PoC by William Lam. It’s incredibly useful, but there might be the occasional situation in a consultant’s life where you can’t rely on an appliance like this. I don’t really understand why you can’t just accept the certificate in the installer via the UI, like with VCF Operations - that would make life a little easier. Well, in the end, building it was good for my rusty Linux skills, too. I hope this article helps you if you ever need to build a repository manually.

End graphic