Depot server

Depot server

Overview

VCF requires binaries for installation. These can either be done by connecting the vcf-installer directly to the Broadcom, or, you can also create a depot server, in-case if you don’t have direct access to the Internet.

I’ve also configured the depot server to run unbound for DNS.

This page outlines the installation for both services.

depot VM

Component Value
Depot Server depot.lab.fiveorange.net
IP Address 192.168.200.5
OS Fedora 43
Web Server Apache (httpd)
Document Root /var/www/html/depot
Depot Path /var/www/html/depot (accessible at /)
Protocols HTTP (80) and HTTPS (443)
Certificate Wildcard *.lab.fiveorange.net
Auth Method Basic Authentication (both HTTP and HTTPS)
Auth Username vcfadmin
Access Methods FQDN or IP address

Creating the Depot VM

Run the following command from Promox

qm create 200 \
    --name depot \
    --memory 2048 \
    --cores 1 \
    --sockets 1 \
    --cpu host \
    --ostype l26 \
    --net0 virtio,bridge=vmbr0 \
    --scsihw lsi \
    --boot order=sata0

And add the Fedora boot ISO.

Once the VM is booted, the config of the vm should look something like this.

# qm config 200                                             
boot: order=sata0                                                         
cores: 1                                                                 
cpu: host                                                              
memory: 2048                                                             
meta: creation-qemu=10.1.2,ctime=1764884766                              
name: depot                                                               
net0: virtio=BC:24:11:EB:FD:1B,bridge=vmbr0                              
ostype: l26                                                              
scsi0: local-lvm:vm-200-disk-0,size=40G,ssd=1                             
scsihw: lsi                                                              
smbios1: uuid=b3998f04-3541-4f15-b277-fc76d2a38dec                        
sockets: 1                                                                
vmgenid: e8ad7143-8119-41fd-a80a-20b0e9da08a6

Run lsblk

     
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS                                                                                                       
sda               8:0    0   40G  0 disk                                 
├─sda1            8:1    0    1M  0 part                                 
├─sda2            8:2    0    2G  0 part /boot                           
└─sda3            8:3    0   38G  0 part                                 
  └─fedora-root 252:0    0   38G  0 lvm  /                                
zram0           251:0    0  1.9G  0 disk [SWAP]

Check the ip route

$ ip route                                                    
default via 192.168.200.1 dev ens18 proto static metric 100              
192.168.200.0/24 dev ens18 proto kernel scope link src 192.168.200.5 metric 100

Set selinux to permissive

# Set immediately
setenforce 0

# Make persistent across reboots
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

# Verify
getenforce
# Should show: Permissive

Disable systemd-resolved (conflicts with Unbound)

# Stop and disable systemd-resolved
sudo systemctl disable --now systemd-resolved

# Delete the symlink 
sudo rm -f /etc/resolv.conf

# Add entries to /etc/resolv.conf
nameserver 192.168.200.1                                                 
search lab.fiveorange.net

# Prevent NetworkManager from overwriting resolv.conf
# Add the following to /etc/NetworkManager/NetworkManager.conf
[main]
dns=none

# Restart NetworkManager
sudo systemctl restart NetworkManager

# Check status
sudo systemctl status NetworkManager

Update the server

sudo dnf update -y

Reboot the server after updates

sudo reboot

unbound

Installing unbound

sudo dnf install unbound -y

Configure unbound

# Change directory
cd /etc/unbound

# Take backup of the original file
sudo cp unbound.conf{,.orig}

Edit the unbound.conf. This is my config

