# How to Set Up the Hysteria Core Module: Server and Client Configuration Guide

> Learn to set up the Hysteria core module with our server and client configuration guide. Easily embed a high-performance QUIC proxy in your Go application.

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

---

**To set up the Hysteria core module, import the `server` or `client` packages from `github.com/apernet/hysteria/core/v2`, populate the `Config` struct with TLS settings and network parameters, and instantiate the service via `NewServer()` or `NewClient()` to embed a high-performance QUIC proxy in your Go application.**

The Hysteria core module resides under the `core/` directory in the `apernet/hysteria` repository and provides low-level building blocks for both server and client implementations. Unlike the command-line interface located in `app/`, this module is deliberately decoupled to allow embedding into existing Go programs without external binary dependencies.

## Core Architecture Overview

The core is organized into three primary areas: server handling, client connectivity, and shared protocol utilities.

| Component | Responsibility | Key Types | Source Files |
|-----------|----------------|-----------|--------------|
| **Server** | Listens on QUIC connections, authenticates clients, and proxies TCP/UDP streams | `Config`, `NewServer`, `serverImpl`, `h3sHandler` | [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go), [`core/server/server.go`](https://github.com/apernet/hysteria/blob/main/core/server/server.go) |
| **Client** | Connects to servers, performs handshake, and exposes proxy APIs | `Config`, `NewClient`, `clientImpl` | [`core/client/config.go`](https://github.com/apernet/hysteria/blob/main/core/client/config.go), [`core/client/client.go`](https://github.com/apernet/hysteria/blob/main/core/client/client.go) |
| **Utilities** | Protocol encoding, congestion control, and stream abstractions | `utils.QStream`, `internal/protocol`, `internal/congestion` | [`core/internal/utils/qstream.go`](https://github.com/apernet/hysteria/blob/main/core/internal/utils/qstream.go), `core/internal/protocol/*` |

**Server initialization flow:**

1. Create a `server.Config` with TLS certificates, a `net.PacketConn` (UDP socket), and an `Authenticator` implementation.
2. Call `config.fill()` to validate fields and apply defaults for stream windows and idle timeouts.
3. Invoke `NewServer()` to convert TLS configurations, build `quic.Config`, and start the QUIC listener.
4. The `h3sHandler` manages incoming connections, authenticates via `Authenticate()`, and dispatches TCP streams via `handleTCPRequest()` or UDP datagrams via `udpIOImpl`.

**Client initialization flow:**

1. Populate `client.Config` with server address, TLS settings, and authentication credentials.
2. `config.verifyAndFill()` normalizes defaults and validates parameters.
3. `clientImpl.connect()` creates a UDP socket, builds QUIC configurations, and sends an HTTP/3 POST request containing an `AuthRequest`.
4. Post-handshake, the client offers `TCP()` and `UDP()` methods for proxy connectivity.

## Setting Up a Hysteria Server

To initialize a server, provide TLS credentials, a UDP socket, and an authentication mechanism. The following example demonstrates a minimal implementation using a static authenticator:

```go
package main

import (
    "crypto/tls"
    "log"
    "net"

    "github.com/apernet/hysteria/core/v2/server"
)

type staticAuth struct{}

func (a *staticAuth) Authenticate(addr net.Addr, auth string, tx uint64) (bool, string) {
    return true, "user-123"
}

func main() {
    cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
    if err != nil {
        log.Fatalf("TLS load error: %v", err)
    }

    udpConn, err := net.ListenPacket("udp", ":443")
    if err != nil {
        log.Fatalf("UDP bind error: %v", err)
    }

    cfg := &server.Config{
        TLSConfig: server.TLSConfig{
            Certificates: []tls.Certificate{cert},
        },
        Conn:          udpConn,
        Authenticator: &staticAuth{},
    }

    s, err := server.NewServer(cfg)
    if err != nil {
        log.Fatalf("Server init error: %v", err)
    }

    log.Println("Hysteria server listening...")
    if err := s.Serve(); err != nil {
        log.Fatalf("Serve exited: %v", err)
    }
}

```

**Critical configuration requirements:**

- `TLSConfig.Certificates` must contain at least one valid certificate; the `fill()` method in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) enforces this validation.
- `Conn` expects a raw UDP socket; the core wraps this with QUIC semantics internally.
- The `Authenticator` interface requires implementing `Authenticate(net.Addr, string, uint64) (bool, string)` to validate tokens and return unique user identifiers.

### Optional Server Hooks

Beyond basic operation, the server supports pluggable interfaces defined in [`core/server/server.go`](https://github.com/apernet/hysteria/blob/main/core/server/server.go):

- **Outbound**: Route TCP/UDP traffic to custom backends such as SOCKS5 proxies.
- **RequestHook**: Inspect or modify the first packet of requests for protocol sniffing.
- **EventLogger** / **TrafficLogger**: Capture connection lifecycle events and per-stream bandwidth metrics; these hooks can enforce limits by returning `false` to block streams.
- **MasqHandler**: Serve regular HTTP responses when clients present no authentication, useful for traffic obfuscation.

## Setting Up a Hysteria Client

The client configuration requires server addressing, TLS settings, and authentication credentials. The handshake process negotiates bandwidth limits and UDP support capabilities:

```go
package main

import (
    "crypto/tls"
    "log"
    "net"

    "github.com/apernet/hysteria/core/v2/client"
)

func main() {
    tlsCfg := client.TLSConfig{
        InsecureSkipVerify: true,
    }

    cfg := &client.Config{
        ServerAddr: &net.UDPAddr{IP: net.ParseIP("192.0.2.1"), Port: 443},
        Auth:       "my-secret-token",
        TLSConfig:  tlsCfg,
    }

    c, info, err := client.NewClient(cfg)
    if err != nil {
        log.Fatalf("Client init error: %v", err)
    }
    defer c.Close()

    log.Printf("Handshake succeeded – UDP enabled: %v, Tx limit: %d\n",
        info.UDPEnabled, info.Tx)

    conn, err := c.TCP("example.org:80")
    if err != nil {
        log.Fatalf("TCP error: %v", err)
    }
    defer conn.Close()

    if info.UDPEnabled {
        udp, err := c.UDP()
        if err != nil {
            log.Fatalf("UDP error: %v", err)
        }
        defer udp.Close()
    }
}

```

**Key implementation details from [`core/client/client.go`](https://github.com/apernet/hysteria/blob/main/core/client/client.go):**

- `ServerAddr` must implement `net.Addr`, typically using `*net.UDPAddr`.
- `NewClient()` returns a `Client` interface and `HandshakeInfo` containing `UDPEnabled` status and transmission bandwidth limits (`Tx`).
- After initialization, `TCP(addr)` opens reliable QUIC streams while `UDP()` manages datagram sessions via `udpSessionManager`.

### Client Configuration Options

As defined in [`core/client/config.go`](https://github.com/apernet/hysteria/blob/main/core/client/config.go), the `Config` struct supports:

- **BandwidthConfig**: Advertise desired send/receive rates to the server for congestion coordination.
- **CongestionConfig**: Select BBR or Cubic algorithms via the `internal/congestion` package.
- **FastOpen**: Enable TCP fast-open for reduced latency on subsequent connections.

## Extending the Core with Custom Interfaces

The modular design allows deep customization without modifying protocol internals.

### Implementing Custom Authentication

The `Authenticator` interface in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) controls access:

```go
type Authenticator interface {
    Authenticate(addr net.Addr, auth string, tx uint64) (bool, string)
}

```

Return `true` and a unique user ID to accept connections, or `false` to reject. The `tx` parameter indicates the client's claimed upload bandwidth, enabling quota-based authentication.

### Adding Traffic Logging

Implement `TrafficLogger` to monitor per-stream statistics:

```go
type TrafficLogger interface {
    LogTraffic(id string, tx, rx uint64) bool
    LogEvent(name string)
}

```

Returning `false` from `LogTraffic` terminates the connection immediately, enabling real-time bandwidth enforcement and circuit-breaking logic.

## Summary

- The Hysteria core module resides in `github.com/apernet/hysteria/core/v2` and operates independently from the CLI application.
- **Server setup** requires implementing `server.Config` with TLS certificates, a UDP `PacketConn`, and an `Authenticator`, then calling `server.NewServer()` defined in [`core/server/server.go`](https://github.com/apernet/hysteria/blob/main/core/server/server.go).
- **Client setup** involves configuring `client.Config` with server addresses and credentials, then using `client.NewClient()` to obtain TCP/UDP proxy interfaces.
- Key source files include [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) for validation logic, [`core/server/server.go`](https://github.com/apernet/hysteria/blob/main/core/server/server.go) for QUIC listener management, and [`core/client/client.go`](https://github.com/apernet/hysteria/blob/main/core/client/client.go) for handshake implementation.
- Extension interfaces (`Outbound`, `RequestHook`, `TrafficLogger`) enable custom routing, packet inspection, and bandwidth management without modifying underlying QUIC code in `core/internal/protocol`.

## Frequently Asked Questions

### What is the difference between the Hysteria core module and the CLI application?

The **core module** (`core/`) provides programmatic Go APIs for embedding Hysteria into applications, while the **CLI** (`app/`) offers a standalone binary with configuration file support. The core exposes interfaces like `Authenticator` and `Outbound` for customization, whereas the CLI wraps these with command-line flags and YAML parsing.

### How do I implement custom authentication when setting up a Hysteria server?

Implement the `Authenticator` interface defined in [`core/server/config.go`](https://github.com/apernet/hysteria/blob/main/core/server/config.go) with an `Authenticate(net.Addr, string, uint64)` method. This receives the client's address, authentication token, and claimed bandwidth. Return `true` and a user ID to accept the connection, or `false` to reject. You can also implement `TrafficLogger` to enforce per-user quotas by returning `false` in `LogTraffic` when limits are exceeded.

### Can I use self-signed certificates with the Hysteria core client?

Yes. When configuring `client.Config`, set `TLSConfig.InsecureSkipVerify: true` to bypass certificate validation, which is useful for testing with self-signed certs. For production, populate `TLSConfig.ServerName` and the root CA pool to verify against your private certificate authority.

### Which congestion control algorithms are available in the Hysteria core module?

According to `core/internal/congestion/`, the core supports **BBR** and **Cubic** congestion controllers. Configure this via `client.Config.CongestionConfig` or server-side defaults in `server.Config`. BBR is recommended for high-latency networks, while Cubic provides traditional TCP-friendly behavior.