CallMeTechie
DE Login
Home Products Blog About Contact

HTTP vs. L4 Routing — When to Use Which?

🌐 Networking & Routing · Updated 1 month ago

Explains the difference between HTTP routing (Layer 7, domain-based) and L4 routing (Layer 4, port-based) — when each type is used, how TLS modes work and which features are available in each case.


What does it do?

GateControl supports two fundamentally different routing types:

  • HTTP routing (Layer 7): Caddy analyzes the HTTP request, matches by domain name and forwards to the backend. Full access to all HTTP features.
  • L4 routing (Layer 4): Caddy forwards raw TCP/UDP traffic without inspecting the content. Matching by port, not by domain.

HTTP routing:

Client  →  https://app.example.com  →  Caddy (matched domain "app.example.com")  →  Backend 10.8.0.3:8080
Client  →  https://api.example.com  →  Caddy (matched domain "api.example.com")  →  Backend 10.8.0.4:3000
                                         ↑ Both on port 443, differentiated by domain

L4 routing:

Client  →  server.example.com:25565  →  Caddy (matched port 25565)  →  Backend 10.8.0.5:25565
Client  →  server.example.com:2222   →  Caddy (matched port 2222)   →  Backend 10.8.0.6:22
                                         ↑ Different ports, domain doesn't matter

HTTP routing (Layer 7) in detail

HTTP routing is the default mode. Caddy terminates TLS, reads HTTP headers and matches based on the Host header.

How it works:

  1. Client connects to port 443 (or 80)
  2. TLS handshake — Caddy picks the correct certificate via SNI
  3. Caddy reads the HTTP Host header
  4. Match against the configured domain → forwarding to the backend
  5. Full HTTP processing: header manipulation, compression, auth, etc.

All route features are available:

  • Force HTTPS with Let's Encrypt
  • Backend HTTPS
  • Compression (Gzip/Zstd)
  • Rate Limiting
  • Basic Auth / Route Auth
  • Peer ACL
  • IP Access Control
  • Request Mirroring
  • Retry on Error
  • Circuit Breaker
  • Custom Headers
  • Load Balancing (multiple backends)
  • Uptime Monitoring (HTTP check)
  • Sticky Sessions

L4 routing (Layer 4) in detail

L4 routing forwards raw TCP or UDP traffic. Caddy opens its own port and tunnels the traffic to the backend.

Three L4-specific fields:

Protocol: TCP or UDP

Protocol Use cases
TCP SSH, Minecraft, SMTP, databases, most services
UDP DNS, game servers (some), VoIP, WireGuard

Listen Port

The port that Caddy opens on the GateControl server. This is the port clients connect to.

  • Not the target port (the port on the backend)
  • Can be equal or different to the target port
  • Must be free on the GateControl server

TLS mode

Mode Description Caddy behavior
None No TLS Caddy forwards raw TCP/UDP traffic
Passthrough TLS pass-through Caddy matches via SNI, forwards encrypted traffic without decrypting
Terminate TLS termination Caddy decrypts TLS (with LE certificate), then forwards unencrypted TCP to the backend

Target Port vs. Listen Port

This is the most important distinction and often causes confusion:

Field Applies to Description
Target Port All routes (HTTP + L4) The port on the backend peer where the service runs
Listen Port Only L4 routes The port Caddy opens on the GateControl server

Example 1: Same ports

Listen Port 25565 (GateControl)  →  Target Port 25565 (Minecraft on peer 10.8.0.4)
Client connects to: server.example.com:25565

Example 2: Different ports

Listen Port 8022 (GateControl)  →  Target Port 22 (SSH on peer 10.8.0.2)
Client connects to: server.example.com:8022
SSH command: ssh -p 8022 user@server.example.com

Example 3: Multiple services, different ports

Listen Port 25565  →  Target Port 25565 (Minecraft on 10.8.0.4)
Listen Port 2222   →  Target Port 22 (SSH on 10.8.0.2)
Listen Port 5433   →  Target Port 5432 (PostgreSQL on 10.8.0.3)

For HTTP routes there is no Listen Port — all HTTP routes share port 80/443 and are differentiated by domain.

TLS modes in detail

None — No TLS

Client  ──TCP/UDP──→  Caddy:25565  ──TCP/UDP──→  Backend:25565
         unencrypted               unencrypted
  • No TLS handshake, no SNI
  • Caddy does not see the traffic content
  • Simplest setup, no certificate required
  • Use cases: Minecraft, game servers, DNS, plain SMTP, databases in the VPN

Passthrough — TLS pass-through

Client  ──TLS──→  Caddy:443  ──TLS──→  Backend:443
         encrypted           encrypted (same connection)
  • Caddy only reads the SNI (server name) from the TLS ClientHello
  • The TLS tunnel is not broken — end-to-end encryption
  • The backend must have its own valid certificate
  • Caddy cannot inspect or modify the content
  • Use cases: Backend with its own LE certificate, strict end-to-end encryption requirements

Terminate — TLS termination

