A modern, simple TCP tunnel in Rust that exposes local ports to a remote server,...

A modern, simple TCP tunnel in Rust that exposes local ports to a remote server, bypassing standard NAT connection firewalls


. That's all it does: no more, and no less.

# Installation (requires Rust, see alternatives below)
cargo install bore-cli

# On your local machine
bore local 8000 --to bore.pub

This will expose your local port at localhost:8000 to the public internet at bore.pub:<PORT>, where the port number is assigned randomly.

Similar to localtunnel and ngrok, except bore is intended to be a highly efficient, unopinionated tool for forwarding TCP traffic that is simple to install and easy to self-host, with no frills attached.

(bore totals less than 400 lines of safe, async Rust code and is trivial to set up — just run a single binary for the client and server.)


If you're on macOS, bore is packaged as a Homebrew formula.

brew install ekzhang/bore/bore

Otherwise, the easiest way to install bore is from prebuilt binaries. These are available on the releases page for macOS, Windows, and Linux. Just unzip the appropriate file for your platform and move the bore executable into a folder on your PATH.

You also can build bore from source using Cargo, the Rust package manager. This command installs the bore binary at a user-accessible path.

cargo install bore-cli

We also publish versioned Docker images for each release. Each image is built for AMD 64-bit and Arm 64-bit architectures. They're tagged with the specific version and allow you to run the statically-linked bore binary from a minimal "scratch" container.

docker run -it --init --rm --network host ekzhang/bore <ARGS>

Detailed Usage

This section describes detailed usage for the bore CLI command.

Local Forwarding

You can forward a port on your local machine by using the bore local command. This takes a positional argument, the local port to forward, as well as a mandatory --to option, which specifies the address of the remote server.

bore local 5000 --to bore.pub

You can optionally pass in a --port option to pick a specific port on the remote to expose, although the command will fail if this port is not available. Also, passing --local-host allows you to expose a different host on your local area network besides the loopback address localhost.

The full options are shown below.

bore-local 0.4.0
Starts a local proxy to the remote server

    bore local [OPTIONS] --to <TO> <LOCAL_PORT>

    <LOCAL_PORT>    The local port to expose

    -h, --help                 Print help information
    -l, --local-host <HOST>    The local host to expose [default: localhost]
    -p, --port <PORT>          Optional port on the remote server to select [default: 0]
    -s, --secret <SECRET>      Optional secret for authentication [env: BORE_SECRET]
    -t, --to <TO>              Address of the remote server to expose local ports to
    -V, --version              Print version information


As mentioned in the startup instructions, there is a public instance of the bore server running at bore.pub. However, if you want to self-host bore on your own network, you can do so with the following command:

bore server

That's all it takes! After the server starts running at a given address, you can then update the bore local command with option --to <ADDRESS> to forward a local port to this remote server.

The full options for the bore server command are shown below.

bore-server 0.4.0
Runs the remote proxy server

    bore server [OPTIONS]

    -h, --help                   Print help information
        --min-port <MIN_PORT>    Minimum TCP port number to accept [default: 1024]
    -s, --secret <SECRET>        Optional secret for authentication [env: BORE_SECRET]
    -V, --version                Print version information


There is an implicit control port at 7835, used for creating new connections on demand. At initialization, the client sends a "Hello" message to the server on the TCP control port, asking to proxy a selected remote port. The server then responds with an acknowledgement and begins listening for external TCP connections.

Whenever the server obtains a connection on the remote port, it generates a secure UUID for that connection and sends it back to the client. The client then opens a separate TCP stream to the server and sends an "Accept" message containing the UUID on that stream. The server then proxies the two connections between each other.

For correctness reasons and to avoid memory leaks, incoming connections are only stored by the server for up to 10 seconds before being discarded if the client does not accept them.


On a custom deployment of bore server, you can optionally require a secret to prevent the server from being used by others. The protocol requires clients to verify possession of the secret on each TCP connection by answering random challenges in the form of HMAC codes. (This secret is only used for the initial handshake, and no further traffic is encrypted by default.)

# on the server
bore server --secret my_secret_string

# on the client
bore local <LOCAL_PORT> --to <TO> --secret my_secret_string

If a secret is not present in the arguments, bore will also attempt to read from the BORE_SECRET environment variable.


Created by Eric Zhang (@ekzhang1). Licensed under the MIT license.

The author would like to thank the contributors and maintainers of the Tokio project for making it possible to write ergonomic and efficient network services in Rust.


