cd /news/developer-tools/headless-mode-on-nvidia-jetson-agx-o… · home topics developer-tools article
[ARTICLE · art-41556] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Headless Mode on NVIDIA Jetson AGX Orin 64GB with JetPack 7.2

A developer documented a method to enable fully headless operation on the NVIDIA Jetson AGX Orin 64GB Developer Kit running JetPack 7.2. The guide uses NoMachine for remote GUI access with XFCE4 instead of GNOME, which fails due to DRI3/GPU acceleration requirements. Steps include setting a static IP, disabling network wait services, and configuring SSH for remote access.

read11 min views1 publishedJun 27, 2026

Tags: jetson

jetpack-7.2

headless

nomachine

ubuntu-24.04

embedded-ai

edge-ai

This guide walks through enabling fully headless operation on the NVIDIA Jetson AGX Orin Developer Kit running JetPack 7.2. After completing these steps, the device boots without any display, keyboard, or mouse — accessible entirely via SSH for terminal use and NoMachine for full GUI access.

Why NoMachine only?

JetPack 7.2 ships GNOME 46 on Ubuntu 24.04. GNOME 46 requires DRI3/GPU acceleration to render its compositor (Mutter). NoMachine's virtual display does not expose DRI3, causing gnome-shell to start but render nothing — only a black screen or bare wallpaper. XFCE4 has no compositor dependency, works perfectly in virtual displays, and is the stable choice for remote GUI access on this platform.

Component Value
Hardware NVIDIA Jetson AGX Orin Developer Kit 64GB
JetPack 7.2-b187
L4T r39.2 (Jetson Linux 39.2)
OS Ubuntu 24.04.4 LTS
Kernel 6.8.12-tegra
CUDA 13.2.1
Python 3.12.3
NoMachine 9.7.3
Remote host Windows 11 (same LAN via Ethernet)

192.168.1.100

as example)Connect a monitor and open a terminal (Ctrl+Alt+T

).

sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
sudo apt install -y \
  net-tools curl wget htop tmux tree \
  git nano vim \
  build-essential \
  python3-pip python3-venv python3-dev pipx \
  software-properties-common \
  apt-transport-https ca-certificates gnupg \
  cmake ninja-build libopenblas-dev

Install jtop

, the Jetson-specific system monitor:

pipx install jetson-stats
pipx ensurepath
source ~/.bashrc

sudo systemctl restart jtop 2>/dev/null || true
jtop --version
sudo hostnamectl set-hostname jetson-orin

sudo nano /etc/hosts

A static IP is required so SSH and NoMachine connections never break after reboots.

Critical:Theconnection.permissions ""

parameter makes the network connection available at boot without requiring a user graphical login. Without this, the Ethernet interface will not come up in headless mode and SSH will be unreachable.

nmcli connection show
nmcli device status

CONN="Wired connection 1"

sudo nmcli connection modify "$CONN" \
  ipv4.method manual \
  ipv4.addresses "192.168.1.100/24" \
  ipv4.gateway "192.168.1.1" \
  ipv4.dns "8.8.8.8,1.1.1.1" \
  ipv4.ignore-auto-dns yes \
  connection.permissions "" \
  connection.autoconnect yes \
  connection.autoconnect-priority 100

sudo nmcli connection down "$CONN" && \
  sudo nmcli connection up "$CONN"

hostname -I

Disable the network boot timeout service to prevent slow headless boots:

sudo systemctl disable NetworkManager-wait-online.service
sudo systemctl mask NetworkManager-wait-online.service
sudo apt install openssh-server -y
sudo systemctl enable ssh
sudo systemctl start ssh
sudo systemctl status ssh

Edit /etc/ssh/sshd_config

— back it up first:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo nano /etc/ssh/sshd_config

Ensure these directives are set (uncomment or add as needed):

Port 22
PubkeyAuthentication yes
PasswordAuthentication yes
PermitRootLogin prohibit-password
ClientAliveInterval 60
ClientAliveCountMax 10
TCPKeepAlive yes
X11Forwarding yes
MaxAuthTries 6
sudo systemctl restart ssh

From the remote host (replace 192.168.1.100

with your Jetson IP):

ssh-keygen -t ed25519 -C "remote-to-jetson" -f ~/.ssh/jetson_orin

ssh-copy-id -i ~/.ssh/jetson_orin.pub jetson@192.168.1.100

type "$env:USERPROFILE\.ssh\jetson_orin.pub" | `
  ssh jetson@192.168.1.100 `
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Once key login is confirmed, disable password authentication:

sudo nano /etc/ssh/sshd_config
sudo systemctl restart ssh

Create or edit ~/.ssh/config

on the remote machine:

Host jetson
    HostName 192.168.1.100
    User jetson
    IdentityFile ~/.ssh/jetson_orin
    IdentitiesOnly yes
    ServerAliveInterval 60
    ServerAliveCountMax 10
    TCPKeepAlive yes

