Networking Azure

FOG Project on Ubuntu 24.04 on Azure User Guide

| Product: FOG Project on Ubuntu 24.04 LTS on Azure

Overview

This image runs FOG Project 1.5.10.1903 on Ubuntu 24.04 LTS. FOG is a free, open source network cloning and imaging platform. You capture a disk image once from a reference machine, store it centrally, and then deploy that image to as many machines as you need over the network, driven by a PXE network boot rather than by anyone carrying media from desk to desk.

Around that core, FOG provides the management work that surrounds imaging: a hardware inventory of every machine that has checked in, a record of which image each one is running, machine groups, scheduled capture and deploy tasks, and snapins that install software or apply a change to a group of machines after imaging.

The appliance has two planes, and they have deliberately different security postures:

  • The management plane - the FOG web console and REST API on port 80. It is authenticated, with a console password and API tokens generated uniquely on your VM's first boot.
  • The boot plane - TFTP on 69/udp serving the iPXE bootloaders, plus NFS on 2049 serving the image store. It is anonymous by protocol necessity: a machine that is powering on cannot present credentials, and TFTP has no authentication in the protocol at all. You scope it with your Azure Network Security Group and the subnet-scoped NFS export.

This image deliberately ships no DHCP server. FOG can install and run one, and on an Azure VNet that would be actively harmful - it would compete with Azure's own platform DHCP and can break networking for every VM on the subnet. This image is built with FOG's DHCP server disabled, and the build fails if any DHCP server package is found installed or anything is found listening on 67/udp. You point your existing DHCP server at this server instead, which is covered in Step 9.

What is included:

  • FOG Project 1.5.10.1903, installed by the project's own installer from the pinned upstream commit c8a5665
  • Apache 2.4 with PHP 8.3 serving the web console and REST API at /fog/management
  • MariaDB, bound to 127.0.0.1 only - the database is a purely local dependency of the web application
  • tftpd-hpa on 69/udp serving the full set of iPXE bootloaders from /tftpboot (BIOS, UEFI, Secure Boot, arm64 and per-NIC variants)
  • nfs-kernel-server serving the image store at /images, scoped at first boot to your VM's own subnet rather than upstream's export-to-every-host default
  • vsftpd for FOG's own image file management
  • The seven FOG service daemons (scheduler, image replicator, multicast manager, ping hosts, snapin hash, snapin replicator, image size), all enabled
  • A per-VM console password, REST API token and user API token generated on first boot into /root/fog-project-credentials.txt, readable only by root. No shared or default login exists in the image - FOG's documented fog / password default does not work on your VM
  • The complete corresponding source at /opt/fog-source with the GPLv3 licence text, satisfying the licence's source obligation on the image itself
  • A fully patched Ubuntu 24.04 LTS base with unattended security upgrades enabled
  • 24/7 cloudimg support

Before you start: what PXE imaging requires

FOG images machines by PXE network boot, and that imposes real network requirements. Read this before you design your deployment, because it determines where this VM belongs.

A machine being imaged powers on, asks its local DHCP server for an address, and that DHCP server tells it where to fetch a bootloader (options 66 and 67). The machine then fetches the bootloader over TFTP, chains to FOG over HTTP, and moves image data over NFS.

  • The DHCP handoff happens on the client's local broadcast domain, so the DHCP server that answers must be one you can configure. This appliance does not provide it.
  • Everything after that handoff - TFTP, HTTP, NFS - is routed unicast, so the FOG server itself does not need to be on the same layer 2 segment as the clients. It needs to be routable from them.

The supported topology on Azure is therefore: this VM in your VNet, your client machines on premises or in a connected network, reached over VPN or ExpressRoute, with your existing on-premises DHCP server setting options 66 and 67 to point at this VM's private address.

