tcpdump prints the packets that cross a network interface, one line per packet, and can save them to a file for Wireshark. On a server it answers questions no log can: is the request reaching the machine at all, who is opening connections to port 443, which DNS server the box really asks, and who sends the reset. The outputs marked as real were captured on a Debian 12 server with tcpdump 4.99.3, on the loopback interface against our own test services; the eth0 recipes use the same flags.
Short answer
- Watch one port:
sudo tcpdump -i eth0 -nn port 443. Stop with Ctrl+C. - Save for Wireshark:
sudo tcpdump -i eth0 -nn -w web.pcap port 443, read it back withtcpdump -nn -r web.pcap. - Quote filters with parentheses:
sudo tcpdump -i eth0 -nn 'host 203.0.113.7 and (port 80 or port 443)'
Key facts
- Package
- tcpdump (apt, dnf, apk, pacman)
- Needs
- root, or CAP_NET_RAW, to capture
- Default snapshot length
- 262144 bytestcpdump 4.99
- Filter syntax
- man 7 pcap-filter
- Stops on
- Ctrl+C, or after -c N packets
- File format
- .pcap, opens in Wireshark
Install tcpdump and pick the interface
sudo apt install tcpdump # Debian, Ubuntu
sudo dnf install tcpdump # Rocky, AlmaLinux, Fedora
sudo apk add tcpdump # Alpine
sudo pacman -S tcpdump # Arch
tcpdump --versionWithout -i, tcpdump picks the lowest numbered interface that is up, loopback excluded. That guess is usually right on a VPS with one network card, but name it anyway, so a script does the same on every server. tcpdump -D lists what it can capture on:
1.eth0 [Up, Running, Connected]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]eth0,ens3,ens18,enp1s0: the public network card. The name depends on the image and the hypervisor;ip -br addrshows which one holds your public IP.any: every interface at once, including loopback and Docker bridges. The man page notes that it never runs in promiscuous mode, and each line gains two columns: the interface and the direction (InorOut).lo: traffic between programs on the same server, such as nginx talking to an app on127.0.0.1:3000or lookups to the local DNS stub.
$ sudo tcpdump -i any -nn -c 3 port 18080
tcpdump: data link type LINUX_SLL2
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
03:15:59.257627 lo In IP 127.0.0.1.46466 > 127.0.0.1.18080: Flags [S], seq 120644302, win 65495, options [mss 65495,sackOK,TS val 2437651709 ecr 0,nop,wscale 7], length 0How to read tcpdump output
This is one complete HTTP request, captured with sudo tcpdump -i lo -nn -c 10 port 18080 while curl fetched a page from a test server on port 18080. It is trimmed to fit the page: the TCP options and the first line (tcpdump: verbose output suppressed, use -v[v]... for full protocol decode) were cut.
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
03:15:57.068132 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [S], seq 1574766054, win 65495, length 0
03:15:57.068146 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [S.], seq 2675402100, ack 1574766055, win 65483, length 0
03:15:57.068157 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 1, win 512, length 0
03:15:57.068190 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [P.], seq 1:77, ack 1, win 512, length 76
03:15:57.068194 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [.], ack 77, win 511, length 0
03:15:57.070098 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [P.], seq 1:185, ack 77, win 512, length 184
03:15:57.070107 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 185, win 511, length 0
03:15:57.070134 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [P.], seq 185:191, ack 77, win 512, length 6
03:15:57.070136 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 191, win 511, length 0
03:15:57.070164 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [F.], seq 77, ack 191, win 512, length 0
10 packets captured
26 packets received by filter
0 packets dropped by kernel- Timestamp, then IP (or
IP6,ARP). 127.0.0.1.46446 > 127.0.0.1.18080: source address and port, then destination. The last dot-separated number is the port, also for IPv6 addresses.- Flags:
SSYN,FFIN,PPUSH (data),RRST, and a dot for ACK.[S],[S.],[.]is the three-way handshake;[P.]carries data;[F.]starts the close. seq 1:77andlength 76: this packet carries bytes 1 to 76 of the client’s stream (the HTTP request). After the handshake, tcpdump prints sequence numbers relative to the start; add-Sfor the real ones. If the capture starts in the middle of a connection, it never sees the start and prints the large absolute numbers instead.- The three counters at the end:
capturedis what tcpdump processed, and the meaning ofreceived by filterdepends on the OS (here it was higher than captured). Onlydropped by kerneltells you about lost packets: it must be 0, or you are missing some.
The handshake itself, retransmissions and what a refused or dropped SYN looks like are explained in what TCP is and how the handshake works.
Options that change the output
| Option | What it does |
|---|---|
-n | No DNS lookups and no port names. In tcpdump 4.99, -n and -nn printed identical lines in our test; -nn is still the habit and harmless. |
-c 100 | Stop after 100 packets. |
-v, -vv, -vvv | More detail: TTL, IP ID, total length, full DNS answers. |
-tttt | Date and time on each line (2026-11-02 03:17:32.731853). |
-A | Payload as ASCII. Readable for HTTP, SMTP and DNS names. |
-X | Payload as hex and ASCII side by side. |
-e | Link-layer header: MAC addresses. |
-l | Line-buffered output, needed when you pipe into grep or awk and want lines right away. |
-q | Shorter lines with less protocol detail. |
-s 128 | Keep only the first 128 bytes of each packet (default 262144). |
-# | Number each packet, like Wireshark's No. column. |
Without -n, the same DNS packet read back from our capture file printed localhost.37266 and 127.0.0.53.domain instead of numbers. On a busy server the reverse lookups also slow tcpdump down, which is one of the causes of dropped packets.
tcpdump filters: host, net, port, protocol
Everything after the options is the filter, written in the libpcap filter language (man 7 pcap-filter). The kernel applies it before tcpdump sees a packet, so a tight filter is also the cheapest way to avoid drops. Put the whole filter in single quotes.
| Capture | Filter |
|---|---|
| To or from one address | host 203.0.113.7 |
| Only from, or only to, an address | src host 203.0.113.7 / dst host 203.0.113.7 |
| A whole subnet | net 198.51.100.0/24 |
| One port, TCP or UDP | port 443 |
| Only the destination port | tcp dst port 443 |
| A port range | portrange 8000-8100 |
| By protocol | tcp / udp / icmp / icmp6 / arp / ip6 |
| Two ports | port 80 or port 443 |
| Everything except SSH | not port 22 |
| One client on the web ports | host 203.0.113.7 and (port 80 or port 443) |
| Packets of 1000 bytes or more | greater 1000 |
| New TCP connections only (SYN without ACK) | tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn |
| Resets only | tcp[tcpflags] & tcp-rst != 0 |
| Ping requests and replies | icmp[icmptype] == icmp-echo or icmp[icmptype] == icmp-echoreply |
Three rules from the man page that explain most surprises:
notbinds tightest, andandandorhave equal precedence, read left to right.not host a and bmeansnot host a and host b, notnot (a or b). Use parentheses whenever you mix them.- A missing keyword repeats the last one.
port 80 or 443is read asport 80 or port 443. - Byte offsets such as
tcp[13]ortcp[tcpflags]only match IPv4 in libpcap 1.10 (Debian 12): the BUGS section says arithmetic on transport headers ignores IPv6 packets. A SYN filter therefore silently misses IPv6 clients. In our test,'ip6 and tcp[tcpflags] & tcp-syn != 0'stopped at once withtcpdump: expression rejects all packets.
For IPv6, read the flags from the IPv6 header instead. The IPv6 header is 40 bytes and the TCP flags are byte 13 of the TCP header, so a new connection (SYN set, ACK clear) is:
sudo tcpdump -i eth0 -nn 'ip6 and tcp dst port 443 and ip6[40+13] & 0x12 == 0x02'It only works when TCP follows the IPv6 header directly. Packets with extension headers in between are not matched at all, which is rare for normal web traffic. In our test it caught the SYN of a curl to [::1] and nothing else.
Only incoming or only outgoing: -Q
-Q in keeps only the packets the interface receives, -Q out only the ones it sends; without -Q you get both. On a server with several addresses that is simpler than writing every address into dst host: sudo tcpdump -i eth0 -nn -Q in 'tcp port 443' shows only what clients send. The man page says the option is not available on every platform; on Linux, tcpdump 4.99.3 accepted it, also together with -i any.
Test a filter, or keep it in a file
To check a filter without capturing, compile it with -d. This needs no root and no capture file: tcpdump -d 'tcp dst port 443' as a normal user printed Warning: assuming Ethernet and the BPF program in our test, or the syntax error when the filter is wrong. Add -r web.pcap to compile it for the exact link type of a capture file.
Long filters can live in a file: -F filter.txt reads the expression from it, and per the man page a filter on the command line is then ignored. Keep the file in your home directory or under /tmp, because the AppArmor profile described in the errors below blocks reads from most other places.
Save, rotate and read pcap files
sudo tcpdump -i eth0 -nn -w web.pcap port 443 # write raw packets, print nothing
sudo tcpdump -i eth0 -nn -w web.pcap --print port 443 # write and show them at the same time
tcpdump -nn -r web.pcap # read back, no root needed
tcpdump -nn -r web.pcap 'tcp[tcpflags] & tcp-rst != 0' # read back with a filter
tcpdump --count -r web.pcap 'tcp[tcpflags] & tcp-syn != 0' # only count matches-w stores whole packets, not the text lines, so you can filter the file again later in tcpdump or Wireshark. The output is buffered: another program reading the file while the capture runs sees nothing for a while, unless you add -U.
Rotate captures with -C, -G and -W
# ring buffer by size: at most 10 files of about 100 MB, oldest overwritten
sudo tcpdump -i eth0 -nn -C 100 -W 10 -w /var/tmp/pcap/ring.pcap port 443
# one file per hour, names from strftime, compressed after each rotation
sudo tcpdump -i eth0 -nn -G 3600 -w '/var/tmp/pcap/web-%Y%m%d-%H%M.pcap' -z gzip port 443What the man page says, and what our test showed:
-Ccounts millions of bytes (1,000,000, not 1,048,576), and checks the size before each write, so files end slightly above it. With-C 1 -W 3, our capture producedring.pcap0,ring.pcap1andring.pcap2, and kept writing in a circle.-Gwith-Wis not a ring. tcpdump stops after that many files. Our-G 2 -W 3test ended withMaximum file limit reached: 3and exit code 0 after six seconds. For an always-on hourly capture, leave out-Wand delete old files with a timer, for examplefind /var/tmp/pcap -name 'web-*' -mmin +1440 -delete.-Gwithout a time format in the name overwrites the same file every period. With both-Cand-G, the man page says-Wis ignored.
tcpdump examples for servers
Replace eth0 with your interface. Each recipe is safe to run on a production server: none of them changes anything, and the filters keep the volume small.
Who is opening connections to port 443?
sudo tcpdump -i eth0 -nn -l -c 2000 \
'tcp dst port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' 2>/dev/null |
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head -20Only the first packet of each connection matches, so the count is connections, not traffic. Field $3 is the source in the normal output; with -i any, the interface and direction columns push it to $5. The cut drops the port, which only works for IPv4 addresses, and the flag filter is IPv4 only anyway (see the rules above). For IPv6 clients, swap in the ip6[40+13] filter from that section and replace the cut with sed 's/\.[0-9]*$//', which strips the port from both address types.
Spot a SYN flood
# new connection attempts in 10 seconds
sudo timeout 10 tcpdump -i eth0 -nn 'tcp dst port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' 2>/dev/null | wc -l
# the same for IPv6 clients
sudo timeout 10 tcpdump -i eth0 -nn 'ip6 and tcp dst port 443 and ip6[40+13] & 0x12 == 0x02' 2>/dev/null | wc -l
# handshakes the server answered but the client never completed
ss -Htn state syn-recv '( sport = :443 )' | wc -l
ss -Htn state established '( sport = :443 )' | wc -lOn a healthy server syn-recv is close to 0, because real clients answer the SYN-ACK within milliseconds. The SYN count has no universal normal value: run the same 10-second count in a quiet hour and keep it as your baseline. A flood shows a SYN rate far above that baseline, a syn-recv count that stays high, and few completed handshakes, often from random, spoofed source addresses, so the per-source list above stays flat instead of showing one attacker. With net.ipv4.tcp_syncookies=1 (the kernel default, also on our Debian 12 host), syn-recv stops growing at the size of the SYN backlog: the kernel answers further SYNs with cookies instead of storing them, and logs a line containing Possible SYN flooding on port. A flat syn-recv count is therefore no sign that the flood has stopped. Background on the attack types is in what a DDoS attack is.
Watch DNS queries
sudo tcpdump -i any -nn -l 'port 53'03:17:32.731853 IP 127.0.0.1.37266 > 127.0.0.53.53: 51342+ [1au] A? example.net. (52)
03:17:32.734063 IP 127.0.0.53.53 > 127.0.0.1.37266: 51342 2/0/1 A 172.66.175.59, A 104.20.21.8 (72)51342 is the query ID that pairs question and answer, + means recursion desired, A? the record type asked for, and (52) the DNS message length. In the answer, 2/0/1 counts answer, authority and additional records. The [1au] on the query is its one additional record, the EDNS option. Use -i any on Ubuntu and Debian with systemd-resolved: programs ask the stub on 127.0.0.53 over loopback, and only the stub’s own queries leave through eth0. Filter on port 53, not udp port 53, because large answers retry over TCP.
See which sites are requested (HTTP Host and HTTPS SNI)
sudo tcpdump -i eth0 -nn -l -A 'tcp dst port 80' | grep -a -i '^Host:'sudo tcpdump -i eth0 -nn -A -c 20 \
'tcp dst port 443 and tcp[((tcp[12] & 0xf0) >> 2)] = 0x16'HTTPS encrypts the Host header, but the name the browser asks for travels in clear text in the first TLS message, the ClientHello. The filter reads the TCP header length, jumps to the first payload byte and keeps packets where it is 0x16, a TLS handshake record. In our test (openssl s_client over loopback, a 517-byte ClientHello in one packet), -A on that packet showed the test name shop.example in the ASCII column. Where it falls short:
- Large ClientHellos from current browsers. Chrome and Firefox now send a post-quantum key share (
X25519MLKEM768), which makes the ClientHello about 1.8 KB. Oneth0with a 1500-byte MTU it spans two TCP segments, and Chrome shuffles the order of its extensions, so the server name can land in the second segment. That segment does not start with0x16, and the filter does not show it. The reliable route is a pcap file andtshark -r web.pcap -Y tls.handshake.extensions_server_name -T fields -e tls.handshake.extensions_server_name, which reassembles the segments first. - Encrypted Client Hello (ECH). The name in clear text is only the outer public name, for example the ECH name of the CDN, not the real site.
- IPv4 only. Like the flag filters, the
tcp[...]offsets do not match IPv6 packets. - HTTP/3 runs over UDP 443, which a
tcpfilter never sees.
Find out who sends a reset
sudo tcpdump -i any -nn 'tcp port 443 and tcp[tcpflags] & tcp-rst != 0' shows every RST on the port, with the side that sent it. How to read the result when a browser reports a reset is in ERR_CONNECTION_RESET for site owners.
Capture for a fixed time
sudo timeout 60 tcpdump -i eth0 -nn -w /var/tmp/pcap/minute.pcap 'port 443'timeout sends SIGTERM, on which tcpdump closes the file cleanly and prints its counters, so a cron job or a support script cannot leave a capture running forever.
Capture a Docker container’s traffic
# all containers on Docker's default bridge network
sudo tcpdump -i docker0 -nn port 80
# one container, inside its network namespace (eth0 is the container's interface)
sudo nsenter -t "$(docker inspect -f '{{.State.Pid}}' CONTAINER)" -n tcpdump -i eth0 -nn port 80docker0is the default bridge. Containers on a network you created withdocker network createsit on abr-bridge instead, and every container also has its ownvethinterface on the host;ip -br linklists them.nsenter -nenters only the container’s network namespace. tcpdump, its filter and the-wpath all come from the host, so the image needs no tcpdump.- Addresses: on
docker0and inside the container you see the container’s private address; on the host’seth0the same traffic appears after Docker’s NAT, with the host’s public address.
Capture remotely and open it in Wireshark
Two ways. The simple one: write a file on the server, copy it home, open it.
# on the server
sudo tcpdump -i eth0 -nn -c 5000 -w /var/tmp/pcap/web.pcap 'port 443'
# on your PC
scp root@203.0.113.10:/var/tmp/pcap/web.pcap .The live one: run tcpdump over SSH, write the packets to standard output and let Wireshark read them from standard input.
ssh root@203.0.113.10 "tcpdump -i eth0 -U -w - 'not port 22'" | wireshark -k -i -not port 22keeps your own SSH session out. Without it, every captured packet travels back over SSH, which creates new packets to capture, and the stream feeds itself. If SSH runs on another port, exclude that one, or narrow it to your session withnot (host YOUR_IP and port 22).-w -and-U: raw packets to standard output, flushed after each packet so Wireshark shows them as they arrive. We tested the same pipe locally intotcpdump -r -.-k -i -: per the Wireshark manual, start capturing at once and read pcap data from standard input.- Not root on the server? Use
sudo tcpdumpwith a sudo rule that needs no password. Do not addssh -tto answer a password prompt: a terminal rewrites line endings and corrupts the binary stream. - Windows: run the same pipe from
cmd.exewith the full path toWireshark.exe. Windows PowerShell 5.1 pipes between programs as text and breaks the pcap data.
If the server uses another SSH port, user or key, put them in a Host block of your SSH config file and the pipe stays a one-liner.
tcpdump vs Wireshark vs ss
| tcpdump | Wireshark | ss | |
|---|---|---|---|
| Runs on a headless server | Yes | No | Yes |
| Shows individual packets | Yes | Yes | No |
| Shows sockets and the owning process | No | No | Yes |
| Decodes protocols in depth (TLS, HTTP/2, QUIC) | Headers and common protocols | Yes | No |
| Writes capture files | .pcap | .pcapng by default, .pcap | No |
| Rights needed | Root, or CAP_NET_RAW, to capture | Capture rights (root, or the wireshark group on Linux) | Only to see other users' processes |
In practice they work together. ss answers “what is listening and who is connected right now” without touching packets, which is the first step in checking open ports on Linux. tcpdump captures on the server, where there is no screen. Wireshark, or its command-line twin tshark, analyses the file afterwards: following a TCP stream, decrypting your own TLS sessions with a key log, graphing retransmissions.
tcpdump errors and fixes
Symptom, cause, fix
Symptom: tcpdump: eth0: You don't have permission to perform this capture on that device
(socket: Operation not permitted)- Cause
- You ran it as a normal user. Capturing needs root or CAP_NET_RAW.
- Fix
- Run it with
sudo. Reading a saved file with-rneeds no root. To capture without sudo, see the note below.
Symptom: tcpdump: eth9: No such device exists
- Cause
- The interface has another name on this machine.
- Fix
- List the names with
tcpdump -Dorip -br link.
Symptom: tcpdump: can't parse filter expression: syntax error
- Cause
- A typo in the filter, such as prot instead of port, or a missing and.
- Fix
- Check each keyword against
man 7 pcap-filterand test it withtcpdump -d.
Symptom: bash: syntax error near unexpected token `('
- Cause
- The shell saw the parentheses of an unquoted filter.
- Fix
- Put the whole filter in single quotes.
Symptom: tcpdump: /var/tmp/pcap/web-20261102-0317.pcap: Permission denied
- Cause
- It appears at the first rotation, after the first file was written, and tcpdump exits with code 1. tcpdump runs as the user tcpdump after opening the first file and cannot create files in a root-only directory.
- Fix
- Capture into a directory owned by
tcpdump(sudo install -d -o tcpdump -g tcpdump /var/tmp/pcap), or add-Z root.
Symptom: tcpdump: /srv/capture.txt: Permission denied, even with sudo
- Cause
- Debian 12 and Ubuntu ship an enforcing AppArmor profile for tcpdump,
/etc/apparmor.d/usr.bin.tcpdump. Outside/tmp,/var/tmpand your home directory,-wmay only write files ending in.pcap,.capor.pcapplus digits;.txtand.pcapngare refused. Read from the profile file on our Debian 12 host (aa-statuslists tcpdump in enforce mode), not reproduced. - Fix
- Name the file
.pcap(ring buffer files such asring.pcap0still match), or write under/var/tmp. That is why the recipes here use/var/tmp/pcapand.pcapnames.
Symptom: N packets dropped by kernel is above 0
- Cause
- tcpdump could not keep up. In our test, three 3 MB downloads over loopback dropped 113 packets while writing to a file.
- Fix
- Add
-nn, write with-winstead of printing, narrow the filter, cut payload with-s 128, or raise the buffer with-B 8192(KiB).
Symptom: cksum 0xfe30 (incorrect -> 0xfa53) on your own outgoing packets (with -v)
- Cause
- The checksum is filled in after tcpdump sees the packet: by the network card (checksum offload), and on loopback not at all. In our test, the SYN that curl sent over lo showed this, the RST that answered it showed correct.
- Fix
- Ignore it, or skip the check with
-K. The man page says that otherwise all outgoing TCP checksums will be flagged as bad on such interfaces.
Capture without sudo (setcap), and its risk
sudo groupadd pcap
sudo usermod -aG pcap YOUR_USER
sudo chgrp pcap /usr/bin/tcpdump
sudo chmod 750 /usr/bin/tcpdump
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump # last: chgrp removes file capabilitiesHow we tested
- OS image
- Debian 12
- Versions
- tcpdump 4.99.3libpcap 1.10.3iproute2 6.1.0curl 7.88.1
- Tested on
- Method
- Captures on the loopback interface only, against test services bound to 127.0.0.1 and ::1 (an HTTP server on port 18080, a TLS server with a throwaway certificate on 18443, curl to a closed port for the checksum, -Q and IPv6 checks) and two lookups through the systemd-resolved stub. Output formats, rotation file names, the -Z permission failure and the dropped-packet count come from those runs, and so does every error text above, except the AppArmor row, which is read from the profile file.
- Not tested
- The live stream into the Wireshark GUI (the pipe was tested into tcpdump -r -), tshark, Docker and nsenter, setcap, the AppArmor denial, captures on a real network card and a real SYN flood.
tcpdump needs root on the machine it captures on, which a shared web host does not give you. Every Standard KVM VPS comes with full root and a VNC console in the panel, so a capture that floods your SSH session can still be stopped from the console in your browser.
Frequently asked
How do I capture traffic on a specific port with tcpdump?
Run sudo tcpdump -i eth0 -nn port 443, replacing eth0 with your interface and 443 with the port. port matches TCP and UDP in both directions; use tcp dst port 443 for only incoming TCP, or 'port 80 or port 443' in single quotes for two ports. Stop with Ctrl+C or add -c 100.
How do I save tcpdump output to a file and open it in Wireshark?
Use -w: sudo tcpdump -i eth0 -nn -w capture.pcap port 443 writes raw packets instead of text. Read it back with tcpdump -nn -r capture.pcap, or copy the file to your PC and open it in Wireshark. Add --print to see packets on screen while they are written.
What does tcpdump -i any do?
It captures on all interfaces at once, including loopback and Docker bridges, in Linux cooked mode. Each line gains the interface name and the direction (In or Out), and the man page notes that captures on any are never in promiscuous mode. Use it when you do not know which interface the traffic takes.
How do I rotate tcpdump capture files?
Use -C 100 -W 10 for a ring of ten files of about 100 MB each (the oldest is overwritten), or -G 3600 with a strftime name such as web-%Y%m%d-%H%M.pcap for one file per hour. Note that -G with -W stops after that many files instead of overwriting, so delete old hourly files with a timer.
What is the difference between tcpdump and Wireshark?
tcpdump is a command-line capture tool that runs on headless servers and writes pcap files. Wireshark is a graphical analyser that decodes far more protocols, follows TCP streams and graphs problems. A common workflow is to capture with tcpdump on the server and analyse the file in Wireshark, or stream it live over SSH.