# How to Configure Hysteria Core for UDP Traffic: Server and Client Settings

> Learn to configure Hysteria core for UDP traffic. Discover essential server and client settings to optimize your UDP connections and improve performance. Get started now.

- Repository: [Aperture Internet Laboratory/hysteria](https://github.com/apernet/hysteria)
- Tags: how-to-guide
- Published: 2026-05-13

---

**To configure Hysteria core for UDP traffic, set `DisableUDP` to `false` and adjust `UDPIdleTimeout` in the server `Config` struct, while ensuring the client uses `udp` transport and does not set `disableUDP` to `true`.**

The Hysteria protocol treats UDP as a first-class transport, offering fine-grained control over session lifecycle and outbound routing. Whether you are deploying the `apernet/hysteria` server or connecting a client, understanding the UDP configuration options in the core library ensures optimal performance for latency-sensitive applications.

## Understanding UDP Configuration in Hysteria Core

The UDP stack is controlled through several fields in the `server.Config` struct defined in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go). These settings determine whether UDP is enabled, how long idle sessions persist, and how packets are routed.

### Server-Side UDP Controls

The primary boolean flag **`DisableUDP`** (default: `false`) located at lines 27-38 in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) acts as the master switch. When set to `true`, the server refuses UDP streams and sets `UDPEnabled: false` in the HTTP authentication response.

Session longevity is governed by **`UDPIdleTimeout`** (default: `60s`), defined at lines 23-25 in the same file. This duration determines when the `udpSessionManager` closes inactive UDP flows to reclaim resources.

### Outbound and Request Hook Interfaces

For custom routing, the **`Outbound`** interface includes a `UDP(reqAddr string)` method (lines 55-60 in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go)) that creates connections to remote addresses. The default implementation in [`extras/outbounds/ob_direct.go`](https://github.com/apernet/hysteria/blob/main/extras/outbounds/ob_direct.go) uses `net.ListenUDP` for full-cone NAT behavior.

The **`RequestHook`** interface provides a `UDP(data []byte, reqAddr *string)` method (lines 44-50) allowing inspection of the first packet in a flow. This hook can reject connections by returning an error, but cannot modify packet contents.

## Server Configuration for UDP Traffic

Configuring UDP on the server involves both configuration files and programmatic setup.

### Config File Settings

Server configurations support TOML, YAML, or JSON formats. To enable UDP with a custom idle timeout:

```toml

# server.conf.toml

listen = "0.0.0.0:8888"

[tls]
cert = "/path/to/cert.pem"
key  = "/path/to/key.pem"

disableUDP = false
udpIdleTimeout = "2m"

```

### Command Line Flags

The `hysteria server` command exposes UDP-specific flags parsed in [`app/cmd/server.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/server.go) (lines 1338-1339):

- `--disableUDP`: Disables UDP handling entirely
- `--udpIdleTimeout`: Sets idle timeout in seconds

Example:

```bash
hysteria server --config server.conf.toml --disableUDP

```

### Authentication and Session Management

When a client POSTs to `/<protocol>.hysteria.org/`, the server builds an `AuthResponse` containing `UDPEnabled: !h.config.DisableUDP` within the `h3sHandler.ServeHTTP` method. Following successful authentication, the server spawns a UDP session manager via `newUDPSessionManager` (lines 199-209 in [`core/server/server.go`](https://github.com/apernet/hysteria/blob/main/core/server/server.go)), but only if `DisableUDP` is `false`. The manager implements idle-timeout logic using the configured `UDPIdleTimeout` value in [`core/server/udp.go`](https://github.com/apernet/hysteria/blob/main/core/server/udp.go).

## Client Configuration for UDP Traffic

Client-side UDP configuration ensures the transport can handle UDP workflows.

### Client Config Options

In the client configuration file, ensure the transport type remains `udp` (the default) and avoid setting `disableUDP`:

```toml

# client.conf.toml

server = "example.com:8888"

[tls]
sni = "example.com"

# Do not set disableUDP = true unless forcing TCP-only

```

### CLI Flags

The client CLI in [`app/cmd/client.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/client.go) supports `--disableUDP` to force TCP-only mode. Without this flag, the client builds a UDP transport in `clientConfig.fillConnFactory` (lines 49-60 in [`client/config.go`](https://github.com/apernet/hysteria/blob/main/client/config.go)), creating a `net.PacketConn` via `socketOptions.ListenUDP()`.

## Advanced UDP Customization

For specialized network environments, Hysteria allows custom UDP handling through Go interfaces.

### Custom Outbound Implementations

To route UDP through specific network interfaces or proxies, implement the `Outbound` interface:

```go
type myUDPOutbound struct{}

func (o *myUDPOutbound) UDP(reqAddr string) (hysteria.UDPConn, error) {
    c, err := net.ListenUDP("udp", nil)
    if err != nil {
        return nil, err
    }
    // Example: bind to specific device
    if err := udpConnBindToDevice(c, "eth0"); err != nil {
        return nil, err
    }
    return &hysteria.DefaultUDPConn{UDPConn: c}, nil
}

// Usage
cfg := server.Config{
    Outbound: &myUDPOutbound{},
}

```

### UDP Request Hooks

Implement `RequestHook` to inspect initial packets for blocking or logging:

```go
type probeHook struct{}

func (h *probeHook) Check(isUDP bool, reqAddr string) bool { 
    return isUDP 
}

func (h *probeHook) TCP(_, _ string) ([]byte, error) { 
    return nil, nil 
}

func (h *probeHook) UDP(data []byte, reqAddr *string) error {
    if bytes.HasPrefix(data, []byte{0x01, 0x02}) {
        return errors.New("blocked payload pattern")
    }
    return nil
}

// Registration
cfg.RequestHook = &probeHook{}

```

## Summary

- **Enable UDP** on the server by ensuring `DisableUDP` remains `false` (default) in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go)
- **Configure session timeouts** using `UDPIdleTimeout` to manage resource usage (default 60 seconds)
- **Use CLI flags** `--disableUDP` and `--udpIdleTimeout` for runtime configuration without rebuilding
- **Implement custom `Outbound`** interfaces to control UDP socket creation and binding
- **Inspect initial packets** via `RequestHook.UDP` for security filtering before session establishment

## Frequently Asked Questions

### What is the default UDP idle timeout in Hysteria?

The default **`UDPIdleTimeout`** is **60 seconds**, defined in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) at lines 23-25. After this period of inactivity, the `udpSessionManager` closes the session to free resources.

### How do I completely disable UDP traffic on a Hysteria server?

Set `DisableUDP` to `true` in the server configuration struct or use the `--disableUDP` command line flag. When disabled, the server sets `UDPEnabled: false` in the HTTP authentication response and skips creation of the UDP session manager.

### Can I inspect UDP packets before processing in Hysteria?

Yes, implement the `RequestHook` interface and define the `UDP(data []byte, reqAddr *string)` method (lines 44-50 in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go)). This hook executes on the first packet of each UDP flow and can reject the connection by returning an error, though it cannot modify the payload.

### Does the Hysteria client need special configuration for UDP?

No special configuration is required. Ensure the transport type is `udp` (default) and do not set `disableUDP = true`. The client automatically creates UDP sockets via `socketOptions.ListenUDP()` in [`client/config.go`](https://github.com/apernet/hysteria/blob/main/client/config.go) (lines 49-60) unless port hopping is enabled.