Now you can connect with just: ssh jetson

XRDP and NoMachine both require X11. Ubuntu 24.04 defaults to Wayland — disable it:

sudo nano /etc/gdm3/custom.conf

Set the file content to:

[daemon]
WaylandEnable=false
AutomaticLoginEnable=true
AutomaticLogin=jetson

[security]

[xdmcp]

[chooser]

[debug]
sudo nano /etc/environment

Add these lines:

QT_QPA_PLATFORM=xcb
GDK_BACKEND=x11
XDG_SESSION_TYPE=x11

Without a physical monitor, the Tegra GPU creates a minimal 640×480 framebuffer. The dummy Xorg driver creates a proper 1920×1080 virtual display that NoMachine can use as a physical desktop target.

sudo apt install xserver-xorg-video-dummy -y

sudo mkdir -p /etc/X11/xorg.conf.d/

sudo tee /etc/X11/xorg.conf.d/30-tegra-headless.conf << 'EOF'
Section "Device"
    Identifier  "Tegra"
    Driver      "nvidia"
    Option      "AllowEmptyInitialConfiguration" "true"
    Option      "UseDisplayDevice" "none"
EndSection

Section "Monitor"
    Identifier  "Monitor0"
    HorizSync   28.0-80.0
    VertRefresh 48.0-75.0
    Modeline    "1920x1080" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
EndSection

Section "Screen"
    Identifier  "Screen0"
    Device      "Tegra"
    Monitor     "Monitor0"
    DefaultDepth 24
    SubSection "Display"
        Depth    24
        Virtual  1920 1080
    EndSubSection
EndSection
EOF

These settings prevent the remote session from being interrupted:

gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
gsettings set org.gnome.desktop.session idle-delay 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power idle-dim false
gsettings set org.gnome.settings-daemon.plugins.power power-button-action 'nothing'

NoMachine creates its own virtual X server and launches the desktop session independently. GDM (the GNOME Display Manager) is not needed and would conflict.

sudo systemctl set-default multi-user.target

sudo systemctl stop gdm 2>/dev/null || true


systemctl get-default

XFCE4 is the desktop environment that runs inside the NoMachine virtual display. It does not require GPU compositor support, making it fully compatible with virtual displays.

sudo apt install xfce4 xfce4-goodies xfce4-terminal -y

Configure it as the session to launch:

cat > ~/.xsession << 'EOF'
#!/bin/bash
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
exec startxfce4
EOF
chmod +x ~/.xsession

Always download the latest ARM64 DEB from the official page:

[https://downloads.nomachine.com/download/?id=30&platform=linux&distro=arm]

cd ~/Downloads

wget "https://web9001.nomachine.com/download/9.7/Arm/nomachine_9.7.3_1_arm64.deb"

sudo dpkg -i nomachine_9.7.3_1_arm64.deb
sudo apt --fix-broken install -y


sudo /usr/NX/bin/nxserver --status
sudo nano /usr/NX/etc/node.cfg

Search for DefaultDesktopCommand

and VirtualDesktopCommand

— add or uncomment:

DefaultDesktopCommand /usr/bin/startxfce4
VirtualDesktopCommand /usr/bin/startxfce4
DisplayGeometry 1920x1080
AllowDesktopResize 1
sudo /usr/NX/bin/nxserver --restart
sudo /usr/NX/bin/nxserver --status
sudo tee /etc/systemd/system/nomachine-headless.service << 'EOF'
[Unit]
Description=NoMachine Headless Server
After=network.target NetworkManager.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/NX/bin/nxserver --restart
ExecStop=/usr/NX/bin/nxserver --stop

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable nomachine-headless
sudo systemctl start nomachine-headless

Note:UFW is not installed by default in JetPack 7.2 on Ubuntu 24.04.

sudo apt install ufw -y

Ubuntu 24.04 with kernel 6.8 uses nftables as the backend, but UFW expects iptables-legacy. Without this fix, sudo ufw enable

will produce errors like RULE_APPEND failed (No such file or directory)

.

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

sudo iptables --version
sudo ufw default deny incoming
sudo ufw default allow outgoing

sudo ufw allow 22/tcp    comment "SSH"
sudo ufw allow 4000/tcp  comment "NoMachine NX"


sudo ufw enable

sudo ufw status numbered

If UFW continues to fail even after the iptables-legacy fix, use nftables directly — it is the native firewall on Ubuntu 24.04:

sudo apt install nftables -y

sudo tee /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        ct state established,related accept
        iif "lo" accept
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept
        tcp dport 22   accept comment "SSH"
        tcp dport 4000 accept comment "NoMachine"
    }
    chain forward { type filter hook forward priority 0; policy accept; }
    chain output  { type filter hook output  priority 0; policy accept; }
}
EOF