Two FOG capabilities genuinely do not work on an Azure VNet, and no configuration changes that:

  • Multicast deployment, which images many machines simultaneously from one stream. Azure VNets do not carry multicast. Unicast deployment to each machine works normally.
  • FOG's proxyDHCP mode, which supplies boot options without running a full DHCP server. It depends on broadcast traffic, which Azure VNets also do not carry. Setting options 66 and 67 on your own DHCP server is the supported path, and is what Step 9 covers.

Be realistic about bandwidth as well. Disk images are tens of gigabytes; deploying them from Azure to on-premises machines pulls that volume across your VPN or ExpressRoute link for every machine. For large on-premises fleets, a FOG storage node on the client network is the usual answer, with this VM as the management server.

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended size - FOG runs Apache, PHP, MariaDB, NFS and TFTP together.

The OS disk holds /images. Captured images are large, so size the disk for your image library, or attach a data disk and mount it at /images.

NSG inbound rules: allow 22/tcp from your management network, 80/tcp from the networks that need the console, and 69/udp, 2049/tcp and 21/tcp from the subnets whose machines will be imaged. Do not expose any of these to the internet. The boot plane is anonymous by design, so the NSG is what scopes it.

Step 1 - Deploy from the Azure Marketplace

In the Azure portal, search the Marketplace for FOG Project on Ubuntu 24.04 LTS by cloudimg and select Create. Choose your subscription, resource group and region, set the size to Standard_B2ms, select SSH public key authentication with the username azureuser, and allow inbound 22/tcp from your management network only. Add the remaining rules from the Prerequisites section after the VM is created.

Step 2 - Deploy from the Azure CLI

Run these on your own workstation, not on the VM. Accept the image terms once per subscription before the first deployment:

az vm image terms accept --publisher cloudimg --offer fog-project-ubuntu-24-04 --plan default

az group create --name fog-rg --location eastus

az vm create \
  --resource-group fog-rg \
  --name fog-server \
  --image cloudimg:fog-project-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --storage-sku StandardSSD_LRS \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Step 3 - Connect to your VM

ssh azureuser@<vm-ip>

Step 4 - Confirm the services are running

FOG is several cooperating services, so check them together. All should report active.

sudo systemctl is-active apache2 mariadb tftpd-hpa nfs-kernel-server vsftpd
active
active
active
active
active

The seven FOG daemons run alongside them:

sudo systemctl is-active FOGScheduler FOGImageReplicator FOGImageSize FOGMulticastManager FOGPingHosts FOGSnapinHash FOGSnapinReplicator
active
active
active
active
active
active
active

The web console answers on the loopback interface:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/fog/management/index.php
200

Terminal showing the FOG Project appliance services active and the web console answering with HTTP 200

Step 5 - Confirm no DHCP server is running

This is the property that makes FOG safe to run on a cloud network, so verify it yourself. FOG records its DHCP decision in its own settings file:

sudo grep -E '^(bldhcp|dodhcp)=' /opt/fog/.fogsettings
dodhcp='N'
bldhcp='0'

No DHCP server package is installed:

for p in isc-dhcp-server kea-dhcp4-server dnsmasq; do
  if dpkg-query -W -f='${Status}' "$p" 2>/dev/null | grep -q '^install ok installed$'; then
    echo "$p: INSTALLED"
  else
    echo "$p: not installed"
  fi
done
isc-dhcp-server: not installed
kea-dhcp4-server: not installed
dnsmasq: not installed

And nothing is listening on the DHCP server port:

ss -lnu | grep -c ':67 ' || echo 0
0

Terminal showing FOG's DHCP server disabled, no DHCP packages installed and nothing listening on port 67

Step 6 - Retrieve your per-VM credentials

Every credential on this VM was generated on its own first boot. The file is readable only by root.

sudo cat /root/fog-project-credentials.txt

You will see the console login, both API tokens, the server address and the database credentials. The console password is what you use in Step 8:

sudo grep -E '^(fog_web_url|fog_admin_user|fog_server_address|fog_tftp_bootfile)=' /root/fog-project-credentials.txt

The file is 0600 root:root:

