Why I Started Using nmap More Regularly
When I first took over managing the network for a 50-person office and a small datacenter, I kept getting blindsided by strange ports that would suddenly appear on servers. One time, the dev team deployed an internal test service and forgot to shut it down — the service was bound to 0.0.0.0, exposing it to the internet. Fortunately, I caught it early before anything bad happened.
From that point on, nmap became a permanent fixture in my weekly checklist. Not for hacking — but to know exactly what my servers are exposing to the outside world. Instead of manually checking each service, a single nmap command can scan an entire subnet in minutes.
Installing nmap on Linux
On most popular distros, nmap is available in the official repository:
# Ubuntu / Debian
sudo apt update && sudo apt install nmap -y
# CentOS / RHEL / Rocky Linux
sudo dnf install nmap -y
# Arch Linux
sudo pacman -S nmap
Check the version after installation:
nmap --version
# Nmap version 7.94 ( https://nmap.org )
An important note: scanning your own systems with nmap is completely legitimate. Scanning someone else’s IP without permission is illegal — in the US you can be prosecuted under the Computer Fraud and Abuse Act, and similar cybercrime laws exist in most countries. I only use nmap to audit infrastructure that I’m authorized to manage.
Detailed Scanning Techniques and Configuration
1. Basic Port Scanning — See What Your Server Is Exposing
Start simple — see which ports the server is listening on:
# Scan the 1000 most common ports (default)
nmap 192.168.1.100
# Scan all 65535 ports — slower but more comprehensive
nmap -p- 192.168.1.100
# Scan a specific port range
nmap -p 22,80,443,3306,6379 192.168.1.100
Sample output:
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
3306/tcp open mysql
Seeing MySQL (3306) open? If this server is public-facing, that’s a serious problem. I’ve actually encountered this — a developer left the default 0.0.0.0 binding during testing and forgot to change it back.
2. Service Version Detection — Critical for Vulnerability Assessment
An open port is just the surface. What matters more is the version — to cross-reference against the CVE database:
# -sV: detect service version
nmap -sV 192.168.1.100
# Combine with -sC (default scripts) for additional information
nmap -sV -sC 192.168.1.100
Much more specific results:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.24.0 (Ubuntu)
443/tcp open ssl/http nginx 1.24.0
OpenSSH 8.9, nginx 1.24 — head to NVD (nvd.nist.gov) right away to check for any active CVEs. This step takes 2 minutes but regularly catches critical vulnerabilities before someone else exploits them.
3. Scanning the Entire Subnet — Internal Network Audit
This is the command I run every Monday morning to check for any network changes:
# Ping scan — list all online hosts in the subnet
nmap -sn 192.168.1.0/24
# Combine with a quick port scan
nmap -sn -oG - 192.168.1.0/24 | grep 'Status: Up' | awk '{print $2}' > live_hosts.txt
nmap -iL live_hosts.txt -p 22,80,443,3306,5432,6379,27017 -oN scan_result.txt
Save the results to a file, then diff it against last week’s output. Any new IPs or unexpected ports that suddenly appear are usually services someone deployed without telling anyone.
4. OS Detection and Fingerprinting
# -O: OS detection (requires root)
sudo nmap -O 192.168.1.100
# Aggressive scan — combines multiple techniques
sudo nmap -A 192.168.1.100
The -A option combines four things in one run: OS detection, version detection, script scanning, and traceroute. Use it when you need to thoroughly audit a specific host. But avoid running it regularly on production — it generates significant traffic and leaves a clear trace in logs.
5. Stealth Scan — Lower-Noise Scanning
# SYN scan (half-open) — fast, minimal logging on target
sudo nmap -sS 192.168.1.100
# UDP scan — many critical services use UDP (DNS, SNMP, NTP)
sudo nmap -sU -p 53,123,161 192.168.1.100
UDP scans often get overlooked because they’re slower than TCP. Don’t skip them. I once discovered SNMP (port 161 UDP) enabled with the default community string “public” on a network device — which meant anyone could read the complete configuration of every switch and router on the internal network without any authentication.
6. Using NSE Scripts — In-Depth Security Checks
The NSE (Nmap Scripting Engine) ships with over 600 scripts — from vulnerability checks to detailed information enumeration:
# Check for common vulnerabilities
nmap --script vuln 192.168.1.100
# Check SSH: brute force protection, encryption algorithms
nmap --script ssh-auth-methods,ssh2-enum-algos -p 22 192.168.1.100
# Check HTTP security headers
nmap --script http-security-headers -p 80,443 192.168.1.100
# Check SSL/TLS configuration
nmap --script ssl-enum-ciphers -p 443 192.168.1.100
The ssl-enum-ciphers script is especially useful — it lists all supported cipher suites and grades each one (A/B/C/F). I use this to verify configuration after every TLS update on nginx.
Analyzing Results and Setting Up Regular Monitoring
Saving Scan Results for Comparison Over Time
Nmap supports multiple output formats. XML for scripted parsing, plaintext for direct reading:
# XML output — for parsing or importing into other tools
nmap -sV -oX scan_$(date +%Y%m%d).xml 192.168.1.0/24
# Output all formats at once
nmap -sV -oA scan_$(date +%Y%m%d) 192.168.1.0/24
# Creates: scan_YYYYMMDD.nmap, scan_YYYYMMDD.xml, scan_YYYYMMDD.gnmap
# Compare two scans to detect changes
diff scan_20240101.nmap scan_20240108.nmap
Simple Automation Script for Weekly Audits
#!/bin/bash
# /opt/scripts/weekly_nmap_audit.sh
SUBNET="192.168.1.0/24"
OUTDIR="/var/log/nmap-audit"
DATE=$(date +%Y%m%d_%H%M)
mkdir -p $OUTDIR
# Scan critical ports across the entire subnet
nmap -sV -p 22,23,80,443,3306,5432,6379,27017,11211,9200 \
--open -oN "$OUTDIR/scan_$DATE.txt" $SUBNET
# Send alert if dangerous ports are detected (23=telnet, 11211=memcached)
if grep -E '^[0-9]+.*23/tcp|11211/tcp' "$OUTDIR/scan_$DATE.txt"; then
echo "WARNING: Dangerous port detected!" | mail -s "[ALERT] nmap audit" [email protected]
fi
Add to crontab to run automatically:
crontab -e
# Run every Monday at 7 AM
0 7 * * 1 /opt/scripts/weekly_nmap_audit.sh
What to Watch For in Scan Results
- Port 23 (Telnet) — shut this down immediately if you see it; Telnet transmits everything unencrypted, including passwords
- Port 3306/5432 (MySQL/PostgreSQL) open to the internet — databases should never be directly public-facing
- Port 6379 (Redis) without authentication — I once handled a case where Redis was compromised to run a cryptominer, with the server CPU pegged at 100% for a full week before we tracked down the root cause
- Port 9200 (Elasticsearch) open without auth — thousands of data breaches have occurred for exactly this reason, many involving large-scale customer data exposure
- Port 11211 (Memcached) — commonly exploited for DDoS amplification attacks, with an amplification factor that can reach 51,000x
After nearly three years of using nmap to audit systems, I’ve realized the real value isn’t in the first scan. It’s in running it regularly and comparing results over time. Infrastructure changes constantly — new services get deployed, updates open additional ports, firewall rules get reset after reboots. Regular scanning lets you catch these changes early, before someone else finds them first.

