TCP vs UDP for Self-Hosting

What Are TCP and UDP?

TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) are the two transport protocols that carry virtually all internet traffic. Every self-hosted service uses one or both. Understanding the difference matters when configuring Docker port mappings, firewall rules, and reverse proxies.

Updated March 2026: Verified with latest Docker images and configurations.

TCP guarantees delivery. Data arrives in order, complete, and without errors. If a packet is lost, TCP retransmits it. This reliability comes at the cost of some latency.

UDP is fire-and-forget. Packets are sent without confirmation. Some may arrive out of order, duplicated, or not at all. This makes UDP faster and lower-latency than TCP, but less reliable.

Prerequisites

TCP vs UDP Comparison

FeatureTCPUDP
ConnectionConnection-oriented (handshake first)Connectionless (send immediately)
Delivery guaranteeYes — retransmits lost packetsNo — packets can be lost
Order guaranteeYes — data arrives in orderNo — packets may arrive out of order
SpeedSlower (overhead from reliability)Faster (no overhead)
LatencyHigher (handshake + acknowledgments)Lower (send and forget)
OverheadHigher (headers, state tracking)Lower (minimal headers)
Use caseWeb, email, file transfer, databasesDNS, VPN, streaming, gaming

Which Self-Hosted Services Use What?

TCP Services

Most self-hosted applications use TCP exclusively:

ServicePortProtocolWhy TCP
Web servers (HTTP/HTTPS)80, 443TCPWeb pages must arrive complete and in order
Nextcloud443TCPFile sync requires reliable delivery
Jellyfin (web UI)8096TCPHTTP-based interface
Vaultwarden80/443TCPPassword data must be perfect
PostgreSQL5432TCPDatabase queries need guaranteed delivery
MariaDB3306TCPSame as PostgreSQL
Redis6379TCPCache commands must complete reliably
SSH22TCPTerminal sessions need ordered, reliable data
SMTP email25, 465, 587TCPEmail must arrive intact
Git22, 443TCPCode transfers must be exact

UDP Services

A smaller set of services rely on UDP:

ServicePortProtocolWhy UDP
Pi-hole / AdGuard Home (DNS)53UDP (and TCP)DNS queries are small, latency-sensitive
WireGuard51820UDPVPN tunnel — speed over reliability
Tailscale / Headscale41641UDPSame VPN reasoning as WireGuard
Jellyfin (DLNA discovery)1900UDPDevice discovery broadcasts
Plex (GDM discovery)32410-32414UDPNetwork device discovery
NTP (time sync)123UDPTime packets are small and time-sensitive
mDNS5353UDPLocal network service discovery
TURN/STUN (video calling)3478UDPReal-time media prefers lower latency

Services Using Both

ServiceTCP PortUDP PortWhy Both
DNS (Pi-hole, AdGuard)5353Small queries use UDP; large responses fall back to TCP
Jitsi Meet443 (web)10000 (media)Web interface via TCP, video/audio via UDP
BigBlueButton443 (web)16384-32768 (media)Same pattern as Jitsi

Docker Port Mappings

By default, Docker maps TCP ports. To map UDP, you must specify it explicitly:

services:
  pihole:
    image: pihole/pihole:2026.02.0
    ports:
      - "53:53/tcp"      # DNS over TCP
      - "53:53/udp"      # DNS over UDP
      - "80:80/tcp"      # Web admin interface
    restart: unless-stopped

  wireguard:
    image: lscr.io/linuxserver/wireguard:1.0.20210914
    ports:
      - "51820:51820/udp" # WireGuard tunnel (UDP only)
    restart: unless-stopped

Common shorthand: "53:53" without a protocol suffix maps TCP only. Always specify /udp when you need UDP.

ports:
  - "8080:8080"          # TCP only (default)
  - "8080:8080/tcp"      # TCP only (explicit)
  - "51820:51820/udp"    # UDP only
  - "53:53/tcp"          # TCP for DNS
  - "53:53/udp"          # UDP for DNS (separate line)

