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
| Flag | Effect |
|---|---|
-4 / -6 | Force an address family, useful when a host has both |
-s addr | Bind a specific local address, for multi-homed routing tests |
-p port | Bind a specific local port. Cannot combine with -l |
-n | No DNS resolution |
-w secs | Timeout for the connect and for the final read |
-v | Report 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:
| Behavior | Almost certainly |
|---|---|
Instant Connection refused | Reached the host, nothing listening. A RST came back |
Hangs until -w expires | Silently dropped. A firewall DROP rule, or wrong route |
No route to host | Local routing table or ARP failure |
Connection reset by peer mid-session | The app closed hard, or a middlebox killed it |
| Connects then immediately closes | TLS 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
| Protocol | Port | First thing to type |
|---|---|---|
| HTTP | 80 | GET / HTTP/1.0 then a blank line |
| SMTP | 25 / 587 | EHLO hostname |
| POP3 | 110 | USER name |
| IMAP | 143 | a1 CAPABILITY |
| Redis | 6379 | PING |
| Memcached | 11211 | stats |
| FTP | 21 | USER anonymous |
| Whois | 43 | The 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 value | Protocol |
|---|---|
4 | SOCKS v4 |
5 | SOCKS v5, the default |
connect | HTTP 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.