Ubuntu Server 24.04
Videos
Overview video: Ubuntu Server 24.04 LTS on Azure (watch on YouTube)
Launch and log in video: Ubuntu Server 24.04 LTS on Azure (watch on YouTube)
Overview
This guide covers the deployment and configuration of Ubuntu Server 24.04 LTS (Noble Numbat) on Microsoft Azure, using SecureAnyCloud's preconfigured virtual machine image from the Azure Marketplace. The image combines Canonical's Ubuntu Server base with the Azure Linux Agent and the Azure-tuned Linux kernel for cloud integration.
What you get:
- Ubuntu Server 24.04 LTS with Canonical standard security maintenance until May 2029 (extended maintenance requires an Ubuntu Pro subscription, which is not included)
- Azure Linux Agent (waagent) for cloud integration
- Chrony (chronyd) for NTP time synchronization
- Gen2 Hyper-V virtual machine support
- Azure-tuned Linux kernel (linux-azure)
- Platform: Microsoft Azure (Gen2 Hyper-V)
- Login user: the administrator username you choose when you deploy (
azureuserin the examples below). The image honors the authentication type you pick in the portal: SSH public key (recommended) or password. - 24/7 SecureAnyCloud support
Prerequisites
Before you deploy this image, make sure you have the following:
- An active Microsoft Azure subscription
- Access to the Azure Portal or Azure CLI
- An SSH key pair (recommended) or a strong password for Linux VM access
- Familiarity with Azure VM management
Recommended VM Size: Standard_B2s (2 vCPU, 4 GB RAM) or larger.
Deploy the Virtual Machine
Option A: Azure Portal
- Go to the Azure Marketplace and search for "Ubuntu Server 24.04 LTS on Azure SecureAnyCloud"
- Select the image, then select Create
- Configure the basics:
- Subscription: Select your Azure subscription
- Resource Group: Create new or select existing
- Virtual Machine Name: Enter a name for your VM
- Region: Select your preferred Azure region
- Size:
Standard_B2srecommended - Under Administrator Account, choose the username you want to log in as, then select SSH public key (recommended) and enter your key, or select Password and set a strong password
- Under Inbound Port Rules, allow SSH (port 22)
- Select Review + Create, then select Create
Option B: Azure CLI
Accept the Marketplace terms once per subscription, then create the VM:
az vm image terms accept --urn sac1647283583153:ubuntu-24-04:default:latest
az vm create \
--resource-group myResourceGroup \
--name my-ubuntu-server-24-04-azure-vm \
--image sac1647283583153:ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku StandardChoosing a VM size
General-purpose, memory-optimized, compute-optimized and burstable sizes of the v5 generation and earlier run this image. Four kinds of size do not work with it:
- NVMe-only sizes (the v6 generation, such as Dsv6, Ddsv6, Dasv6 and Easv6): this image boots from a SCSI disk controller, so Azure refuses to create it on a size that offers only NVMe ("cannot boot with OS image or disk"). Choose a v5 or earlier size instead, for example
Standard_D2s_v5orStandard_D2as_v5. - Confidential VM sizes (such as DCasv5, ECasv5 and their v6 successors): these need an image that supports the Confidential VM security type. This image supports the Standard security type only (not Trusted launch or Confidential VM), so if your organization's Azure Policy requires Trusted launch, the deployment is refused.
- Arm64 sizes (a
pin the size name, such asStandard_D2ps_v5): this image is x64. - NVv4 GPU sizes (such as
Standard_NV4as_v4): Microsoft supports the NVv4 AMD GPU on Windows only and retired the series on 30 September 2026, so the GPU cannot be used from Linux. For an NVIDIA GPU size, see Step 6.
Connect via SSH
When your VM is running, connect over SSH:
ssh azureuser@<public-ip-address>To find your VM's public IP address, run:
az vm show --resource-group myResourceGroup --name my-ubuntu-server-24-04-azure-vm --show-details --query publicIps -o tsvVerify the Installation
After you connect, verify the operating system:
cat /etc/os-release uname -rCheck disk space and memory:
df -h free -hVerify that the Azure Linux Agent is running. On Ubuntu, its service is named walinuxagent:
systemctl status walinuxagentUpdate the System
Keep your system up to date by installing the latest security patches:
sudo apt-get update && sudo apt-get upgrade -yConfigure Firewall (Optional)
The Azure Network Security Group (NSG) controls inbound and outbound traffic. Ubuntu's own firewall, ufw, ships inactive. Check its status:
sudo ufw status verboseTo enable it, allow SSH first so that you do not lock yourself out, then allow any other ports you need:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableInstall a GPU Driver (NVIDIA GPU Sizes Only)
The image ships without a GPU driver, so on an NVIDIA GPU size (such as the NC, ND and NV series with NVIDIA GPUs), nvidia-smi does not work until you install one. Canonical publishes prebuilt NVIDIA kernel modules for the image's Azure kernel, and ubuntu-drivers picks the right driver for your GPU:
sudo apt-get update
sudo apt-get install -y ubuntu-drivers-common
sudo ubuntu-drivers list
sudo ubuntu-drivers install sudo rebootAfter the reboot, run nvidia-smi to see the GPU. On a size without an NVIDIA GPU, ubuntu-drivers list prints nothing, and ubuntu-drivers install has nothing to install.
Common Use Cases
- Modern cloud-native application hosting
- AI/ML workloads and data science environments
- Container and Kubernetes deployments
- Edge computing and IoT platforms
Troubleshooting
Cannot Connect via SSH
- Verify the VM is in Running state in the Azure Portal
- Check that port 22 is allowed in the Network Security Group
- Make sure you are using the administrator username you chose at deployment (
azureuseronly if you kept the example) and the matching key or password - Verify your SSH key matches the one configured during deployment
Azure Agent Not Running
Start the agent and enable it at boot:
sudo systemctl start walinuxagent
sudo systemctl enable walinuxagentPackage Manager Issues
Refresh the package index and upgrade the installed packages:
sudo apt-get update && sudo apt-get upgrade -yIf repositories are unreachable, check DNS resolution:
nslookup google.comImportant Notes
Ubuntu is free and open source. No license is required.
Support
For assistance with this image, contact SecureAnyCloud support:
- Website: secureanycloud.com
- Product catalog: secureanycloud.com/products
- User guides: secureanycloud.com/guides
- SLA: 24-hour response guaranteed
Deploy on Azure
Launch Ubuntu Server 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This image is Ubuntu Server 24.04 LTS (Noble Numbat), one software version in the SecureAnyCloud Hardened Ubuntu 22.04, 24.04 & 26.04 LTS AMIs: Minimal, LVM, STIG listing on AWS Marketplace. Every release and variant in the listing is described at /guides/ubuntu-server-aws/.
The host firewall is enabled (ufw, inbound SSH only). Open application ports in both the security group and ufw. Opening a port in the security group alone is not enough.
What you get:
- Remediated with the OpenSCAP CIS Level 1 Server profile. The build applies the SCAP Security Guide 0.1.82 profile
cis_level1_serverwithoscap --remediate, reboots, then runs a scored evaluation. The build fails if fewer than 95% of the scored rules pass; this version scored 348 of 352 rules (98.9%). The report ships in the image at/usr/share/doc/sac/cis-l1-report.html. This is a measurement made by open-source tooling, not a certification or accreditation by the benchmark's publisher or any other body, and these images are not CIS Hardened Images. - 6 rules waived, each with its reason (listed below and in
/usr/share/doc/sac/cis-l1-waivers.txt). These are rules that would lock you out of an EC2 instance or need a password baked into every copy of the image. - Fully patched at build time. The build fails if any update is outstanding or a reboot is pending.
- Automatic security updates stay enabled (unattended-upgrades).
- Key-only SSH as
ubuntu. Password login is off, root login is refused, the root account is locked, and no account has a password. - IMDSv2 only. The AMI is marked IMDSv2-only, so instances launched from it require session tokens for instance metadata.
- Host firewall enabled (ufw): inbound SSH only, with outbound traffic open so that the SSM agent, updates, DNS and NTP work.
- AppArmor enforcing, chrony on the Amazon Time Sync Service (169.254.169.123, no internet access needed), and the AWS Systems Manager (SSM) agent installed from its Debian package (no snaps).
- Nothing shared between instances. No SSH keys, host keys, machine ID or credentials are baked in. cloud-init creates them on each instance's first boot.
- No swap, and SSH is the only service listening on the network (the DNS stub resolver, chrony and the local mail transfer agent listen on loopback only).
Connecting to your instance
Connect over SSH as the default login user for the operating system variant you launched. For Ubuntu Server 24.04 LTS, the login user is ubuntu.
Launch from AWS Marketplace
- Open the listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for full control), then in Version choose Ubuntu Server 24.04 LTS - YYYY-MM-DD (the date is when the version was added) and your Region.
- Instance type:
m5.largeis recommended, and any current x86_64 type works. The software charge is $0.04 per vCPU per hour. - Key pair: choose your EC2 key pair. It is the only way in. RSA and ED25519 keys both work.
- Security group: allow inbound TCP 22 from your own IP address or network only.
- Storage: the root volume is 8 GiB gp3 by default. Choose a larger size if you need one. cloud-init grows the root file system to fill it on first boot.
- Metadata: leave the defaults. The image already requires IMDSv2. Then choose Launch.
To launch from the AWS CLI, use the AMI ID that the Marketplace launch page shows for your Region:
aws ec2 run-instances --image-id ami-xxxxxxxxxxxxxxxxx --instance-type m5.large \
--key-name my-key --security-group-ids sg-xxxxxxxx --subnet-id subnet-xxxxxxxxConnect over SSH
Connect with your key pair:
ssh -i ~/.ssh/my-key.pem ubuntu@<public-ip>ubuntu has passwordless sudo. There is no password on any account. AWS Systems Manager Session Manager also works: the SSM agent is installed and running (attach an instance profile with AmazonSSMManagedInstanceCore).
Confirm the release and kernel:
grep -E '^(PRETTY_NAME|VERSION_ID|VERSION_CODENAME)=' /etc/os-release uname -rPRETTY_NAME="Ubuntu 24.04.5 LTS" VERSION_ID="24.04" VERSION_CODENAME=noble 7.0.0-1014-awsThe kernel version moves forward as Ubuntu publishes updates. The image ships the kernel that is current on its build date.
IMDSv2
The AMI carries ImdsSupport=v2.0, so every instance launched from it gets HttpTokens=required. Check it on the instance:
imds_token=$(curl -s -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 300' http://169.254.169.254/latest/api/token)
curl -s -H "X-aws-ec2-metadata-token: $imds_token" http://169.254.169.254/latest/meta-data/instance-id; echo
curl -s -o /dev/null -w '%{http_code}\n' http://169.254.169.254/latest/meta-data/instance-idThe first request (with a token) returns your instance ID. The second request (IMDSv1, no token) is refused with 401:
i-0123456789abcdef0 401From your workstation, you can confirm the setting in the instance's metadata options:
aws ec2 describe-instances --instance-ids <instance-id> \
--query 'Reservations[0].Instances[0].MetadataOptions' --output table------------------------------------------------------------------------------------------------------------------ | DescribeInstances | +--------------+-------------------+--------------------------+-------------+------------------------+-----------+ | HttpEndpoint | HttpProtocolIpv6 | HttpPutResponseHopLimit | HttpTokens | InstanceMetadataTags | State | +--------------+-------------------+--------------------------+-------------+------------------------+-----------+ | enabled | disabled | 2 | required | disabled | applied | +--------------+-------------------+--------------------------+-------------+------------------------+-----------+HttpTokens is required, and the hop limit of 2 lets a container on the instance reach the metadata service with a token.
Software that still uses IMDSv1 must be updated to request a token (current AWS SDKs and CLIs already do). If you must allow IMDSv1 temporarily, change it per instance with aws ec2 modify-instance-metadata-options --http-tokens optional. We do not recommend this.
View the compliance report
The evaluation that the build ran is in /usr/share/doc/sac/cis-l1-report.html (HTML), /usr/share/doc/sac/cis-l1-arf.xml (machine-readable ARF) and /usr/share/doc/sac/cis-l1-summary.json (counts, pass rate, threshold, SSG version and checksums). The shipped copy replaces the build host's name and addresses.
ls /usr/share/doc/sac/ python3 -c "import json; d=json.load(open('/usr/share/doc/sac/cis-l1-summary.json')); print(d['profileLabel'], d['ssgVersion'], '-', d['pass'], 'of', d['scored'], 'scored rules pass', '(' + str(d['ratePct']) + '%)', '- waived', d['waived'])"cis-l1-arf.xml cis-l1-report.html cis-l1-summary.json cis-l1-tailoring.xml cis-l1-waivers.txt scap-security-guide-LICENSE.txt CIS Level 1 Server 0.1.82 - 348 of 352 scored rules pass (98.9%) - waived 6Copy the HTML report to your workstation and open it in a browser:
scp -i ~/.ssh/my-key.pem ubuntu@<public-ip>:/usr/share/doc/sac/cis-l1-report.html .List the waived rules with their categories, and the scored rules that do not pass:
grep -v '^#' /usr/share/doc/sac/cis-l1-waivers.txt | cut -f1,2 python3 -c "import json; [print(r) for r in json.load(open('/usr/share/doc/sac/cis-l1-summary.json'))['failingRules']]"partition_for_tmp [single-volume-partitions] grub2_password [serial-console-and-boot] grub2_uefi_password [serial-console-and-boot] accounts_maximum_age_login_defs [key-only-account-aging] account_disable_post_pw_expiration [key-only-account-aging] sshd_limit_user_access [ssh-access-list] all_apparmor_profiles_in_enforce_complain_mode set_nftables_loopback_traffic set_nftables_table set_ufw_default_ruleThe full reason for each waiver is in the third column of the same file. The summary lists the 4 scored rules that do not pass under failingRules: all_apparmor_profiles_in_enforce_complain_mode, set_nftables_loopback_traffic, set_nftables_table and set_ufw_default_rule. The two nftables rules belong to the profile's nftables firewall option, which this image does not use (ufw is the host firewall). The rule set_ufw_default_rule fails because outbound traffic is allowed on purpose (see below).
You can re-run the same evaluation on your instance at any time. It takes about 5 to 10 minutes and changes nothing:
sudo oscap xccdf eval --tailoring-file /usr/share/sac/openscap/tailoring.xml \
--profile xccdf_co.sac_profile_cis-l1_ec2_single \
--report ~/cis-l1-rescan.html /usr/share/xml/scap/ssg/content/ssg-ubuntu2404-ds.xmlThe oscap command exits with status 2 when any rule fails. This is expected, and the HTML report is still written.
Waived rules
These rules of the profile are deselected through the tailoring file /usr/share/sac/openscap/tailoring.xml and are not scored. Everything else the profile selects is remediated and scored. The tailoring also selects ufw as the profile's firewall option and chrony as its time service.
Each entry below gives the rule, its category and the reason it is waived on EC2:
- partition_for_tmp (single-volume-partitions): The standard and Minimal versions boot from one EBS root volume, so /tmp, /var, /var/log, /var/log/audit, /var/tmp and /home live on the root file system. The LVM versions provide every one of these as a separate volume with the benchmark's mount options.
- grub2_password (serial-console-and-boot): A boot-loader or root password would have to be baked into the image, giving every instance the same credential. Root stays locked and no password exists. EC2 Serial Console and single-user recovery need a password that you set yourself on your own instance (see Emergency access).
- grub2_uefi_password (serial-console-and-boot): As above, for the UEFI boot loader.
- accounts_maximum_age_login_defs (key-only-account-aging): Password-age and inactivity defaults apply to every account that cloud-init creates at launch. Those accounts are key-only and have no password, so an age limit expires them and locks the SSH key out. Accounts that do have a password are still aged.
- account_disable_post_pw_expiration (key-only-account-aging): As above, for the inactivity default.
- sshd_limit_user_access (ssh-access-list): An AllowUsers/AllowGroups list fixed at build time would refuse SSH to accounts that you create with cloud-init user-data. SSH is key-only, root login is refused, and your security group restricts the source addresses.
Deliberate deviation (scored as a failure): ufw denies all inbound traffic except SSH (22/tcp) but allows outbound traffic, so set_ufw_default_rule reports fail and counts against the score. A default-deny outbound policy would cut the SSM agent off from its endpoints, cloud-init and the instance from the metadata service (169.254.169.254), and the instance from DNS, NTP and package updates.
Host firewall and SSH
ufw is active and allows inbound SSH only, and SSH accepts keys only. Check both:
sudo ufw status verbose
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin|pubkeyauthentication) '
sudo passwd -S rootStatus: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) New profiles: skip To Action From -- ------ ---- Anywhere on lo ALLOW IN Anywhere 22/tcp ALLOW IN Anywhere 68/udp ALLOW IN 67/udp
# DHCP client: replies from a DHCP server (port 67) 53 on lo ALLOW IN Anywhere
# systemd-resolved loopback stub 127.0.0.54:53 (lo only) Anywhere DENY IN 127.0.0.0/8 Anywhere (v6) on lo ALLOW IN Anywhere (v6) 22/tcp (v6) ALLOW IN Anywhere (v6) 53 (v6) on lo ALLOW IN Anywhere (v6)
# systemd-resolved loopback stub 127.0.0.54:53 (lo only) Anywhere (v6) DENY IN ::1 Anywhere ALLOW OUT Anywhere on lo Anywhere (v6) ALLOW OUT Anywhere (v6) on lo permitrootlogin no pubkeyauthentication yes passwordauthentication no root L 2024-04-23 0 99999 7 -1root L means the root password is locked. The 68/udp rule admits only the replies of the VPC's DHCP server to the instance's own DHCP client (the client that keeps the instance's private address), and the 53 on lo rules cover the systemd-resolved stub resolver on the loopback interface only. ufw already accepts both, and the explicit rules open nothing new to the network.
To serve anything else, open the port in both your security group and the host firewall, for example HTTPS:
sudo ufw allow 443/tcp
sudo ufw status verboseServices
Check that the services are running and that time synchronization is working:
systemctl is-active ssh ufw apparmor amazon-ssm-agent chrony
systemctl is-enabled unattended-upgrades chronyc -n sources | head -3active active active active active enabled MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^* 169.254.169.123 3 4 377 6 +2767ns[ +11us] +/- 536us^* marks the source that chrony is synchronized to: the Amazon Time Sync Service at 169.254.169.123, which every EC2 instance reaches without internet access. The Ubuntu NTP pool servers in /etc/chrony/chrony.conf remain as fallbacks.
Per-instance identity
Nothing that identifies a machine is baked into the image. The machine ID and the SSH host keys are created when the instance first boots, so their timestamps follow the boot time:
uptime -s sudo ls -l --time-style=+%F_%T /etc/machine-id /etc/ssh/ssh_host_*_key.pub ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub2026-10-19 10:57:33 -r--r--r-- 1 root root 33 2026-10-19_10:57:48 /etc/machine-id -rw-r--r-- 1 root root 182 2026-10-19_10:57:59 /etc/ssh/ssh_host_ecdsa_key.pub -rw-r--r-- 1 root root 102 2026-10-19_10:57:59 /etc/ssh/ssh_host_ed25519_key.pub -rw-r--r-- 1 root root 574 2026-10-19_10:57:59 /etc/ssh/ssh_host_rsa_key.pub 256 SHA256:<fingerprint> root@ip-172-31-87-69 (ED25519)The fingerprint is unique to your instance. Compare it with the one your SSH client showed on first connect.
Patching
unattended-upgrades installs security updates automatically. It runs daily. Confirm that it is enabled:
systemctl is-enabled unattended-upgrades cat /etc/apt/apt.conf.d/20auto-upgradesenabled APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1";To see how many updates are waiting and to install everything now, run:
apt list --upgradable 2>/dev/null | grep -c upgradable || truesudo apt-get update && sudo apt-get -y upgradeIf /var/run/reboot-required exists afterwards, a new kernel or core library was installed. Reboot when convenient with sudo reboot.
Emergency access
There is no password on any account, by design. EC2 Serial Console and single-user recovery need a local password. Set one for root on your own instance before you need it, and keep it in your secrets store:
sudo passwd rootSession Manager (SSM) is the other way in if SSH is unavailable.
Support
SecureAnyCloud provides 24/7 technical support for this image by email and live chat: sales@secureanycloud.com. Ubuntu is a registered trademark of Canonical Ltd. CIS and CIS Benchmarks are trademarks of the Center for Internet Security, Inc. SecureAnyCloud is not affiliated with or endorsed by Canonical or CIS.
Deploy on AWS
Launch Ubuntu Server 24.04 LTS on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com