sudo ls -l /root/fog-project-credentials.txt

FOG's documented default login, fog / password, does not work on your VM - the build replaces it with the generated password before the image is captured, and the first boot then sets a value unique to your machine.

Terminal showing the first-boot service active and the root-only per-VM credentials file

Step 7 - Confirm the boot plane and image store

Fetch a PXE bootloader over TFTP exactly as a booting machine would:

cd /tmp && rm -f undionly.kpxe && tftp 127.0.0.1 -c get undionly.kpxe && ls -l undionly.kpxe
-rw-r--r-- 1 azureuser azureuser 105509 Jul 19 08:40 undionly.kpxe

The iPXE chain file tells booting machines where to find the FOG server. It is regenerated with your VM's address on first boot:

sudo tail -1 /tftpboot/default.ipxe

The image store is exported over NFS, scoped to your VM's own subnet rather than to every host:

sudo exportfs -s
/images  10.0.0.0/24(sync,no_wdelay,hide,insecure_locks,fsid=0,anonuid=1001,anongid=1001,sec=sys,ro,secure,root_squash,all_squash)
/images/dev  10.0.0.0/24(async,no_wdelay,hide,fsid=1,anonuid=1001,anongid=1001,sec=sys,rw,secure,root_squash,all_squash)

If your machines are imaged from a different subnet reached over VPN or ExpressRoute, add that CIDR to /etc/exports and re-export. This block is an example to adapt, not something to run as is:

# /etc/exports - add your imaging subnet alongside the local one
/images      10.50.0.0/16(ro,sync,no_wdelay,subtree_check,insecure_locks,all_squash,anonuid=1001,anongid=1001,fsid=0)
/images/dev  10.50.0.0/16(rw,async,no_wdelay,subtree_check,all_squash,anonuid=1001,anongid=1001,fsid=1)

Terminal showing a PXE bootloader fetched over TFTP, the iPXE chain file and the subnet scoped NFS export

Step 8 - Sign in to the FOG console

Browse to http://<vm-ip>/fog/management. Sign in as fog with the fog_admin_password value from Step 6.

The FOG Project console login page

The dashboard shows the server at a glance: storage group activity, disk usage on the storage node and imaging activity over the last 30 days.

The FOG Project dashboard showing system overview, storage group activity and storage node disk usage

Step 9 - Point your DHCP server at the FOG server

FOG needs your existing DHCP server to tell booting machines where to find it. Set two options on the scope serving the machines you want to image:

  • Option 66 (next-server / TFTP server name) - this VM's private IP address, the fog_server_address value from Step 6
  • Option 67 (filename / bootfile name) - undionly.kpxe for BIOS machines, or snponly.efi for UEFI machines

On an ISC DHCP server, the scope looks like this. Adapt the addresses to your network; this is an example, not something to run on this VM:

# dhcpd.conf - point PXE clients at the FOG server
subnet 10.50.0.0 netmask 255.255.0.0 {
  range 10.50.10.100 10.50.10.200;
  option routers 10.50.0.1;
  next-server 10.0.0.4;          # your FOG server's private IP
  filename "undionly.kpxe";      # use "snponly.efi" for UEFI clients
}

On a Windows DHCP server, set scope option 066 Boot Server Host Name to the FOG server's IP and 067 Bootfile Name to undionly.kpxe or snponly.efi.

Mixed BIOS and UEFI fleets need your DHCP server to select the bootfile by client architecture. Both ISC DHCP and Windows Server support this; FOG's documentation covers the exact syntax.

Step 10 - Register a machine

With DHCP pointing at the server, boot a client machine from the network. It fetches the bootloader, chains to FOG, and presents the FOG boot menu. Choose Perform Full Host Registration and Inventory to add it to FOG with its hardware inventory.

Registered machines appear under Host Management, where you assign an image, put them in groups and schedule tasks.

FOG Project Host Management listing registered machines

Step 11 - Define an image and capture

