Netcat Cheatsheet

Client Mode

Use this Netcat reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Connecting

nc example.com 80
nc -v -n 10.0.0.5 8080
nc -4 example.com 443            # force IPv4
nc -6 example.com 443            # force IPv6
nc -s 10.0.0.7 example.com 80    # pick the source address
nc -p 12345 example.com 80       # pick the source port
FlagEffect
-4 / -6Force an address family, useful when a host has both
-s addrBind a specific local address, for multi-homed routing tests
-p portBind a specific local port. Cannot combine with -l
-nNo DNS resolution
-w secsTimeout for the connect and for the final read
-vReport success and failure

-p needs a free port, and below 1024 it needs root. It matters when a firewall rule keys on the source port, which is otherwise the main reason to care.

Timeouts, and why a hang is data

nc -v -w 3 10.0.0.5 443

What -w does depends on the phase, which is the part people miss:

- During the connect it caps how long to wait for the SYN-ACK. - After the peer closes, it caps how long to keep reading. - It does not cap an idle established connection. A server that accepts and then says nothing keeps netcat open forever.

For a hard ceiling, wrap it:

timeout 5 nc -v 10.0.0.5 443

Diagnose from how it fails, which distinguishes the two failure modes people usually conflate:

BehaviorAlmost certainly
Instant Connection refusedReached the host, nothing listening. A RST came back
Hangs until -w expiresSilently dropped. A firewall DROP rule, or wrong route
No route to hostLocal routing table or ARP failure
Connection reset by peer mid-sessionThe app closed hard, or a middlebox killed it
Connects then immediately closesTLS port getting plaintext, or an allowlist rejecting you

A refusal is good news. It proves IP reachability and that the host is up.

Sending a request non-interactively

Piping into netcat is the normal way to script it.

# Minimal HTTP/1.0 request
printf 'GET / HTTP/1.0\r\n\r\n' | nc example.com 80

# HTTP/1.1 needs a Host header and an explicit close
printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' \
  | nc example.com 80

# From a file
nc example.com 80 < request.txt

# Keep the request readable with a heredoc
nc example.com 80 <<'EOF'
GET /index.html HTTP/1.1
Host: example.com
Connection: close

EOF

CRLF is mandatory in HTTP, SMTP, and most text protocols. A heredoc sends bare LF, which some servers tolerate and others reject. Two fixes:

# Ask netcat to translate, OpenBSD nc and Ncat
printf 'GET / HTTP/1.0\n\n' | nc -C example.com 80

# Or translate yourself, works with any variant
printf 'GET / HTTP/1.0\n\n' | sed 's/$/\r/' | nc example.com 80

On macOS nc that flag is lowercase -c, not -C.

The trailing-blank-line trap

A heredoc ending like this sends only one newline after the last header, and the request never completes:

# WRONG: server waits forever for the end of the headers
nc example.com 80 <<'EOF'
GET / HTTP/1.0
EOF

HTTP headers end with a blank line, so you need two newlines. printf with explicit \r\n\r\n avoids the ambiguity entirely, and is why most working examples use printf rather than a heredoc.

Half-close, the other common hang

By default netcat keeps the socket open after stdin hits EOF, because the server may still be replying. Some servers wait for a FIN before responding, so the two sides deadlock.

# Send FIN after stdin EOF, then keep reading. OpenBSD nc
printf 'GET / HTTP/1.0\r\n\r\n' | nc -N example.com 80

# Ncat equivalent
printf 'GET / HTTP/1.0\r\n\r\n' | ncat --send-only example.com 80

# Wait 1 second after EOF then quit, OpenBSD nc and Ncat
printf 'GET / HTTP/1.0\r\n\r\n' | nc -q 1 example.com 80

# Universal fallback: cap the whole thing
printf 'GET / HTTP/1.0\r\n\r\n' | timeout 5 nc example.com 80

macOS nc has neither -N nor -q. Its -N is an Apple-specific probe count, so passing it does something entirely unrelated. Use timeout or install ncat there.

Interactive protocol probing

netcat's real strength: speaking a text protocol by hand.

# SMTP
nc -C mail.example.com 25
# EHLO test.local
# MAIL FROM:<a@example.com>
# RCPT TO:<b@example.com>
# QUIT

# Redis, which uses its own inline protocol
nc 127.0.0.1 6379
# PING
# INFO server

# Check whether a Redis is exposed without auth
printf 'PING\r\n' | nc -w 2 10.0.0.5 6379

# HTTP proxy CONNECT tunnel by hand
printf 'CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n' \
  | nc proxy.internal 3128
ProtocolPortFirst thing to type
HTTP80GET / HTTP/1.0 then a blank line
SMTP25 / 587EHLO hostname
POP3110USER name
IMAP143a1 CAPABILITY
Redis6379PING
Memcached11211stats
FTP21USER anonymous
Whois43The domain name alone

TLS-wrapped versions of these need ncat --ssl or openssl s_client, because plain netcat sends your typing as cleartext into a TLS listener and gets a handshake failure back.

Proxies

OpenBSD nc and macOS nc can dial through a proxy without extra tooling.

nc -x 127.0.0.1:1080 -X 5 example.com 80        # SOCKS5
nc -x 127.0.0.1:1080 -X 4 example.com 80        # SOCKS4
nc -x proxy:3128 -X connect example.com 443     # HTTP CONNECT
-X valueProtocol
4SOCKS v4
5SOCKS v5, the default
connectHTTP CONNECT

Ncat uses long options and adds authentication:

ncat --proxy 127.0.0.1:1080 --proxy-type socks5 example.com 80
ncat --proxy proxy:3128 --proxy-type http \
  --proxy-auth user:pass example.com 443

netcat-traditional and GNU netcat have no proxy support at all.