opscape

Networking and remote

nc

Open raw TCP or UDP connections, or listen for them; for testing ports, talking to services by hand and piping data between hosts.

nc [OPTION...] HOST PORT  |  nc -l [OPTION...] [ADDRESS] PORT

9 of 9 examples run in Debian 13.7 on 2026-10-31 · manual: nc(1)

netcat connects standard input and output to a network socket. nc host port opens a TCP connection and sends whatever you type (or pipe in), printing whatever comes back; nc -l port waits for someone to connect. That simple model makes it a universal test tool: is the port open, what does the service say first, does my request get an answer.

Several incompatible netcats exist. These examples use netcat-openbsd, the default on Debian and Ubuntu (and the basis of macOS's nc). Two of its habits matter: the listener's port is given directly (nc -l 9000, not nc -l -p 9000 as in the traditional version), and a client does not hang up when its input ends unless you pass -N (or set an idle timeout with -w). ncat from the nmap project is a third variant with its own options.

The examples run on loopback, with a listener started in the background in the same command. Across two machines it is the same: run the -l side on one and the client on the other.

Examples

Check whether a port is open

nc -zv 127.0.0.1 22
explain
output
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!

-z connects and immediately closes without sending data; -v reports the result. The message goes to standard error, and the exit status is 0 for success.

A closed port

nc -zv 127.0.0.1 9999
explain
outputexit 1
nc: connect to 127.0.0.1 port 9999 (tcp) failed: Connection refused

Nothing listens on 9999, so the connection is refused and nc exits with 1, which makes nc -z usable in if tests and wait loops.

Check a range of ports

nc -zv 127.0.0.1 20-23
explain
output
nc: connect to 127.0.0.1 port 20 (tcp) failed: Connection refused
nc: connect to 127.0.0.1 port 21 (tcp) failed: Connection refused
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!
nc: connect to 127.0.0.1 port 23 (tcp) failed: Connection refused

A range checks each port in turn. Only 22 accepts. The exit status is 0 because at least one connection succeeded.

Wait for a service in a script

for i in 1 2 3; do
  nc -z -w 1 127.0.0.1 8080 && { echo "web server is up"; break; }
  sleep 1
done
output
Connection to 127.0.0.1 8080 port [tcp/http-alt] succeeded!
web server is up

-w 1 limits each attempt to one second, so a filtered port that never answers cannot hang the loop. Debian's nc prints the succeeded! line even without -v. A typical use is waiting for a database or web server to start before running tests.

See what a service says first

nc -w 1 127.0.0.1 22 < /dev/null
explain
output
SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4

SSH servers announce their protocol and software version as soon as you connect. nc prints it and, with no input and -w 1, gives up after a second of silence. Mail, FTP and many other text protocols greet you the same way.

Speak HTTP by hand

printf 'GET /api/status.json HTTP/1.0\r\nHost: localhost\r\n\r\n' | nc 127.0.0.1 8080
explain
output
HTTP/1.1 200 OK
Server: demo-httpd/1.0
Date: Sat, 31 Oct 2026 20:20:12 GMT
Content-type: application/json
Content-Length: 56
Last-Modified: Mon, 26 Oct 2026 13:48:10 GMT

{"status": "ok", "version": "2.4.1", "uptime_s": 86400}

The request line, a header and a blank line, with the CRLF endings HTTP requires. The server replies with its status line, headers and body. This shows exactly what is on the wire, with no client adding or hiding anything.

Listen and connect

nc -l 127.0.0.1 9000 > received.txt &
sleep 0.3
echo "hello over tcp" | nc -N 127.0.0.1 9000
wait
cat received.txt
output
hello over tcp

The listener writes whatever arrives to received.txt. The client sends one line; -N shuts down the connection once its input ends, which makes the listener exit too, and wait waits for it.

Send a file between machines

nc -l 127.0.0.1 9000 > copy.csv &
sleep 0.3
nc -N 127.0.0.1 9000 < data/sales.csv
wait
cmp data/sales.csv copy.csv && echo "identical, $(wc -c < copy.csv) bytes"
output
identical, 405 bytes

The same pattern with a file: start the receiving side first, then send. cmp confirms the copy is identical. The data is not encrypted, so use this only on trusted networks; otherwise use scp or rsync.

Send a UDP datagram

nc -u -l 127.0.0.1 9001 > datagram.txt &
sleep 0.3
echo "metric.cpu 42" | nc -u -w 1 127.0.0.1 9001
sleep 0.2
cat datagram.txt
output
metric.cpu 42

-u switches to UDP, as used by syslog, statsd and DNS. UDP has no connection to close, so the client uses -w 1 to quit after a second.

Common pitfalls

  • nc -l -p 9000 is traditional-netcat syntax. netcat-openbsd wants nc -l 9000 and reports an error for -p combined with -l on some versions.

  • Without -N or -w, the openbsd client keeps the connection open after its input ends, so a command like echo hi | nc host port can hang waiting for the server.

  • A successful nc -z only proves that something accepted a TCP connection, not that it is the service you expect or that it works. Talk to it (an HTTP request, a banner) to be sure.

  • -u -z checks for UDP are unreliable: with no reply, nc cannot tell an open port from a filtered one.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • macOS's nc derives from the same BSD code, so most of these examples work there; check man nc for -N before relying on it. Traditional netcat (netcat-traditional), BusyBox nc and nmap's ncat differ in listener syntax and options.

Options worth knowing

A selection, described in our own words. For the full list, see nc(1) or nc --help.

OptionWhat it does
-lListen for an incoming connection instead of connecting.
-kWith -l, keep listening for more connections after one ends.
-zOnly check whether the port accepts connections; send no data.
-vReport connection results and errors.
-nDo not resolve host names or look up ports.
-uUse UDP instead of TCP.
-NShut down the network connection after end of input.
-w SECONDSTime out connections and idle sessions after SECONDS.
-q SECONDSAfter end of input, wait SECONDS and then quit.
-s ADDRESSSend from this local address.
-p PORTUse this local source port.
-4Use IPv4 only.
-6Use IPv6 only.
-UUse Unix domain sockets.
-CSend CRLF as the line ending.
-X PROTOCOLProxy protocol: 4 (SOCKS4), 5 (SOCKS5) or connect (HTTPS proxy).
-x ADDRESS[:PORT]Connect through this proxy.

Related