Client  ──TLS──→  Caddy:993  ──TCP──→  Backend:143
         encrypted            unencrypted
         (Let's Encrypt)
  • Caddy terminates TLS with a Let's Encrypt certificate
  • The traffic to the backend is unencrypted (but within the VPN)
  • Matched via SNI, domain must be specified
  • Use cases: TLS for services that don't natively support it, IMAPS/SMTPS in front of a plaintext backend

Blocked ports

The following ports are reserved by default and cannot be used as Listen Port (list from config/default.jsl4.blockedPorts, adjustable via GC_L4_BLOCKED_PORTS):

Port Usage
22 SSH (host service)
53 DNS (host service)
80 Caddy HTTP (ACME challenge + redirect)
443 Caddy HTTPS (HTTP routes)
2019 Caddy Admin API
3000 GateControl Web UI
51820 WireGuard VPN

Use cases

Minecraft server (TCP, port 25565, TLS: None)

Player connects to: mc.example.com:25565
L4 route: Listen Port 25565 → Peer "Gaming-Server" Target Port 25565
Protocol: TCP, TLS: None

SSH access (TCP, port 2222 → 22, TLS: None)

ssh -p 2222 admin@server.example.com
L4 route: Listen Port 2222 → Peer "Homeserver" Target Port 22
Protocol: TCP, TLS: None

Port 22 is not used as the Listen Port to avoid conflicts with the SSH of the GateControl server.

Mail server SMTP (TCP, port 25, TLS: None)

Mail server connects to: mail.example.com:25
L4 route: Listen Port 25 → Peer "Mailserver" Target Port 25
Protocol: TCP, TLS: None (STARTTLS is handled by the backend)

Database (TCP, port 5433 → 5432, TLS: None)

psql -h server.example.com -p 5433 -U myuser mydb
L4 route: Listen Port 5433 → Peer "DB-Server" Target Port 5432
Protocol: TCP, TLS: None

Game server (UDP)

Player connects to: game.example.com:27015
L4 route: Listen Port 27015 → Peer "Game-Server" Target Port 27015
Protocol: UDP, TLS: None

Feature comparison: HTTP vs. L4

Feature HTTP (Layer 7) L4 (Layer 4)
Routing method Domain-based Port-based
HTTPS / Let's Encrypt Yes Only with TLS Terminate
Compression (Gzip/Zstd) Yes No
Rate Limiting Yes No
Custom Headers Yes No
Basic Auth Yes No
Route Auth Yes No
Peer ACL Yes No
IP Access Control Yes No
Request Mirroring Yes No
Retry on Error Yes No
Circuit Breaker Yes No
Uptime Monitoring HTTP check TCP check
Multiple backends Yes (load balancing) No
Sticky Sessions Yes No
WebSocket Yes (automatic) Yes (as TCP)
Protocol HTTP/HTTPS TCP / UDP

WebSocket on HTTP routes: WebSocket connections start as a normal HTTP request with a special Connection: Upgrade header. Caddy detects this header automatically and switches the connection to a persistent WebSocket connection. No additional configuration is required — it works out-of-the-box on any HTTP route.

WebSocket on L4 routes: Since L4 forwards the raw TCP stream without inspecting the content, WebSocket also works here — Caddy only sees TCP packets and forwards them 1:1.

Setup

The route type (HTTP vs. L4) is toggled in the route wizard in Step 1 — Target. The L4-specific fields (Protocol, Listen Port, TLS Mode) then appear in the same step.

Creating an HTTP route (UI)

  1. In Step 1 Route Type: HTTP (default)
  2. Enter domain (e.g. app.example.com)
  3. Select Target Peer
  4. Enter Target Port (e.g. 8080)
  5. Configure features in Step 2-5 (HTTPS, Auth, ACL, Reliability)
  6. Save

Creating an L4 route (UI)

  1. In Step 1 toggle Route Type: L4
  2. Enter domain (required for TLS passthrough/terminate, optional for TLS None)
  3. Select Target Peer
  4. Enter Target Port (port on the backend)
  5. Select Protocol: TCP or UDP
  6. Enter Listen Port (port on the GateControl server)
  7. Select TLS Mode (None, Passthrough, Terminate)
  8. Save

Via the API

# Create HTTP route
curl -X POST https://gatecontrol.example.com/api/v1/routes \
  -H "Authorization: Bearer gc_..." \
  -H "Content-Type: application/json" \
  -d '{
    "route_type": "http",
    "domain": "app.example.com",
    "peer_id": 1,
    "target_port": 8080,
    "https_enabled": true
  }'

# Create L4 route (Minecraft)
curl -X POST https://gatecontrol.example.com/api/v1/routes \
  -H "Authorization: Bearer gc_..." \
  -H "Content-Type: application/json" \
  -d '{
    "route_type": "l4",
    "domain": "mc.example.com",
    "peer_id": 2,
    "target_port": 25565,
    "l4_protocol": "tcp",
    "l4_listen_port": "25565",
    "l4_tls_mode": "none"
  }'

Important notes

  • L4 routes occupy exclusive ports. Every L4 route (without TLS) needs its own Listen Port. Two routes on the same port and protocol without TLS cause a conflict.
  • Multiple L4 routes with TLS (Passthrough or Terminate) can share the same port — Caddy differentiates them via SNI (domain in the TLS ClientHello).
  • Port ranges are possible (e.g. 25565-25575 for multiple Minecraft servers).
  • UDP routes do not support TLS (TLS runs over TCP).
  • L4 routes have no HTTP features: no Rate Limiting, no Auth, no Compression, no ACL, no Mirroring, no Retry, no Circuit Breaker.
  • The Caddy L4 configuration is generated in a separate block (layer4 app), separate from the HTTP servers.
  • If you're unsure which type you need: if the service is accessed in the browser (HTTP/HTTPS), use HTTP routing. If it's a non-HTTP protocol (SSH, database, game server), use L4.

See also

Cookie Settings

We use cookies to improve your experience. Essential cookies are always active.

Privacy Policy
ESC
↑↓ navigate open esc close