{"slug": "headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2", "title": "Headless Mode on NVIDIA Jetson AGX Orin 64GB with JetPack 7.2", "summary": "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.", "body_md": "**Tags:** `jetson`\n\n`jetpack-7.2`\n\n`headless`\n\n`nomachine`\n\n`ubuntu-24.04`\n\n`embedded-ai`\n\n`edge-ai`\n\nThis 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.\n\nWhy NoMachine only?\n\nJetPack 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.\n\n| Component | Value |\n|---|---|\n| Hardware | NVIDIA Jetson AGX Orin Developer Kit 64GB |\n| JetPack | 7.2-b187 |\n| L4T | r39.2 (Jetson Linux 39.2) |\n| OS | Ubuntu 24.04.4 LTS |\n| Kernel | 6.8.12-tegra |\n| CUDA | 13.2.1 |\n| Python | 3.12.3 |\n| NoMachine | 9.7.3 |\n| Remote host | Windows 11 (same LAN via Ethernet) |\n\n`192.168.1.100`\n\nas example)Connect a monitor and open a terminal (`Ctrl+Alt+T`\n\n).\n\n```\n# Update package lists and upgrade installed packages\n# DO NOT run dist-upgrade on Jetson — it breaks JetPack components\nsudo apt update && sudo apt upgrade -y\nsudo apt autoremove -y\nsudo apt install -y \\\n  net-tools curl wget htop tmux tree \\\n  git nano vim \\\n  build-essential \\\n  python3-pip python3-venv python3-dev pipx \\\n  software-properties-common \\\n  apt-transport-https ca-certificates gnupg \\\n  cmake ninja-build libopenblas-dev\n```\n\nInstall `jtop`\n\n, the Jetson-specific system monitor:\n\n```\n# Ubuntu 24.04 requires pipx for global Python tools\npipx install jetson-stats\npipx ensurepath\nsource ~/.bashrc\n\nsudo systemctl restart jtop 2>/dev/null || true\njtop --version\nsudo hostnamectl set-hostname jetson-orin\n\n# Update /etc/hosts to match\nsudo nano /etc/hosts\n# Find the line with 127.0.1.1 and change it to:\n# 127.0.1.1  jetson-orin\n```\n\nA static IP is required so SSH and NoMachine connections never break after reboots.\n\nCritical:The`connection.permissions \"\"`\n\nparameter 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.\n\n```\n# Find your Ethernet connection name\nnmcli connection show\nnmcli device status\n\n# Set a variable — replace with your actual connection name\nCONN=\"Wired connection 1\"\n\n# Apply static IP configuration\n# Replace values to match your network\nsudo nmcli connection modify \"$CONN\" \\\n  ipv4.method manual \\\n  ipv4.addresses \"192.168.1.100/24\" \\\n  ipv4.gateway \"192.168.1.1\" \\\n  ipv4.dns \"8.8.8.8,1.1.1.1\" \\\n  ipv4.ignore-auto-dns yes \\\n  connection.permissions \"\" \\\n  connection.autoconnect yes \\\n  connection.autoconnect-priority 100\n\n# Apply immediately\nsudo nmcli connection down \"$CONN\" && \\\n  sudo nmcli connection up \"$CONN\"\n\n# Confirm the IP\nhostname -I\n```\n\nDisable the network boot timeout service to prevent slow headless boots:\n\n```\nsudo systemctl disable NetworkManager-wait-online.service\nsudo systemctl mask NetworkManager-wait-online.service\nsudo apt install openssh-server -y\nsudo systemctl enable ssh\nsudo systemctl start ssh\nsudo systemctl status ssh\n```\n\nEdit `/etc/ssh/sshd_config`\n\n— back it up first:\n\n```\nsudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup\nsudo nano /etc/ssh/sshd_config\n```\n\nEnsure these directives are set (uncomment or add as needed):\n\n```\nPort 22\nPubkeyAuthentication yes\nPasswordAuthentication yes\nPermitRootLogin prohibit-password\nClientAliveInterval 60\nClientAliveCountMax 10\nTCPKeepAlive yes\nX11Forwarding yes\nMaxAuthTries 6\nsudo systemctl restart ssh\n```\n\nFrom the remote host (replace `192.168.1.100`\n\nwith your Jetson IP):\n\n```\n# Generate a key pair (if you don't have one)\nssh-keygen -t ed25519 -C \"remote-to-jetson\" -f ~/.ssh/jetson_orin\n\n# Deploy the public key to the Jetson\n# On Linux/macOS:\nssh-copy-id -i ~/.ssh/jetson_orin.pub jetson@192.168.1.100\n\n# On Windows PowerShell:\ntype \"$env:USERPROFILE\\.ssh\\jetson_orin.pub\" | `\n  ssh jetson@192.168.1.100 `\n  \"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys\"\n```\n\nOnce key login is confirmed, disable password authentication:\n\n```\nsudo nano /etc/ssh/sshd_config\n# Set: PasswordAuthentication no\nsudo systemctl restart ssh\n```\n\nCreate or edit `~/.ssh/config`\n\non the remote machine:\n\n```\nHost jetson\n    HostName 192.168.1.100\n    User jetson\n    IdentityFile ~/.ssh/jetson_orin\n    IdentitiesOnly yes\n    ServerAliveInterval 60\n    ServerAliveCountMax 10\n    TCPKeepAlive yes\n```\n\nNow you can connect with just: `ssh jetson`\n\nXRDP and NoMachine both require X11. Ubuntu 24.04 defaults to Wayland — disable it:\n\n```\nsudo nano /etc/gdm3/custom.conf\n```\n\nSet the file content to:\n\n```\n[daemon]\nWaylandEnable=false\nAutomaticLoginEnable=true\nAutomaticLogin=jetson\n\n[security]\n\n[xdmcp]\n\n[chooser]\n\n[debug]\nsudo nano /etc/environment\n```\n\nAdd these lines:\n\n```\nQT_QPA_PLATFORM=xcb\nGDK_BACKEND=x11\nXDG_SESSION_TYPE=x11\n```\n\nWithout 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.\n\n```\nsudo apt install xserver-xorg-video-dummy -y\n\nsudo mkdir -p /etc/X11/xorg.conf.d/\n\nsudo tee /etc/X11/xorg.conf.d/30-tegra-headless.conf << 'EOF'\nSection \"Device\"\n    Identifier  \"Tegra\"\n    Driver      \"nvidia\"\n    Option      \"AllowEmptyInitialConfiguration\" \"true\"\n    Option      \"UseDisplayDevice\" \"none\"\nEndSection\n\nSection \"Monitor\"\n    Identifier  \"Monitor0\"\n    HorizSync   28.0-80.0\n    VertRefresh 48.0-75.0\n    Modeline    \"1920x1080\" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync\nEndSection\n\nSection \"Screen\"\n    Identifier  \"Screen0\"\n    Device      \"Tegra\"\n    Monitor     \"Monitor0\"\n    DefaultDepth 24\n    SubSection \"Display\"\n        Depth    24\n        Virtual  1920 1080\n    EndSubSection\nEndSection\nEOF\n```\n\nThese settings prevent the remote session from being interrupted:\n\n```\n# Run these as your user (not root)\ngsettings set org.gnome.desktop.screensaver lock-enabled false\ngsettings set org.gnome.desktop.screensaver idle-activation-enabled false\ngsettings set org.gnome.desktop.session idle-delay 0\ngsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0\ngsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 0\ngsettings set org.gnome.settings-daemon.plugins.power idle-dim false\ngsettings set org.gnome.settings-daemon.plugins.power power-button-action 'nothing'\n```\n\nNoMachine creates its own virtual X server and launches the desktop session independently. GDM (the GNOME Display Manager) is not needed and would conflict.\n\n```\n# Set boot to multi-user (CLI only, no display manager)\nsudo systemctl set-default multi-user.target\n\n# Ensure GDM does not start\nsudo systemctl stop gdm 2>/dev/null || true\n\n# Do NOT run: sudo systemctl disable gdm\n# On Ubuntu 24.04, gdm is statically enabled via graphical.target\n# Switching to multi-user.target is the correct method to prevent it from starting\n\n# Verify\nsystemctl get-default\n# Expected: multi-user.target\n```\n\nXFCE4 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.\n\n```\nsudo apt install xfce4 xfce4-goodies xfce4-terminal -y\n```\n\nConfigure it as the session to launch:\n\n``` bash\ncat > ~/.xsession << 'EOF'\n#!/bin/bash\nunset DBUS_SESSION_BUS_ADDRESS\nunset XDG_RUNTIME_DIR\nexec startxfce4\nEOF\nchmod +x ~/.xsession\n```\n\nAlways download the latest ARM64 DEB from the official page:\n\n[https://downloads.nomachine.com/download/?id=30&platform=linux&distro=arm]\n\n```\ncd ~/Downloads\n\n# Check the current version at the URL above and adjust the filename\nwget \"https://web9001.nomachine.com/download/9.7/Arm/nomachine_9.7.3_1_arm64.deb\"\n\nsudo dpkg -i nomachine_9.7.3_1_arm64.deb\nsudo apt --fix-broken install -y\n\n# The installation output will show warnings about CUPS (printer support)\n# These are expected and harmless — NoMachine installs correctly\n\n# Verify the server started\nsudo /usr/NX/bin/nxserver --status\n# Expected: Running server at port: 4000\n# Find and edit node.cfg\nsudo nano /usr/NX/etc/node.cfg\n```\n\nSearch for `DefaultDesktopCommand`\n\nand `VirtualDesktopCommand`\n\n— add or uncomment:\n\n```\nDefaultDesktopCommand /usr/bin/startxfce4\nVirtualDesktopCommand /usr/bin/startxfce4\nDisplayGeometry 1920x1080\nAllowDesktopResize 1\n# Restart NoMachine to apply changes\nsudo /usr/NX/bin/nxserver --restart\nsudo /usr/NX/bin/nxserver --status\nsudo tee /etc/systemd/system/nomachine-headless.service << 'EOF'\n[Unit]\nDescription=NoMachine Headless Server\nAfter=network.target NetworkManager.service\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/NX/bin/nxserver --restart\nExecStop=/usr/NX/bin/nxserver --stop\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl enable nomachine-headless\nsudo systemctl start nomachine-headless\n```\n\nNote:UFW is not installed by default in JetPack 7.2 on Ubuntu 24.04.\n\n```\nsudo apt install ufw -y\n```\n\nUbuntu 24.04 with kernel 6.8 uses nftables as the backend, but UFW expects iptables-legacy. Without this fix, `sudo ufw enable`\n\nwill produce errors like `RULE_APPEND failed (No such file or directory)`\n\n.\n\n```\n# Switch to iptables-legacy\nsudo update-alternatives --set iptables /usr/sbin/iptables-legacy\nsudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy\n\n# Verify\nsudo iptables --version\n# Expected: iptables v1.8.x (legacy)\nsudo ufw default deny incoming\nsudo ufw default allow outgoing\n\nsudo ufw allow 22/tcp    comment \"SSH\"\nsudo ufw allow 4000/tcp  comment \"NoMachine NX\"\n\n# Add additional ports as needed for your stack:\n# sudo ufw allow 3389/tcp  comment \"XRDP\"\n# sudo ufw allow 11434/tcp comment \"Ollama\"\n# sudo ufw allow 8000/tcp  comment \"vLLM\"\n# sudo ufw allow 3000/tcp  comment \"Open WebUI\"\n# sudo ufw allow 8888/tcp  comment \"Jupyter\"\n\nsudo ufw enable\n# Type 'y' when prompted\n\nsudo ufw status numbered\n```\n\nIf UFW continues to fail even after the iptables-legacy fix, use nftables directly — it is the native firewall on Ubuntu 24.04:\n\n``` bash\nsudo apt install nftables -y\n\nsudo tee /etc/nftables.conf << 'EOF'\n#!/usr/sbin/nft -f\nflush ruleset\n\ntable inet filter {\n    chain input {\n        type filter hook input priority 0; policy drop;\n        ct state established,related accept\n        iif \"lo\" accept\n        ip protocol icmp accept\n        ip6 nexthdr icmpv6 accept\n        tcp dport 22   accept comment \"SSH\"\n        tcp dport 4000 accept comment \"NoMachine\"\n        # Add more ports here as needed\n    }\n    chain forward { type filter hook forward priority 0; policy accept; }\n    chain output  { type filter hook output  priority 0; policy accept; }\n}\nEOF\n\nsudo systemctl enable nftables\nsudo systemctl start nftables\nsudo nft list ruleset\nsudo reboot\n```\n\nDisconnect the physical monitor and keyboard. After approximately 30 seconds, from the remote host:\n\n```\n# Test 1: Network is up\nping 192.168.1.100\n\n# Test 2: SSH is reachable\nssh jetson\n\n# Test 3: NoMachine port is open\n# Linux/macOS:\nnc -zv 192.168.1.100 4000\n\n# Windows PowerShell:\nTest-NetConnection -ComputerName 192.168.1.100 -Port 4000\n```\n\nIf all three pass, the Jetson is running fully headless.\n\n`192.168.1.100`\n\n→ Port: `4000`\n\nIn JetPack 7.2, the CUDA compiler (`nvcc`\n\n) is installed but not in the default PATH. Add it:\n\n```\n# Install CUDA development tools if not present\nsudo apt install nvidia-cuda-dev -y\n\n# Add CUDA to PATH permanently\necho 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc\necho 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc\nsource ~/.bashrc\n\n# Verify\nnvcc --version\n# Expected: Cuda compilation tools, release 13.2, ...\n```\n\nRun this block after a clean reboot to confirm the headless setup is complete:\n\n```\necho \"=== Headless Mode Verification ===\"\n\necho -n \"Network (static IP): \"\nhostname -I | grep -q \"192.168.1.100\" && echo \"OK\" || echo \"FAIL\"\n\necho -n \"SSH server: \"\nsystemctl is-active ssh\n\necho -n \"Boot target (no GDM): \"\nsystemctl get-default\n\necho -n \"GDM status: \"\nsystemctl is-active gdm 2>/dev/null || echo \"inactive (correct)\"\n\necho -n \"NoMachine port 4000: \"\nsudo ss -tlnp | grep -q \":4000\" && echo \"listening\" || echo \"NOT listening\"\n\necho -n \"XFCE4 installed: \"\nwhich startxfce4 && echo \"OK\" || echo \"NOT FOUND\"\n\necho -n \"~/.xsession → XFCE4: \"\ngrep -q \"startxfce4\" ~/.xsession && echo \"OK\" || echo \"NOT configured\"\n\necho -n \"Wayland disabled: \"\ngrep -q \"WaylandEnable=false\" /etc/gdm3/custom.conf && echo \"OK\" || echo \"NOT disabled\"\n\necho -n \"Xorg dummy driver: \"\ntest -f /etc/X11/xorg.conf.d/30-tegra-headless.conf && echo \"OK\" || echo \"NOT configured\"\n\necho -n \"CUDA PATH: \"\nnvcc --version 2>/dev/null | grep -o \"release [0-9.]*\" || echo \"NOT in PATH — run: source ~/.bashrc\"\n\necho \"=== Done ===\"\n```\n\nExpected output (all lines should show OK or the correct active status):\n\n```\n=== Headless Mode Verification ===\nNetwork (static IP): OK\nSSH server: active\nBoot target (no GDM): multi-user.target\nGDM status: inactive (correct)\nNoMachine port 4000: listening\nXFCE4 installed: /usr/bin/startxfce4  OK\n~/.xsession → XFCE4: OK\nWayland disabled: OK\nXorg dummy driver: OK\nCUDA PATH: release 13.2,\n=== Done ===\n```\n\nThis typically means gnome-shell was launched instead of XFCE4.\n\n```\n# Check ~/.xsession\ncat ~/.xsession\n# Must contain: exec startxfce4\n\n# Check node.cfg\ngrep -E \"DefaultDesktop|VirtualDesktop\" /usr/NX/etc/node.cfg\n# Must point to /usr/bin/startxfce4\n\n# Fix and restart\ncat > ~/.xsession << 'EOF'\n#!/bin/bash\nunset DBUS_SESSION_BUS_ADDRESS\nunset XDG_RUNTIME_DIR\nexec startxfce4\nEOF\nchmod +x ~/.xsession\nsudo /usr/NX/bin/nxserver --restart\n```\n\nThen disconnect and reconnect from the NoMachine client, choosing **\"Create a new virtual desktop\"**.\n\nThe SSH port is open but the connection times out. SSH may be down, or UFW may be blocking it.\n\n```\n# Via a physical connection or recovery\nsudo systemctl status ssh\nsudo systemctl start ssh\nsudo ufw status\nsudo ufw allow 22/tcp\n```\n\nThe Ethernet connection may require a user session to activate. Verify the `connection.permissions`\n\nfix:\n\n```\nnmcli connection show \"Wired connection 1\" | grep permissions\n# Must show: connection.permissions: (empty)\n\n# If not empty, reapply\nsudo nmcli connection modify \"Wired connection 1\" connection.permissions \"\"\nsudo nmcli connection up \"Wired connection 1\"\nsudo update-alternatives --set iptables /usr/sbin/iptables-legacy\nsudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy\nsudo ufw disable\nsudo ufw reset\nsudo ufw enable\n# The PATH change requires sourcing the profile\nsource ~/.bashrc\n\n# Or specify the full path directly\n/usr/local/cuda/bin/nvcc --version\n\n# Verify the binary exists\nls /usr/local/cuda/bin/nvcc\n```\n\n| Step | Action | Result |\n|---|---|---|\n| 1–3 | System update + packages + hostname | Base system ready |\n| 4 | Static IP + `connection.permissions=\"\"`\n|\nNetwork up without login |\n| 5 | SSH + key auth | Secure remote terminal |\n| 6 | Disable Wayland + dummy Xorg driver | X11 display at 1920×1080 |\n| 7 |\n`multi-user.target` (no GDM) |\nNoMachine owns the display |\n| 8 | XFCE4 + `~/.xsession`\n|\nDesktop environment ready |\n| 9 | NoMachine server + `node.cfg`\n|\nVirtual GUI accessible |\n| 10 | UFW + iptables-legacy fix | Firewall active |\n| 11 | Reboot test without monitor | Fully headless |\n| 12 | NoMachine client → virtual desktop | Full GUI via NX |\n| 13 | CUDA PATH |\n`nvcc` accessible |\n\nAfter 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.\n\n*Platform: NVIDIA Jetson AGX Orin Developer Kit 64GB · JetPack 7.2 (L4T r39.2) · Ubuntu 24.04 LTS · NoMachine 9.7.3*", "url": "https://wpnews.pro/news/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2", "canonical_source": "https://dev.to/vonusma/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-72-448a", "published_at": "2026-06-27 04:08:35+00:00", "updated_at": "2026-06-27 04:33:53.600017+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "machine-learning"], "entities": ["NVIDIA", "Jetson AGX Orin", "JetPack 7.2", "NoMachine", "Ubuntu 24.04", "CUDA", "XFCE4", "GNOME"], "alternates": {"html": "https://wpnews.pro/news/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2", "markdown": "https://wpnews.pro/news/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2.md", "text": "https://wpnews.pro/news/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2.txt", "jsonld": "https://wpnews.pro/news/headless-mode-on-nvidia-jetson-agx-orin-64gb-with-jetpack-7-2.jsonld"}}