netcat (nc) reads and writes raw data over TCP or UDP connections. It’s called the “Swiss army knife” of networking. For server admins, it’s the quickest way to answer “is this port reachable?”, to fake a service while testing a firewall, or to move a file between two servers.
Versions
There are several netcat implementations with slightly different flags:
- OpenBSD netcat (
netcat-openbsd) is the default on Debian and Ubuntu. Used in this guide. - Ncat (from nmap) is the default on RHEL-family systems (
nmap-ncat). Most examples work, with some flag differences. - Traditional netcat is old. Avoid it.
sudo apt install netcat-openbsd # Debian/Ubuntu
sudo dnf install nmap-ncat # RHEL family
Test whether a port is open
nc -zv 203.0.113.10 22
# Connection to 203.0.113.10 22 port [tcp/ssh] succeeded!
nc -zv db.internal 5432
nc -zv -w 3 example.com 443 # 3-second timeout
nc -zv 203.0.113.10 20-25 # a port range
-z— just check, send no data.-v— verbose: say whether it succeeded.-w 3— timeout in seconds.
Results:
- succeeded → reachable, and something is listening.
- Connection refused → reachable, but nothing listens on that port. Check the service and its bind address.
- timed out → a firewall is dropping packets somewhere, or the host is down.
This is the fastest check when an app says “can’t connect to database”. Test from the app server to the database host and port.
UDP (less reliable, because UDP has no handshake):
nc -zvu 203.0.113.10 51820
Listen on a port (fake a service)
Is the firewall open, before the real service is even installed? Start a listener on the server:
nc -lv 8080 # OpenBSD nc: listen on port 8080
# ncat: ncat -lv 8080
Then from outside, run nc -zv server-ip 8080. If the listener prints a connection, the path through all firewalls works. Stop the listener with Ctrl+C.
Ports below 1024 need root.
Talk to services by hand
HTTP:
printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' | nc example.com 80
This shows raw response headers. For HTTPS, use openssl s_client -connect example.com:443 instead, because nc doesn’t do TLS. See openssl commands.
SMTP, to check whether outbound port 25 is reachable and see the server banner:
nc -v mx.example.com 25
# 220 mx.example.com ESMTP Postfix
QUIT
Redis:
printf 'PING\r\n' | nc -q1 127.0.0.1 6379
# +PONG
Transfer a file between servers
On the receiving server:
nc -l 9000 > backup.tar.gz
On the sending server:
nc -N receiver-ip 9000 < backup.tar.gz
-N closes the connection at end of file (OpenBSD nc). Check integrity afterwards with sha256sum on both sides.
A whole directory, compressed on the fly:
# receiver
nc -l 9000 | tar -xzf -
# sender
tar -czf - /var/www/site | nc -N receiver-ip 9000
This is unencrypted and unauthenticated. Only use it on private networks or tunnels, and close the port afterwards. Over the internet, use rsync or scp over SSH. See rsync and scp.
Simple port scan
nc -zv -w1 203.0.113.10 1-1024 2>&1 | grep succeeded
For anything beyond a quick check, use nmap.
Chat between two machines
# machine A
nc -l 5000
# machine B
nc A-ip 5000
Whatever you type appears on the other side. It’s a fun way to show that a network path works in both directions.
Alternatives when nc isn’t installed
Bash can open TCP connections itself:
timeout 3 bash -c '</dev/tcp/db.internal/5432' && echo open || echo closed
curl -v telnet://host:port also works as a quick connectivity test.
Quick reference
| Task | Command |
|---|---|
| Is TCP port open? | nc -zv host port |
| With timeout | nc -zv -w 3 host port |
| UDP check | nc -zvu host port |
| Listen | nc -lv port |
| Raw HTTP | printf 'GET / HTTP/1.1\r\nHost: x\r\n\r\n' | nc host 80 |
| Receive file | nc -l 9000 > file |
| Send file | nc -N host 9000 < file |
| No nc available | bash -c '</dev/tcp/host/port' |
Related: check open ports and tcpdump.