Firewall Rules

Firewalls also distinguish between TCP and UDP. You must open the correct protocol:

UFW

# Open TCP port
sudo ufw allow 443/tcp

# Open UDP port
sudo ufw allow 51820/udp

# Open both TCP and UDP on the same port
sudo ufw allow 53

# Open a port range (UDP)
sudo ufw allow 10000:10100/udp

iptables

# Allow TCP
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow UDP
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT

See Firewall Setup for complete firewall configuration.

Reverse Proxies and Protocols

Standard reverse proxies (Nginx Proxy Manager, Traefik, Caddy) handle TCP traffic. They proxy HTTP/HTTPS connections to your backend containers.

UDP traffic cannot be proxied through standard HTTP reverse proxies. Services that use UDP (WireGuard, DNS) need direct port exposure:

services:
  # This goes through the reverse proxy (TCP/HTTP)
  nextcloud:
    image: nextcloud:33.0.0
    # No port mapping needed — reverse proxy routes to it
    restart: unless-stopped

  # This needs direct port exposure (UDP)
  wireguard:
    image: lscr.io/linuxserver/wireguard:1.0.20210914
    ports:
      - "51820:51820/udp"  # Direct exposure, no reverse proxy
    restart: unless-stopped

Nginx can proxy UDP with the stream module, but this is rarely needed for self-hosting.

Troubleshooting Protocol Issues

Service Not Reachable

If a service uses UDP but you only opened TCP (or vice versa), it won’t work:

# Test TCP connectivity
nc -zv server-ip 53

# Test UDP connectivity
nc -zuv server-ip 53

# Check what's listening
sudo ss -tulnp | grep :53
# t = TCP, u = UDP

DNS Not Working Through Docker

Pi-hole or AdGuard not resolving DNS? Verify both TCP and UDP port 53 are mapped:

ports:
  - "53:53/tcp"
  - "53:53/udp"  # This line is often forgotten

WireGuard Can’t Connect

WireGuard is UDP-only. Check:

  1. Docker port mapping includes /udp
  2. Firewall allows UDP on the WireGuard port
  3. Router port forwards UDP (not just TCP)

Common Mistakes

Forgetting /udp in Docker Port Mappings

The default protocol in Docker is TCP. Writing "53:53" only maps TCP. DNS queries from clients use UDP by default and will fail. Always explicitly map UDP ports.

Blocking UDP in Firewall

Many firewall guides focus on TCP. If you set up ufw default deny and only allow TCP ports, UDP services (DNS, VPN) won’t work. Check your rules with sudo ufw status verbose.

Port Forwarding Only TCP on Router

Home routers often separate TCP and UDP port forwarding. If you forward TCP port 51820 but not UDP port 51820, WireGuard won’t accept connections from outside your network.

Using a Reverse Proxy for UDP Services

HTTP reverse proxies don’t handle UDP. WireGuard, DNS, and media streaming (Jitsi’s UDP port) need direct port exposure, not reverse proxy routing.

Next Steps

FAQ

Can I force a UDP service to use TCP instead?

Generally no. The application determines which protocol it uses. WireGuard is UDP-only. DNS can use either (TCP fallback for large responses), but clients default to UDP. Some VPN protocols (OpenVPN) support both and can be configured for TCP, usually at the cost of performance.

Is UDP less secure than TCP?

No. Security is handled by the application layer (TLS, encryption), not the transport protocol. WireGuard uses UDP and is one of the most secure VPN protocols. Both TCP and UDP traffic should be encrypted at the application level.

Why does DNS use UDP instead of TCP?

DNS queries are small (typically under 512 bytes) and latency-sensitive. UDP’s lack of connection setup overhead makes DNS queries faster. If a response is too large for a single UDP packet, DNS falls back to TCP automatically.

Do I need to open both TCP and UDP for every service?

No. Most services only use one protocol. Check the service’s documentation for which ports and protocols it needs. Opening unnecessary ports increases your attack surface.

Comments