惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
O
OpenAI News
美团技术团队
月光博客
月光博客
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
Webroot Blog
Webroot Blog
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Tenable Blog
S
Security Affairs
博客园_首页
S
Schneier on Security
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
Spread Privacy
Spread Privacy
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
Vercel News
Vercel News
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 最新话题
D
DataBreaches.Net
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - Franky
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Check Point Blog
H
Hacker News: Front Page

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Headless Mode on NVIDIA Jetson AGX Orin 64GB with JetPack 7.2
Sergio Andres Usma · 2026-06-27 · via DEV Community

Tags: jetson jetpack-7.2 headless nomachine ubuntu-24.04 embedded-ai edge-ai


Overview

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.


Tested Environment

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)

Prerequisites

  • Jetson AGX Orin with JetPack 7.2 flashed and first-boot wizard completed
  • Static IP assigned or known (this guide uses 192.168.1.100 as example)
  • A monitor and keyboard connected for this setup session only — they will not be needed after
  • OpenSSH client installed on the remote host (Windows: built-in; Linux/macOS: native)
  • NoMachine client installed on the remote host: https://nomachine.com/download

Step 1 — System Update

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


Step 2 — Install Essential Packages

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


Step 3 — Set Hostname

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


Step 4 — Static IP via NetworkManager

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


Step 5 — SSH Server

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

SSH Key-Based Authentication

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

SSH Config on Remote Host (Optional but Recommended)

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


Step 6 — Headless Display Configuration

6.1 Disable Wayland in GDM3

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]

6.2 System-Wide X11 Environment Variables

sudo nano /etc/environment

Add these lines:

QT_QPA_PLATFORM=xcb
GDK_BACKEND=x11
XDG_SESSION_TYPE=x11

6.3 Xorg Dummy Display Driver

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

6.4 Disable Screensaver and Power Management

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'


Step 7 — Boot Target and Display Manager

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


Step 8 — Install XFCE4

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


Step 9 — Install NoMachine Server

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

Configure NoMachine for XFCE4

# 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

Enable NoMachine Autostart

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


Step 10 — Firewall

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

sudo apt install ufw -y

Fix for UFW + Kernel 6.8 (nftables conflict)

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)

Apply Firewall Rules

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

Alternative: nftables (if UFW issues persist)

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"
        # 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


Step 11 — First Reboot Test

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.


Step 12 — Connect via NoMachine

  1. Open NoMachine on the remote host
  2. Click Add → Protocol: NX → Host: 192.168.1.100 → Port: 4000
  3. Authentication: Password
  4. Click Connect → accept the host fingerprint
  5. Enter your Jetson username and password
  6. When prompted for the session type → select "Create a new virtual desktop"
  7. XFCE4 desktop loads with full mouse, keyboard, and 1920×1080 resolution

Step 13 — CUDA PATH Fix

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, ...


Verification Checklist

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 ===


Troubleshooting

NoMachine connects but shows a black screen

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".


SSH unreachable after reboot (but ping works)

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


Network not up after headless reboot

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"


UFW enable fails with RULE_APPEND errors (kernel 6.8)

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


nvcc not found after installing nvidia-cuda-dev

# 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


Summary

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