Collection of the latest Issues



Comment Icon0

Since most users will have setup their own bore server, this server will likely not change a lot. However users are still required to always specify the server they want to forward to.

I would suggest reading from an environment variable (BORE_SERVER for example) when the --to option is omitted.


Find the latest versions by id

v0.4.0 - Apr 22, 2022

This release of bore finally distributes the CLI via prebuilt binaries! If you scroll down to the "Assets" attached to the release, you can now download bore and install instantly it by just adding a single file to your PATH. No need to build from source using Rust (cargo install) anymore. Big thanks to @praveenperera for making this happen.


This release also makes internal improvements, using the tokio-util codec library to avoid possibly unbounded memory usage if a malicious client were to stream arbitrarily long frames to the server.

What's Changed

New Contributors

Full Changelog: https://github.com/ekzhang/bore/compare/v0.3.0...v0.4.0

v0.3.0 - Apr 14, 2022

This release makes it possible for bore to expose any address on your local area network, not just localhost. For example, if you have an ssh daemon running on a computer on your network at, then you could forward that using something like:

Then, using the port returned, you could connect to your printer from the public Internet with ssh bore.pub:<PORT>.

We also now allow the secret to be passed in via the BORE_SECRET environment variable, and the package has been updated to depend on a minimal set of features in tokio, which should make build times slightly shorter.

Standalone binary builds are in development but not complete yet.

What's Changed

New Contributors

Full Changelog: https://github.com/ekzhang/bore/compare/v0.2.3...v0.3.0

v0.2.3 - Apr 11, 2022

This release makes it possible to run bore from a 6 MB Docker image using a single command.

The image is built for multiple platforms (amd64, arm64) and contains a single statically-linked binary executable. They're published on Docker Hub with version tags like ekzhang/bore:latest, ekzhang/bore:0.2, and ekzhang/bore:0.2.3.

Releasing standalone binary builds is planned starting with bore v0.3.0.

What's Changed

New Contributors

Full Changelog: https://github.com/ekzhang/bore/compare/v0.2.1...v0.2.3

v0.2.1 - Apr 09, 2022

What's Changed

New Contributors

Full Changelog: https://github.com/ekzhang/bore/compare/v0.2.0...v0.2.1

v0.2.0 - Apr 08, 2022

What's Changed

New Contributors

Full Changelog: https://github.com/ekzhang/bore/compare/v0.1.1...v0.2.0

Information - Updated Aug 01, 2022

Stars: 4.9K
Forks: 123
Issues: 3

Repositories & Extras

Rust bindings for libinjection

Add libinjection to dependencies of Cargo

Rust bindings for libinjection

Rust bindings for the C++ api of PyTorch

LIghtweight wrapper for pytorch eg libtorch in rust

Rust bindings for the C++ api of PyTorch

Rust leveldb bindings

Almost-complete bindings for leveldb for Rust

Rust leveldb bindings

Rust-Lightning is a Bitcoin Lightning library written in Rust

lightning, does not handle networking, persistence, or any other I/O

Rust-Lightning is a Bitcoin Lightning library written in Rust

P2P Rollback Networking in Rust

GGRS (good game rollback system) is a reimagination of the Rust 🦀

P2P Rollback Networking in Rust

Cardano Rust Ouroboros Network

This crate implements the networking layer for the Ouroboros blockchain protocol

Cardano Rust Ouroboros Network

An experimental project for using Golioth (currently just) on the nRF9160

This project is currently in a holding pattern until the Embedded Rust ecosystem has caught up to the necessary networking support

An experimental project for using Golioth (currently just) on the nRF9160

Painless peer-to-peer WebRTC networking for rust wasm applications

The goal of the Matchbox project is to enable udp-like, unordered, unreliable

Painless peer-to-peer WebRTC networking for rust wasm applications

Here lies my attempt to create a multi thread webserver based off of Rust and...

Here lies my attempt to create a multi thread webserver based off of Rust and using HTTP and TCP networking protocols :)

Here lies my attempt to create a multi thread webserver based off of Rust and...

Utilities for networking in rust with tokio

This does not have a well-defined or finished API yet, so breaking changes will be counted as minor changes before release v1

Utilities for networking in rust with tokio

Rust Data Transfer Protocol

Asynchronous cross-platform networking interfaces for Rust

Rust Data Transfer Protocol
Facebook Instagram Twitter GitHub Dribbble