sudo systemctl enable nftables
sudo systemctl start nftables
sudo nft list ruleset
sudo reboot

Disconnect the physical monitor and keyboard. After approximately 30 seconds, from the remote host:

ping 192.168.1.100

ssh jetson

nc -zv 192.168.1.100 4000

Test-NetConnection -ComputerName 192.168.1.100 -Port 4000

If all three pass, the Jetson is running fully headless.

192.168.1.100

→ Port: 4000

In JetPack 7.2, the CUDA compiler (nvcc

) is installed but not in the default PATH. Add it:

sudo apt install nvidia-cuda-dev -y

echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

nvcc --version

Run this block after a clean reboot to confirm the headless setup is complete:

echo "=== Headless Mode Verification ==="

echo -n "Network (static IP): "
hostname -I | grep -q "192.168.1.100" && echo "OK" || echo "FAIL"

echo -n "SSH server: "
systemctl is-active ssh

echo -n "Boot target (no GDM): "
systemctl get-default

echo -n "GDM status: "
systemctl is-active gdm 2>/dev/null || echo "inactive (correct)"

echo -n "NoMachine port 4000: "
sudo ss -tlnp | grep -q ":4000" && echo "listening" || echo "NOT listening"

echo -n "XFCE4 installed: "
which startxfce4 && echo "OK" || echo "NOT FOUND"

echo -n "~/.xsession → XFCE4: "
grep -q "startxfce4" ~/.xsession && echo "OK" || echo "NOT configured"

echo -n "Wayland disabled: "
grep -q "WaylandEnable=false" /etc/gdm3/custom.conf && echo "OK" || echo "NOT disabled"

echo -n "Xorg dummy driver: "
test -f /etc/X11/xorg.conf.d/30-tegra-headless.conf && echo "OK" || echo "NOT configured"

echo -n "CUDA PATH: "
nvcc --version 2>/dev/null | grep -o "release [0-9.]*" || echo "NOT in PATH — run: source ~/.bashrc"

echo "=== Done ==="

Expected output (all lines should show OK or the correct active status):

=== Headless Mode Verification ===
Network (static IP): OK
SSH server: active
Boot target (no GDM): multi-user.target
GDM status: inactive (correct)
NoMachine port 4000: listening
XFCE4 installed: /usr/bin/startxfce4  OK
~/.xsession → XFCE4: OK
Wayland disabled: OK
Xorg dummy driver: OK
CUDA PATH: release 13.2,
=== Done ===

This typically means gnome-shell was launched instead of XFCE4.

cat ~/.xsession

grep -E "DefaultDesktop|VirtualDesktop" /usr/NX/etc/node.cfg

cat > ~/.xsession << 'EOF'
#!/bin/bash
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
exec startxfce4
EOF
chmod +x ~/.xsession
sudo /usr/NX/bin/nxserver --restart

Then disconnect and reconnect from the NoMachine client, choosing "Create a new virtual desktop".

The SSH port is open but the connection times out. SSH may be down, or UFW may be blocking it.

sudo systemctl status ssh
sudo systemctl start ssh
sudo ufw status
sudo ufw allow 22/tcp

The Ethernet connection may require a user session to activate. Verify the connection.permissions

fix:

nmcli connection show "Wired connection 1" | grep permissions

sudo nmcli connection modify "Wired connection 1" connection.permissions ""
sudo nmcli connection up "Wired connection 1"
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo ufw disable
sudo ufw reset
sudo ufw enable
source ~/.bashrc

/usr/local/cuda/bin/nvcc --version

ls /usr/local/cuda/bin/nvcc
Step Action Result
1–3 System update + packages + hostname Base system ready
4 Static IP + connection.permissions=""
Network up without login
5 SSH + key auth Secure remote terminal
6 Disable Wayland + dummy Xorg driver X11 display at 1920×1080
7
multi-user.target (no GDM)
NoMachine owns the display
8 XFCE4 + ~/.xsession
Desktop environment ready
9 NoMachine server + node.cfg
Virtual GUI accessible
10 UFW + iptables-legacy fix Firewall active
11 Reboot test without monitor Fully headless
12 NoMachine client → virtual desktop Full GUI via NX
13 CUDA PATH
nvcc accessible

After completing all steps, the Jetson AGX Orin operates entirely without a physical display. SSH provides terminal access and NoMachine provides full XFCE4 desktop access — both available immediately after any reboot, without any physical interaction with the device.

Platform: NVIDIA Jetson AGX Orin Developer Kit 64GB · JetPack 7.2 (L4T r39.2) · Ubuntu 24.04 LTS · NoMachine 9.7.3

── more in #developer-tools 4 stories · sorted by recency
── more on @nvidia 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/headless-mode-on-nvi…] indexed:0 read:11min 2026-06-27 ·