server:
        # number of threads to create. 1 disables threading.
        # num-threads: 1

        interface: 0.0.0.0

        access-control: 127.0.0.0/8 allow
        access-control: 192.168.200.0/24 allow
        access-control: 192.168.201.0/24 allow
        access-control: 192.168.202.0/24 allow
        access-control: 192.168.203.0/24 allow

        include: /etc/unbound/local.d/*.conf

        # Local zone for lab.fiveorange.net (forward lookups)
        local-zone: "lab.fiveorange.net." static

        # Forward DNS records (A records)
        local-data: "depot.lab.fiveorange.net. IN A 192.168.200.5"
        local-data: "proxmox.lab.fiveorange.net. IN A 192.168.200.10"
        local-data: "esxi-mgmt-01.lab.fiveorange.net. IN A 192.168.200.21"
        local-data: "esxi-mgmt-02.lab.fiveorange.net. IN A 192.168.200.22"
        local-data: "esxi-mgmt-03.lab.fiveorange.net. IN A 192.168.200.23"
        local-data: "vcf-installer.lab.fiveorange.net. IN A 192.168.200.49"
        local-data: "sddc-manager.lab.fiveorange.net. IN A 192.168.200.51"
        local-data: "vcenter.lab.fiveorange.net. IN A 192.168.200.52"
        local-data: "nsxmgr.lab.fiveorange.net. IN A 192.168.200.53"
        local-data: "nsxmgr-vip.lab.fiveorange.net. IN A 192.168.200.54"

        # Reverse DNS records (PTR records)
        local-data: "5.200.168.192.in-addr.arpa. IN PTR depot.lab.fiveorange.net."
        local-data: "10.200.168.192.in-addr.arpa. IN PTR proxmox.lab.fiveorange.net."
        local-data: "21.200.168.192.in-addr.arpa. IN PTR esxi-mgmt-01.lab.fiveorange.net."
        local-data: "22.200.168.192.in-addr.arpa. IN PTR esxi-mgmt-02.lab.fiveorange.net."
        local-data: "23.200.168.192.in-addr.arpa. IN PTR esxi-mgmt-03.lab.fiveorange.net."
        local-data: "49.200.168.192.in-addr.arpa. IN PTR vcf-installer.lab.fiveorange.net."
        local-data: "51.200.168.192.in-addr.arpa. IN PTR sddc-manager.lab.fiveorange.net."
        local-data: "52.200.168.192.in-addr.arpa. IN PTR vcenter.lab.fiveorange.net."
        local-data: "53.200.168.192.in-addr.arpa. IN PTR nsxmgr.lab.fiveorange.net."
        local-data: "54.200.168.192.in-addr.arpa. IN PTR nsxmgr-vip.lab.fiveorange.net."

forward-zone:
    name: "."
    forward-addr: UPSTREAM.DNS.1
    forward-addr: UPSTREAM.DNS.2

Save and Exit and check the config for errors.

$ sudo unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Enable and start unbound

sudo systemctl enable --now unbound

Check status

sudo systemctl status --now unbound

Update local resolv.conf to use Unbound. Edit the /etc/resolv.conf with the following contents

nameserver 127.0.0.1                                                      
search lab.fiveorange.net

Testing resolution

$ dig @127.0.0.1 vcenter.lab.fiveorange.net +short 
192.168.200.52

$ dig @127.0.0.1 -x 192.168.200.52 +short           
vcenter.lab.fiveorange.net.

$ dig @127.0.0.1 google.com +short                  
142.250.195.142

Installing and configuring apache

dnf install -y httpd

Create the depot directory

sudo mkdir /var/www/html/depot
sudo chown -R apache:apache /var/www/html/depot/
sudo chmod -R 755 /var/www/html/depot/

Configure httpd

# Create a new file /etc/httpd/conf.d/depot.conf with following contents

<Directory "/var/www/html/depot">                                        
    Options Indexes FollowSymLinks                                        
    AllowOverride None                                                    
    Require all granted                                                   
</Directory>

Enable and start Apache

sudo systemctl enable --now httpd
sudo systemctl status httpd

Configuring firewalld

Add the following rules

# Add rules
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

# Check 
sudo firewall-cmd --list-all
services: dhcpv6-client dns http mdns ssh

Testing Apache From the Mac, browse to http://192.168.200.5/depot/ and it should show listing. It will be blank for now.

Copying offline-depot-metadata

rsync the files to the Depot server

rsync -Pav VMware-VCSA-all-9.0.1.0.24957454.iso max@depot:~/

Unzip the file at /var/www/html/depot

Create the following directories in /var/www/html/depot

/var/www/html/depot$ tree .
.
├── PROD
│   ├── COMP
│   │   ├── NSX_T_MANAGER
│   │   │   └── nsx-unified-appliance-9.0.1.0.24952114.ova
│   │   ├── SDDC_MANAGER_VCF
│   │   │   ├── Compatibility
│   │   │   │   └── VmwareCompatibilityData.json
│   │   │   └── VCF-SDDC-Manager-Appliance-9.0.1.0.24962180.ova
│   │   └── VCENTER
│   │       └── VMware-VCSA-all-9.0.1.0.24957454.iso

And copy the .ova’s there.

Set the correct permissions

chown -R apache:apache /var/www/html/depot
chmod -R 755 /var/www/html/depot

Obtain the wildcard certificate

VCF installer requires valid wildcard certificate. Self-signed certificates don’t seem to work.

Since I have a domain name with Cloudflare, I’m using certbot.

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.cloudflare/credentials.ini \
  --dns-cloudflare-propagation-seconds 30 \
  -d "*.lab.fiveorange.net" \
  -d "lab.fiveorange.net" \
  --email VALID@EMAIL \
  --agree-tos \
  --non-interactive

# You should get something like this 
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for *.lab.fiveorange.net and lab.fiveorange.net
Waiting 30 seconds for DNS changes to propagate

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/lab.fiveorange.net/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/lab.fiveorange.net/privkey.pem
This certificate expires on 2026-03-07.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The certificates are stored here

Successfully received certificate.                                       
Certificate is saved at: /etc/letsencrypt/live/lab.fiveorange.net/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/lab.fiveorange.net/privkey.pem 
This certificate expires on 2026-03-07.

Verify the certificates

$ sudo certbot certificates                    
Saving debug log to /var/log/letsencrypt/letsencrypt.log 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                           
Found the following certs:                                           
  Certificate Name: lab.fiveorange.net                                   
    Serial Number: 6095e161478e882e436e4f35e929b031f2d                   
    Key Type: ECDSA                                                      
    Domains: *.lab.fiveorange.net lab.fiveorange.net                     
    Expiry Date: 2026-03-07 05:26:10+00:00 (VALID: 89 days)              
    Certificate Path: /etc/letsencrypt/live/lab.fiveorange.net/fullchain.pem  
    Private Key Path: /etc/letsencrypt/live/lab.fiveorange.net/privkey.pem 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Install mod_ssl

# Install mod_ssl
sudo dnf install -y mod_ssl

# Verify mod_ssl is loaded
httpd -M | grep ssl                          
 ssl_module (shared)

Creating Basic Auth Password file

# Install httpd-tools if not already installed
sudo dnf install -y httpd-tools

# Create a user called vcfadmin 
sudo htpasswd -c /etc/httpd/.htpasswd vcfadmin    
New password:                                                         
Re-type new password:                                                    
Adding password for user vcfadmin

Configure Apache SSL VirtualHost

# Create a new file called /etc/httpd/conf.d/depot-ssl.conf with the following contents

<VirtualHost *:443>
    ServerName depot.lab.fiveorange.net
    DocumentRoot /var/www/html

    # SSL Configuration
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/lab.fiveorange.net/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/lab.fiveorange.net/privkey.pem

    # Modern SSL settings
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off

    # Logging
    ErrorLog /var/log/httpd/depot-ssl-error.log
    CustomLog /var/log/httpd/depot-ssl-access.log combined

    # Depot directory with basic auth
    <Directory "/var/www/html/depot">
        Options Indexes FollowSymLinks
        AllowOverride None

        # Basic Authentication
        AuthType Basic
        AuthName "VCF Offline Depot"
        AuthUserFile /etc/httpd/.htpasswd
        Require valid-user
    </Directory>
</VirtualHost>

Configure HTTP to HTTPS redirect

# Create a new file /etc/httpd/conf.d/depot-redirect.conf with following contents

<VirtualHost *:80>                                                       
    ServerName depot.lab.fiveorange.net 
    # Redirect all HTTP traffic to HTTPS                                 
    RewriteEngine On                                                     
    RewriteCond %{HTTPS} off                                             
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]      
</VirtualHost>

Verify HTTPS and Basic auth

# Test HTTPS
$ curl -u vcfadmin https://depot.lab.fiveorange.net/depot/  
Enter host password for user 'vcfadmin':

# You can also do this 
curl -u vcfadmin -I https://depot.lab.fiveorange.net/depot/
Enter host password for user 'vcfadmin':
HTTP/1.1 200 OK
Date: Sun, 07 Dec 2025 06:47:36 GMT
Server: Apache/2.4.65 (Fedora Linux) OpenSSL/3.5.4
Content-Type: text/html;charset=ISO-8859-1

Verify auto-renewal

# Check timer status
sudo systemctl status certbot-renew.timer

# If you want to list all timers
sudo systemctl list-timers

# Do a dry run of cert-bot
sudo certbot renew --dry-run

# You should get something like this 
Saving debug log to /var/log/letsencrypt/letsencrypt.log                          
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                                                            
Processing /etc/letsencrypt/renewal/lab.fiveorange.net.conf                                                                                                
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                                                            
Account registered.                                                     
Simulating renewal of an existing certificate for *.lab.fiveorange.net and lab.fiveorange.net                                                              
Waiting 30 seconds for DNS changes to propagate  
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                                                            
Congratulations, all simulated renewals succeeded:                     
  /etc/letsencrypt/live/lab.fiveorange.net/fullchain.pem (success)                                                                                         
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Verify firewalld

# Ensure that you have done this 
$ sudo firewall-cmd --list-services           
dhcpv6-client dns http https mdns ssh

Trouble shooting - unbound

# Check config
unbound-checkconf

# Restart service
systemctl restart unbound

# View logs
journalctl -u unbound -f

# Test lookup
dig @127.0.0.1 <hostname>
dig @127.0.0.1 -x <ip>

Trouble shooting - Apache

Test HTTPS via FQDN (certificate valid, no -k flag needed)
curl -u vcfadmin https://depot.lab.fiveorange.net/

# Test HTTPS via IP (requires -k flag for IP-based access)
curl -u vcfadmin -k https://192.168.200.5/

# Note: The `-k` flag is required for IP-based HTTPS access because the certificate is issued for `*.lab.fiveorange.net`, not the IP address.

# Test access to metadata (VCF Installer requests these paths)
curl -u vcfadmin https://depot.lab.fiveorange.net/PROD/metadata/manifest/v1/vcfManifest.json
curl -u vcfadmin https://depot.lab.fiveorange.net/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json

# Check config
apachectl configtest

# Restart service
systemctl restart httpd

# View logs
tail -f /var/log/httpd/access_log
tail -f /var/log/httpd/error_log

Configuring chronyd

This server is also going to be a NTP server. I’m using chrony instead of ntpd.

In Fedora 43, chronyd is already installed.

Take backup of original config

cd /etc
cp chrony.conf{,.orig}

Now edit the chrony.conf

# Set the pool 
pool 0.au.pool.ntp.org iburst
pool 1.au.pool.ntp.org iburst
pool 2.au.pool.ntp.org iburst
pool 3.fedora.pool.ntp.org iburst

# Backup sources (global, in case AU pool has issues)
server time.cloudflare.com iburst

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

# Allow NTP client access from local network.
#allow 192.168.0.0/16

allow 127.0.0.0/8
allow 192.168.200.0/24
allow 192.168.201.0/24
allow 192.168.202.0/24
allow 192.168.203.0/24

# Serve time even if not synchronized to a time source.
local stratum 10

Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony

# Set the TAI-UTC offset of the system clock.
leapseclist /usr/share/zoneinfo/leap-seconds.list

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
log measurements statistics tracking

Enable and Start the service

systemctl enable chronyd && systemctl start chronyd

Configure firewall

firewall-cmd --add-service=ntp --permanent
firewall-cmd --reload

Checking Chrony

Checking sources

chronyc sources -v

You should get something like this

.-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^+ 159.196.178.7                 1   6   377    28    -62us[  -62us] +/-   12ms
^- syd.clearnet.pw               3   6   377    30  +1627us[+1627us] +/-   68ms
^- bitburger.simonrumble.com     1   6   377    30  +7005us[+7005us] +/-   13ms
^+ 193.177.220.128               2   6   377    32   +184us[ +114us] +/- 4948us
^+ time.cloudflare.com           3   6   377    28   -443us[ -443us] +/- 6341us
^+ time.cloudflare.com           3   6   377    29   -505us[ -505us] +/- 6111us
^- 194-195-253-58.ip.linode>     4   6   377    30  +4989us[+4920us] +/-   62ms
^- 220-158-215-20.broadband>     2   6   377     7   -548us[ -548us] +/-   43ms
^- ap-southeast-2.clearnet.>     2   6   377    29   +208us[ +208us] +/-   42ms
^- 159-196-3-239.9fc403.mel>     2   6   377    28  +2856us[+2856us] +/-   13ms
^- ns2.rasp.sh                   3   6   377    32   -309us[ -378us] +/-   47ms
^- ntp-mel.mansfield.id.au       2   6   377    31  -1502ns[  -71us] +/-   12ms
^+ time.bbmg.tech                5   6   377    29   -407us[ -407us] +/- 4605us
^- ntp2.ds.network               2   6   377    32   -159us[ -228us] +/- 6307us
^+ ntp1.ds.network               2   6   377    31    +80us[  +11us] +/-   10ms
^* smtp.juneks.com.au            1   6   377    30   -137us[ -207us] +/- 5106us

Check tracking

chronyc tracking
Reference ID    : 77120625 (smtp.juneks.com.au)
Stratum         : 2
Ref time (UTC)  : Fri Jan 30 05:40:16 2026
System time     : 0.000139529 seconds slow of NTP time
Last offset     : -0.000043255 seconds
RMS offset      : 0.000548189 seconds
Frequency       : 4.411 ppm slow
Residual freq   : -0.071 ppm
Skew            : 0.825 ppm
Root delay      : 0.009834820 seconds
Root dispersion : 0.000394668 seconds
Update interval : 64.9 seconds
Leap status     : Normal

The Leap status should be Normal.

Checking clients - once they are configured

chronyc clients
Last updated on