# How to Update Hysteria Core to the Latest Version: 3 Methods Explained

> Keep Hysteria core updated to the latest version with these 3 methods: check update command, automatic checks, or the official install script. Ensure optimal performance and security.

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

---

**You can update Hysteria core using the built-in `check-update` command, rely on automatic 24-hour background checks, or execute the official install script from [`scripts/install_server.sh`](https://github.com/apernet/hysteria/blob/main/scripts/install_server.sh).**

Hysteria provides multiple mechanisms to keep its core binary current, ranging from manual CLI commands to fully automatic background updates. Whether you are running a server or client instance, the repository at `apernet/hysteria` ensures you can quickly verify and install the latest release without manual binary management. This guide covers all update pathways using the actual source implementation.

## Method 1: Using the Built-In Update Command

The fastest way to manually verify your version is through the `check-update` subcommand defined in [`app/cmd/update.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/update.go). This command constructs an `UpdateChecker` instance and queries the Hysteria update API to compare your current build against the latest release.

When you invoke `hysteria check-update`, the application executes the check immediately and prints the results. For server deployments, the code uses `utils.NewServerUpdateChecker`, while client deployments use `utils.NewClientUpdateChecker` to route the request through the active Hysteria connection, preventing SNI fingerprinting by censors.

```bash

# Display current installed version

hysteria version

# Check for available updates

hysteria check-update

```

## Method 2: Automatic Background Updates

Hysteria can automatically check for updates every 24 hours without user intervention. This mechanism is implemented in [`app/cmd/update.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/update.go) through the functions `runCheckUpdateServer` and `runCheckUpdateClient`, which spawn a background goroutine executing `checkUpdateRoutine`.

The routine creates a `time.NewTicker(updateCheckInterval)` set to 24 hours and repeatedly queries the update API. When an update is available, the process logs the new version, download URL, and urgency flag.

To disable this behavior, pass the `--disable-update-check` flag defined in [`app/cmd/root.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/root.go):

```bash

# Start server with automatic update checks disabled

hysteria --disable-update-check server -c config.yaml

```

## Method 3: Updating via the Install Script

For server administrators, the [`scripts/install_server.sh`](https://github.com/apernet/hysteria/blob/main/scripts/install_server.sh) bash script provides a complete update workflow. The script detects your environment, compares the installed version against the latest release using the `vercmp` function, and handles binary replacement automatically.

The script supports three operational modes:

- **Check mode** (`-c` or `--check`): Verifies if an update is available without installing
- **Install mode** (default): Downloads and installs the latest binary via `download_hysteria` only if newer than the current version
- **Force mode** (`-f` or `--force`): Re-installs the binary even when `get_installed_version` matches `get_latest_version`

```bash

# Check only without installing

curl -sSL https://get.hy2.sh | bash -s -- --check

# Standard update (or fresh install)

curl -sSL https://get.hy2.sh | bash -s --

# Force reinstallation regardless of current version

curl -sSL https://get.hy2.sh | bash -s -- -f

```

The script places the binary at `/usr/local/bin/hysteria` by default.

## Understanding the Update Mechanism

The core update logic resides in [`app/internal/utils/update.go`](https://github.com/apernet/hysteria/blob/main/app/internal/utils/update.go) within the `UpdateChecker` struct. Understanding this implementation helps diagnose connectivity or version-check failures.

**API Endpoint and Request Structure**

The checker sends a GET request to `https://api.hy2.io/v1/update` with query parameters encoding the current version, platform, architecture, channel, and side (server or client):

```go
const updateCheckEndpoint = "https://api.hy2.io/v1/update"
url := fmt.Sprintf("%s?cver=%s&plat=%s&arch=%s&chan=%s&side=%s",
    updateCheckEndpoint, uc.CurrentVersion, uc.Platform,
    uc.Architecture, uc.Channel, uc.Side)
resp, err := uc.Client.Get(url)

```

**Response Handling**

The API returns a JSON `UpdateResponse` containing:

- `update`: Boolean indicating if a newer version exists
- `lver`: Latest version string (e.g., "v2.6.0")
- `url`: Direct download URL for the new binary
- `urgent`: Boolean flag marking critical security updates

**Transport Differences**

- **Server checks** use a standard `http.Client` instantiated via `NewServerUpdateChecker`
- **Client checks** route HTTP requests through the active Hysteria connection using `NewClientUpdateChecker`, ensuring the update check traffic is indistinguishable from regular data and cannot be blocked by simple SNI filters

## Programmatic Update Checks

You can integrate update checking into custom Go applications using the `UpdateChecker` utilities. This is useful for building management dashboards or monitoring tools that track version drift across deployments.

```go
import (
    "fmt"
    "github.com/apernet/hysteria/app/internal/utils"
    "github.com/apernet/hysteria/core/v2/client"
)

func checkForUpdate(hyClient client.Client) {
    // Create checker for client side (tunnelled through hyClient)
    checker := utils.NewClientUpdateChecker(
        "v2.5.1", "linux", "amd64", "release", hyClient,
    )
    
    resp, err := checker.Check()
    if err != nil {
        panic(err)
    }
    
    if resp.HasUpdate {
        fmt.Printf("New version %s available: %s\n", 
            resp.LatestVersion, resp.URL)
    } else {
        fmt.Println("You are on the latest version.")
    }
}

```

## Summary

- Use `hysteria check-update` for immediate manual checks via the Cobra command in [`app/cmd/update.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/update.go)
- Automatic background checks run every 24 hours via `checkUpdateRoutine` unless disabled with the `--disable-update-check` flag
- The install script at [`scripts/install_server.sh`](https://github.com/apernet/hysteria/blob/main/scripts/install_server.sh) handles complete server upgrades using `get_latest_version` and `vercmp` logic
- Server and client instances use different transport methods: plain HTTP for servers, tunneled connections for clients to avoid censorship
- All mechanisms query `https://api.hy2.io/v1/update` and return structured `UpdateResponse` data containing version, URL, and urgency indicators

## Frequently Asked Questions

### How often does Hysteria check for updates automatically?

Hysteria checks for updates once every 24 hours when the automatic background ticker is enabled. This interval is hardcoded as `updateCheckInterval` in [`app/cmd/update.go`](https://github.com/apernet/hysteria/blob/main/app/cmd/update.go). The check runs in a separate goroutine started by either `runCheckUpdateServer` or `runCheckUpdateClient` after the main process initializes, ensuring the binary stays current without user interaction.

### What is the difference between server and client update checking?

Server update checks use a standard HTTP client that connects directly to the update API via `NewServerUpdateChecker`, while client checks route the request through the active Hysteria connection using `NewClientUpdateChecker`. This tunneling approach prevents censors from detecting update checks through SNI fingerprinting or blocking the update API endpoint separately from the proxy traffic.

### Can I update Hysteria without stopping the service?

The install script ([`scripts/install_server.sh`](https://github.com/apernet/hysteria/blob/main/scripts/install_server.sh)) downloads the new binary to a temporary location and replaces the executable at `/usr/local/bin/hysteria`, but you must restart the service to load the new binary into memory. For zero-downtime updates, deploy the new binary alongside the running instance, swap the files, and trigger a graceful restart via your process manager or init system.

### Why does the install script report the latest version is already installed when I want to force an update?

The install script compares versions using the `vercmp` function and skips the `download_hysteria` step if the installed version matches the latest release. To force a reinstallation regardless of the current version, use the `-f` or `--force` flag when running the script, which bypasses the version comparison and executes the download and installation routine immediately.