Debian 13 with GNOME Desktop on Azure User Guide
Overview
This guide covers the deployment and configuration of Debian 13 "trixie" with the GNOME desktop on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.
Debian is one of the oldest and most widely used Linux distributions, produced by the Debian Project. Debian 13 "trixie" was released on 9 August 2025 and has security support from the Debian Security Team followed by Debian LTS, to 30 June 2030. This image is the cloudimg Debian 13 base with Debian's own GNOME 48 desktop added from Debian main (GDM, GNOME Shell, GNOME Session, Nautilus and the standard GNOME applications) and GNOME's own remote desktop server, gnome-remote-desktop, set up for remote login: you connect with any RDP client, see the GNOME login screen, and sign in to a full desktop session running on the virtual machine.
The image is built so that a freshly deployed machine exposes nothing but SSH. Remote desktop ships switched off, no account has a password, and nothing listens on the RDP port until you decide to turn it on. A desktop login always needs a password, so the image never ships one: you set your own over SSH, then enable remote desktop with a single command.
What's included:
- Debian 13 "trixie" with the GNOME 48 desktop (GDM login screen, GNOME Shell, Files, Terminal, Text Editor, System Monitor, Settings) from Debian main; GVFS is rebuilt from Debian source without the Google Drive backend, so every remote-location type except Google Drive (
google-drive://) is available in Files - GNOME Remote Desktop 48.1 in system mode: RDP remote login through the GNOME login screen, with the modern RDP graphics pipeline
- A per-VM RDP credential and a per-VM self signed TLS certificate, generated at first boot and readable by root only
cloudimg-remote-desktop, a small helper to show the remote desktop state, switch it on and off, and print your VM's RDP credential- Every available security update applied at build time, with
unattended-upgradesarmed so the machine keeps patching itself - The Azure provisioning path unchanged: cloud-init, the Azure Linux Agent and systemd-networkd
- Gen2 Hyper V virtual machine support
- 24/7 cloudimg support
A deliberate difference from Debian's stock cloud image: this image runs Debian's generic linux-image-amd64 kernel rather than the linux-image-cloud-amd64 flavour Debian's own cloud images boot. The cloud flavour is stripped for headless servers and omits the DRM graphics drivers, including hyperv_drm. Without that driver there is no /dev/dri device, GNOME cannot start a graphical session, and the login screen never appears. The generic flavour is a fully supported Debian kernel on exactly the same security update stream; it simply carries more drivers. If you rebuild or re-pin the kernel yourself, keep the generic flavour or the desktop will stop working.
What's deliberately NOT included: a web browser, NetworkManager (networking is managed by systemd-networkd, the Azure default), printing, Bluetooth, the Avahi service discovery daemon and the GNOME first login wizard. None of these add anything on a cloud server, and several would open network listeners. Install anything you need with sudo apt install.
Platform: Microsoft Azure (Gen2 Hyper V, x64)
Default user: azureuser
Security posture
This image ships with no known credential:
- No account has a password. The root account is locked, and
azureuseris created at first boot with only the SSH key you supply. - SSH is key only (
PasswordAuthentication no). Setting an account password for the desktop does not enable password logins over SSH. - The remote desktop server is installed but disabled: a new virtual machine listens on SSH port 22 only.
- The RDP credential and the RDP TLS certificate are generated on your virtual machine at first boot. They are unique to that machine and are not baked into the image, so no two deployments share them.
- LLMNR is switched off. Debian 13's
systemd-resolvedenables LLMNR by default, which listens off box on TCP and UDP port 5355; this image disables it so the only off box listener is SSH.
Prerequisites
- An active Microsoft Azure subscription
- Azure CLI installed and authenticated, or access to the Azure Portal
- An SSH key pair
- An RDP client. Windows App (Windows, macOS, iOS, Android), the built in Windows Remote Desktop Connection (
mstsc), or Remmina and FreeRDP 3 on Linux all work. - A virtual machine size with at least 8 GB of RAM.
Standard_B2msis the recommended size and is what this image is tested on; GNOME plus a remote session does not fit comfortably in the 4 GB of aStandard_B2s.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Sign in to the Azure Portal.
- Search the Marketplace for Debian 13 with GNOME Desktop and select the cloudimg offer.
- Choose Create.
- Select your subscription, resource group and region.
- Enter a virtual machine name.
- Choose a size of Standard_B2ms or larger.
- Set the authentication type to SSH public key, with username
azureuserand your own public key. - Under Inbound port rules, allow SSH (22) only. Do not open 3389: the recommended route to the desktop is an SSH tunnel, and remote desktop is switched off on a new machine anyway.
- Review and create.
Option B: Azure CLI
Run this on your own workstation, substituting your resource group, VM name and preferred region. Accept the Marketplace terms once per subscription, then create the machine:
az vm image terms accept --urn cloudimg1647283583153:debian-13-gui:default:latest
az vm create \
--resource-group myResourceGroup \
--name my-debian-13-gui-vm \
--image cloudimg1647283583153:debian-13-gui:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Step 2: Connect via SSH
ssh azureuser@<your-vm-public-ip>
Everything in this guide is done over SSH. You will not need the Azure serial console.
Step 3: Confirm the release and the desktop
cat /etc/os-release
cat /etc/debian_version
uname -r
You should see Debian GNU/Linux 13 (trixie), a point release of 13.x, and a kernel ending -amd64 (the generic flavour, not -cloud-amd64).
Confirm the desktop is installed and the machine boots to a graphical login screen:
systemctl get-default
systemctl is-active graphical.target
systemctl is-active gdm.service
dpkg-query -W -f='${Package} ${Version}\n' gdm3 gnome-shell gnome-session gnome-remote-desktop nautilus
systemctl get-default should print graphical.target, both is-active checks should print active, and dpkg-query should list GDM, GNOME Shell, GNOME Session, GNOME Remote Desktop and Nautilus at version 48.x.
The graphics device the desktop renders on:
ls -l /dev/dri/
You should see card0. If that directory is missing, the machine is running the wrong kernel flavour; see Troubleshooting.
Step 4: Check that remote desktop is off
sudo cloudimg-remote-desktop status
On a new machine this reports the service as disabled / inactive, the RDP backend as disabled, nothing listening on 3389, a per-VM RDP credential that has been generated, and no accounts able to log in at the GNOME login screen.
Confirm nothing but SSH is listening off box:
ss -tln
The only non loopback listener should be port 22.
Step 5: Set your password and turn remote desktop on
The GNOME login screen asks for your own account password. The image does not ship one, so set it now:
sudo passwd azureuser
This password is used only at the graphical login screen. SSH remains key only.
Now turn remote desktop on:
sudo cloudimg-remote-desktop enable
The helper refuses to enable remote desktop while no administrator account has a password, so that a login screen is never exposed with nothing behind it. Once enabled it reports that port 3389 is listening and prints the TLS certificate fingerprint.
Print this machine's RDP credential:
sudo cloudimg-remote-desktop credentials
You will get RDP_USERNAME, RDP_PASSWORD, RDP_PORT and the TLS fingerprints. There are two secrets and they are different:
- the RDP credential above is asked for by your RDP client before anything is drawn (Network Level Authentication). It is not an operating system account and cannot be used for SSH.
- the account password you set in
sudo passwdis what the GNOME login screen asks for once the session opens.
Step 6: Connect with your RDP client
The recommended route is an SSH tunnel, so port 3389 is never exposed to the internet. On your own workstation:
ssh -N -L 3389:localhost:3389 azureuser@<your-vm-public-ip>
Leave that running, then point your RDP client at localhost:3389.
- Your client will warn about the self signed certificate. Compare its fingerprint with the
RDP_TLS_SHA256value from Step 5 and accept it. - At the first prompt, enter the RDP credential from Step 5.
- The GNOME login screen then appears. Select your user and enter the account password you set in Step 5.
If you would rather not tunnel, you can instead add an Azure network security group rule allowing TCP 3389 from your own IP address only (/32). Do not open 3389 to the internet.
Step 7: Use the desktop
You now have a full GNOME 48 session. The Activities overview (top left, or the Super key) gives you the application grid; Files, Terminal, Text Editor, System Monitor and Settings are installed.
The machine has no GPU acceleration, so expect software rendering. For everyday administration, editing and browsing of local files this is perfectly usable at 1280x720 or 1920x1080.
Remote locations in Files
Files can open remote locations over SMB/CIFS (Windows and Samba shares), SFTP, WebDAV, NFS, AFP and FTP, browse Android phones over MTP and iPhones/iPads over AFC, read cameras over PTP, open archives in place, and mount Microsoft OneDrive. In Files, choose Network in the sidebar and type an address such as smb://fileserver/share or sftp://host/ into the Server address box at the bottom, then Connect; or use gio mount from a terminal:
# list the location types this image can mount
ls /usr/share/gvfs/mounts/ | sed 's/\.mount$//'
One exception: Google Drive is not available in Files on this image. You can still add a Google account under Settings -> Online Accounts and use it in Calendar and Contacts, but the account's page offers only Mail, Calendar and Contacts — there is no Files switch — Drive does not appear in the Files sidebar, and google-drive:// locations will not open. (The Connect an Account list still describes Google as "Email, calendar, contacts, files"; that is a fixed label in Settings.) Microsoft 365 accounts are unaffected and still offer Files through the OneDrive backend. This is deliberate: Google Drive support is the only part of GVFS that needs the libgdata library, so this image ships GVFS rebuilt from Debian's own source with that one backend switched off (the same configuration Debian ships on i386), and /etc/goa.conf tells GNOME Online Accounts not to offer Files for Google accounts. If you need Google Drive in Files, switch back to Debian's stock GVFS build (which pulls libgdata back in), remove the [google] section from /etc/goa.conf, then sign out and back in. The cloudimg build carries a higher version number than the archive copy, so a plain apt-get install is a no-op and the downgrade has to be explicit:
V="$(apt-cache madison gvfs-backends | awk -F'|' 'NR==1{gsub(/ /,"",$2); print $2}')"
sudo apt-get install --allow-downgrades gvfs=$V gvfs-backends=$V gvfs-common=$V gvfs-daemons=$V gvfs-fuse=$V gvfs-libs=$V
sudo sed -i '/^\[google\]/,/^files=/d' /etc/goa.conf
Debian security updates to GVFS are not blocked: the cloudimg build is versioned just below Debian's next GVFS update, so when Debian publishes one the machine moves onto Debian's build — which brings the Google Drive backend and libgdata back with it.
Step 8: Verify the security posture
Confirm no account carries a password hash other than the one you just set:
sudo awk -F: '($2 ~ /^\$/) {print $1}' /etc/shadow
Only azureuser should appear, because you set that password yourself in Step 5.
Confirm SSH is still key only:
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin)'
Confirm the RDP TLS certificate belongs to this machine:
sudo openssl x509 -in /var/lib/gnome-remote-desktop/.local/share/gnome-remote-desktop/rdp-tls.crt -noout -subject -fingerprint -sha256
The CN should be your VM's hostname, not a cloudimg build machine.
Step 9: Networking
Networking is handled by cloud-init and systemd-networkd, the Azure default. NetworkManager is not installed.
networkctl status
resolvectl status
LLMNR is disabled by /etc/systemd/resolved.conf.d/20-cloudimg-no-llmnr.conf. If you want it back, delete that file and run sudo systemctl restart systemd-resolved.
Step 10: Turn remote desktop off, or change the RDP credential
To switch remote desktop off again and close the port:
sudo cloudimg-remote-desktop disable
To rotate the RDP credential to a new random password:
sudo grdctl --system rdp set-credentials "$(whoami)" "$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | cut -c1-24)"
sudo systemctl restart gnome-remote-desktop.service
sudo cloudimg-remote-desktop credentials
Step 11: Check the patch level
sudo apt-get update
echo "pending upgrades: $(apt-get -s dist-upgrade | grep -c '^Inst ' || true)"
systemctl is-enabled unattended-upgrades.service
The image ships fully patched with unattended-upgrades armed, so the machine continues to apply security updates on its own.
Common Use Cases
- A Linux desktop in Azure for developers who need a graphical toolchain, an IDE or a browser close to other Azure resources
- A jump box with a real desktop for administering systems that only expose web or graphical consoles inside a virtual network
- Training, demonstration and lab environments where every student needs an identical Debian desktop
- Testing desktop Linux software against Debian 13 without local hardware
Troubleshooting
The RDP client connects, then the screen stays black or disconnects
Check that the handover service is running in your session:
systemctl --user status cloudimg-remote-desktop-handover.service
journalctl -b | grep -i handover
GNOME's remote login needs a "handover" helper in both the login screen and your session. This image ships that wiring; if you have removed /usr/local/libexec/cloudimg-grd-remote-session, /etc/systemd/user/cloudimg-remote-desktop-handover.service or /usr/share/gdm/greeter/autostart/cloudimg-remote-desktop-handover.desktop, remote login will show a black screen and the journal will log Aborting handover. Do not enable the stock gnome-remote-desktop-handover.service alongside them: both claim the same D-Bus name and systemd refuses the second one.
The login screen never appears and /dev/dri is missing
The machine is running the -cloud-amd64 kernel, which has no DRM graphics driver. Reinstall the generic kernel and remove the cloud flavour:
sudo apt-get install --reinstall linux-image-amd64
sudo apt-get purge 'linux-image-*-cloud-amd64' linux-image-cloud-amd64
sudo update-grub
sudo reboot
The RDP client says the credentials are wrong
You are being asked for the RDP credential (Step 5), not your account password. Print it again with sudo cloudimg-remote-desktop credentials.
The login screen does not accept my password
That prompt wants your account password, the one you set with sudo passwd azureuser. If you have forgotten it, set it again over SSH.
The client reports a graphics pipeline error
Older RDP clients that do not advertise the RDP graphics pipeline are refused. With FreeRDP, pass /gfx /bpp:32. Current Windows App, mstsc and Remmina are all fine.
Cannot connect via SSH
- Confirm the network security group allows TCP 22 from your address.
- Confirm you are using the private key matching the public key given at deployment.
- Check the VM is running in the Azure Portal.
Azure agent not running
systemctl status walinuxagent
sudo systemctl restart walinuxagent
Important Notes
- Two passwords, both yours. The per-VM RDP credential gates the connection before any pixel is drawn; your own account password gates the GNOME login screen. The image ships neither: the first is generated on your machine at first boot, the second you choose.
- Remote desktop ships off. A new machine listens on SSH only. The listing does not pre-open 3389 in your network security group.
- Keep the generic kernel. The
-cloud-amd64flavour has no DRM driver and the desktop will not start on it. - Use an SSH tunnel rather than exposing 3389 to the internet.
- Google Drive is not available in Files (see Step 7). Every other remote location type — SMB, SFTP, WebDAV, NFS, AFP, FTP, MTP, AFC, OneDrive — works normally, and Google accounts still work in Settings -> Online Accounts for Calendar and Contacts.
- Debian 13 "trixie" has security support to 30 June 2030.
- cloudimg is not affiliated with, endorsed by or sponsored by the Debian Project or the GNOME Foundation. "Debian" is a trademark of Software in the Public Interest, Inc. and "GNOME" is a trademark of the GNOME Foundation; both are used here nominatively to identify the software this image contains.
Support
For assistance with this image, contact cloudimg support at support@cloudimg.co.uk. Support is available 24/7.