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

> Source: <https://dev.to/vonusma/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-72-448a>
> Published: 2026-06-27 04:08:35+00:00

**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`

).

```
# Update package lists and upgrade installed packages
# DO NOT run dist-upgrade on Jetson — it breaks JetPack components
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:

```
# Ubuntu 24.04 requires pipx for global Python tools
pipx install jetson-stats
pipx ensurepath
source ~/.bashrc

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

# Update /etc/hosts to match
sudo nano /etc/hosts
# Find the line with 127.0.1.1 and change it to:
# 127.0.1.1  jetson-orin
```

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

Critical:The`connection.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.

```
# Find your Ethernet connection name
nmcli connection show
nmcli device status

# Set a variable — replace with your actual connection name
CONN="Wired connection 1"

# Apply static IP configuration
# Replace values to match your network
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

# Apply immediately
sudo nmcli connection down "$CONN" && \
  sudo nmcli connection up "$CONN"

# Confirm the IP
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):

```
# Generate a key pair (if you don't have one)
ssh-keygen -t ed25519 -C "remote-to-jetson" -f ~/.ssh/jetson_orin

# Deploy the public key to the Jetson
# On Linux/macOS:
ssh-copy-id -i ~/.ssh/jetson_orin.pub jetson@192.168.1.100

# On Windows PowerShell:
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
# Set: PasswordAuthentication no
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:

```
# Run these as your user (not root)
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.

```
# Set boot to multi-user (CLI only, no display manager)
sudo systemctl set-default multi-user.target

# Ensure GDM does not start
sudo systemctl stop gdm 2>/dev/null || true

# Do NOT run: sudo systemctl disable gdm
# On Ubuntu 24.04, gdm is statically enabled via graphical.target
# Switching to multi-user.target is the correct method to prevent it from starting

# Verify
systemctl get-default
# Expected: multi-user.target
```

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:

``` bash
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

# Check the current version at the URL above and adjust the filename
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

# The installation output will show warnings about CUPS (printer support)
# These are expected and harmless — NoMachine installs correctly

# Verify the server started
sudo /usr/NX/bin/nxserver --status
# Expected: Running server at port: 4000
# Find and edit node.cfg
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
# Restart NoMachine to apply changes
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)`

.

```
# Switch to iptables-legacy
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

# Verify
sudo iptables --version
# Expected: iptables v1.8.x (legacy)
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"

# Add additional ports as needed for your stack:
# sudo ufw allow 3389/tcp  comment "XRDP"
# sudo ufw allow 11434/tcp comment "Ollama"
# sudo ufw allow 8000/tcp  comment "vLLM"
# sudo ufw allow 3000/tcp  comment "Open WebUI"
# sudo ufw allow 8888/tcp  comment "Jupyter"

sudo ufw enable
# Type 'y' when prompted

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:

``` bash
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"
        # Add more ports here as needed
    }
    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:

```
# Test 1: Network is up
ping 192.168.1.100

# Test 2: SSH is reachable
ssh jetson

# Test 3: NoMachine port is open
# Linux/macOS:
nc -zv 192.168.1.100 4000

# Windows PowerShell:
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:

```
# Install CUDA development tools if not present
sudo apt install nvidia-cuda-dev -y

# Add CUDA to PATH permanently
echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

# Verify
nvcc --version
# Expected: Cuda compilation tools, release 13.2, ...
```

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.

```
# Check ~/.xsession
cat ~/.xsession
# Must contain: exec startxfce4

# Check node.cfg
grep -E "DefaultDesktop|VirtualDesktop" /usr/NX/etc/node.cfg
# Must point to /usr/bin/startxfce4

# Fix and restart
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.

```
# Via a physical connection or recovery
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
# Must show: connection.permissions: (empty)

# If not empty, reapply
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
# The PATH change requires sourcing the profile
source ~/.bashrc

# Or specify the full path directly
/usr/local/cuda/bin/nvcc --version

# Verify the binary exists
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*