Under Image Management, select Create New Image and give it a name, a storage group and an image type. Single Disk - Resizable suits most single-disk Windows and Linux workstations.

FOG Project Image Management showing the image library

To capture, assign the image to your reference machine under Host Management, schedule a Capture task, and network boot that machine - it boots into FOG's imaging environment and uploads the image to /images. To deploy, assign the same image to the target machines, schedule a Deploy task, and boot them.

Step 12 - Use the REST API

FOG's REST API is enabled on this image with tokens generated for your VM. Both tokens are stored ready to paste straight into the request headers.

API_TOKEN=$(sudo grep '^fog_api_token=' /root/fog-project-credentials.txt | cut -d= -f2-)
USER_TOKEN=$(sudo grep '^fog_user_api_token=' /root/fog-project-credentials.txt | cut -d= -f2-)
curl -s -H "fog-api-token: ${API_TOKEN}" -H "fog-user-token: ${USER_TOKEN}" \
  http://127.0.0.1/fog/system/info
success

List the registered machines as JSON:

API_TOKEN=$(sudo grep '^fog_api_token=' /root/fog-project-credentials.txt | cut -d= -f2-)
USER_TOKEN=$(sudo grep '^fog_user_api_token=' /root/fog-project-credentials.txt | cut -d= -f2-)
curl -s -H "fog-api-token: ${API_TOKEN}" -H "fog-user-token: ${USER_TOKEN}" \
  http://127.0.0.1/fog/host | head -c 200

Requests without valid tokens are rejected:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/fog/system/info
403

Note that FOG's hostName column is 16 characters, so machine names are truncated beyond that.

Security

  • No DHCP server. FOG's own DHCP server is not installed and is not running. This is asserted at build time and again on every first boot; the appliance refuses to start it.
  • No default credentials. FOG's documented fog / password default does not authenticate on your VM. The console password, both API tokens, both database passwords and the storage account password are generated on your VM's first boot and exist nowhere else. They are written to /root/fog-project-credentials.txt at 0600 root:root.
  • The database is not reachable off the VM. MariaDB is bound to 127.0.0.1 with name resolution disabled.
  • The image store is scoped. Upstream FOG exports /images to every host with /images/dev writable. This image exports it to your VM's own subnet instead, and you widen it deliberately as shown in Step 7.
  • The boot plane is anonymous by protocol necessity. TFTP has no authentication and a machine that is powering on cannot present credentials. Scope 69/udp, 2049/tcp and 21/tcp with your NSG to the subnets that image machines, and never expose them to the internet.
  • FOG stores console passwords as unsalted MD5. That is upstream FOG's scheme and cannot be changed without forking its authentication. Treat the console as a trusted-network service, put it behind your NSG, and do not reuse the console password anywhere else.
  • Change the console password from Users in the web console if you want a value you have chosen rather than the generated one.

Maintenance

Ubuntu security updates apply automatically through unattended upgrades. Restart the appliance after a kernel update:

sudo systemctl restart apache2 mariadb tftpd-hpa nfs-kernel-server

Back up the FOG database and your image library. The database holds the inventory, groups, tasks and settings:

sudo mysqldump fog | gzip > /tmp/fog-backup.sql.gz && ls -lh /tmp/fog-backup.sql.gz

Watch free space on /images - it fills as your image library grows:

df -h /images | tail -1

Licence and source

FOG Project is licensed under the GNU General Public License, version 3 or later. The complete corresponding source for the version in this image ships on the image:

ls /opt/fog-source/LICENSE /opt/fog-source/CLOUDIMG-SOURCE-NOTICE.txt

The notice file records the exact upstream commit, the source URLs for the bundled iPXE and Syslinux bootloaders, and a written offer for machine-readable source. Nothing in cloudimg's terms restricts your rights in the FOG software or any other GPL-licensed component.

Support

cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk. For questions about FOG itself, the project's own documentation is at docs.fogproject.org and its community forum is at forums.fogproject.org.