Convert Figma logo to code with AI

ekzhang logobore

🕳 bore is a simple CLI tool for making tunnels to localhost

8,424
337
8,424
1

Top Related Projects

Minimal, self-hosted, 0-config alternative to ngrok. Caddy+OpenSSH+50 lines of Python.

27,614

Easily and securely send things from one computer to another :crocodile: :package:

85,378

A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.

24,128

Unified ingress for developers

expose yourself

Expose your local web server to the internet with a public URL.

Quick Overview

bore is a lightweight and fast HTTP/HTTPS tunnel written in Rust. It allows you to securely expose a local server to the internet, making it useful for development, testing, and other scenarios where you need to access a local service from a remote location.

Pros

  • Lightweight and Fast: bore is written in Rust, which provides excellent performance and low resource usage.
  • Cross-Platform: bore supports Windows, macOS, and Linux, making it a versatile tool.
  • Secure: bore uses HTTPS by default, ensuring secure communication between the local server and the remote client.
  • Easy to Use: bore has a simple command-line interface and can be easily integrated into various development workflows.

Cons

  • Limited Features: bore is a focused tool and may not provide the same level of functionality as more feature-rich alternatives.
  • Dependency on Rust: Users who are not familiar with Rust may need to invest time in learning the language to contribute to the project or customize it.
  • Potential Complexity: Setting up and configuring bore may require some technical knowledge, especially for more advanced use cases.
  • Limited Documentation: The project's documentation could be more comprehensive, which may make it harder for new users to get started.

Code Examples

use bore::tunnel;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tunnel = tunnel::Tunnel::new("my-tunnel", "localhost:8080")
        .with_subdomain("my-subdomain")
        .build();

    tunnel.start().await?;
    Ok(())
}

This code creates a new Tunnel instance, configures it with a name and a local server address, and then starts the tunnel.

use bore::tunnel;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tunnel = tunnel::Tunnel::new("my-tunnel", "localhost:8080")
        .with_subdomain("my-subdomain")
        .with_auth("username", "password")
        .build();

    tunnel.start().await?;
    Ok(())
}

This example is similar to the previous one, but it also adds basic authentication to the tunnel, requiring clients to provide a username and password to access the local server.

use bore::tunnel;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tunnel = tunnel::Tunnel::new("my-tunnel", "localhost:8080")
        .with_subdomain("my-subdomain")
        .with_tls_cert("path/to/cert.pem", "path/to/key.pem")
        .build();

    tunnel.start().await?;
    Ok(())
}

This example demonstrates how to configure the tunnel to use custom TLS certificates, which can be useful for scenarios where you need to use a specific SSL/TLS setup.

Getting Started

To get started with bore, follow these steps:

  1. Install Rust on your system if you haven't already. You can download it from the official Rust website: https://www.rust-lang.org/tools/install.

  2. Install the bore command-line tool using Cargo, Rust's package manager:

    cargo install bore
    
  3. Start the tunnel by running the following command:

    bore tunnel --name my-tunnel --local localhost:8080 --subdomain my-subdomain
    

    This will create a tunnel named "my-tunnel" that exposes your local server running on localhost:8080 to the internet using the subdomain "my-subdomain.bore.pub".

  4. (Optional) To add basic authentication to the tunnel, use the --auth flag:

    bore tunnel --name my-tunnel --local localhost:8080 --subdomain my-subdomain --auth username:password
    
  5. (Optional) To use custom TLS certificates, use the --tls-cert and --tls-key flags

Competitor Comparisons

Minimal, self-hosted, 0-config alternative to ngrok. Caddy+OpenSSH+50 lines of Python.

Pros of SirTunnel

  • Written in Rust, potentially offering better performance and memory safety
  • Supports WebSocket connections, allowing for real-time bidirectional communication
  • Designed with a focus on simplicity and ease of use

Cons of SirTunnel

  • Less actively maintained, with fewer recent updates compared to bore
  • Limited documentation and examples available
  • Smaller community and fewer stars on GitHub, potentially indicating less adoption

Code Comparison

SirTunnel:

let listener = TcpListener::bind("127.0.0.1:8080").await?;
let (stream, _) = listener.accept().await?;
let ws_stream = accept_async(stream).await?;

bore:

let server = Server::new(addr).await?;
let tunnel = server.tunnel(local_addr, remote_port).await?;
tunnel.wait().await?;

Both projects aim to provide tunneling solutions, but they differ in their approach and implementation. SirTunnel focuses on WebSocket connections and is written in Rust, potentially offering better performance. However, it has less active development and a smaller community compared to bore. bore, on the other hand, appears to have more recent updates and a larger user base, which could translate to better support and documentation. The code comparison shows that both projects use async Rust, but SirTunnel's example demonstrates WebSocket handling, while bore's example showcases its tunneling functionality.

27,614

Easily and securely send things from one computer to another :crocodile: :package:

Pros of Croc

  • Designed specifically for secure file transfer between devices
  • Supports end-to-end encryption and password protection
  • Includes built-in relay servers for NAT traversal

Cons of Croc

  • Limited to file transfer use case
  • May have higher latency due to relay servers
  • More complex setup for custom relay servers

Code Comparison

Croc (file transfer):

send := croc.Send{
    SharedSecret: "your-secret-code",
    Files:        []string{"path/to/file"},
}
err := send.Run()

Bore (TCP tunneling):

let tunnel = TcpTunnel::new("example.com:1234", 8080)?;
tunnel.run().await?;

Key Differences

Croc focuses on secure file transfer between devices, while Bore is a TCP tunneling tool for exposing local servers. Croc offers end-to-end encryption and built-in relay servers, making it more suitable for transferring sensitive data. Bore, on the other hand, provides a simpler solution for creating TCP tunnels, which can be used for various networking scenarios beyond file transfer.

Croc's implementation is in Go, while Bore is written in Rust. This may affect performance characteristics and ecosystem compatibility. Bore's simpler architecture potentially offers lower latency for general TCP tunneling, while Croc's relay-based approach ensures better NAT traversal at the cost of potential increased latency.

85,378

A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.

Pros of frp

  • More comprehensive feature set, including TCP/UDP forwarding, HTTP/HTTPS tunneling, and load balancing
  • Supports multiple protocols and transport layers
  • Offers a web-based dashboard for easier management

Cons of frp

  • More complex setup and configuration
  • Larger codebase, potentially leading to more maintenance and security concerns
  • Higher resource usage due to additional features

Code Comparison

frp configuration example:

[common]
server_addr = x.x.x.x
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

bore usage example:

bore local 8000 --to bore.pub

Key Differences

  • frp offers a more feature-rich solution for various networking scenarios, while bore focuses on simplicity and ease of use for basic port forwarding
  • frp requires more configuration and setup, whereas bore can be quickly deployed with minimal configuration
  • frp supports multiple protocols and advanced features, while bore is primarily designed for simple TCP tunneling
  • bore is written in Rust, potentially offering better performance and memory safety, while frp is written in Go

Both projects aim to solve similar problems but cater to different use cases and complexity levels.

24,128

Unified ingress for developers

Pros of ngrok

  • More established and widely used, with a larger community and ecosystem
  • Offers additional features like authentication, API access, and custom domains
  • Provides a user-friendly web interface for managing tunnels

Cons of ngrok

  • Closed-source and proprietary, limiting customization and self-hosting options
  • Free tier has limitations on usage and features
  • Can be more complex to set up and configure for advanced use cases

Code Comparison

ngrok:

ngrok http 8080

bore:

bore local 8080 --to bore.pub

Both tools provide simple command-line interfaces for creating tunnels, but bore's syntax is slightly more explicit about the local port and remote server.

Key Differences

  • bore is open-source and written in Rust, while ngrok is closed-source
  • ngrok offers a wider range of features and integrations
  • bore focuses on simplicity and performance, with a lightweight design
  • ngrok has a freemium model with paid tiers, while bore is completely free

Use Cases

ngrok is well-suited for:

  • Developers needing advanced features and integrations
  • Teams requiring centralized management and access controls

bore is ideal for:

  • Developers preferring open-source solutions
  • Users needing a lightweight, fast tunneling option
  • Projects requiring customization or self-hosting capabilities

expose yourself

Pros of localtunnel

  • Longer history and more established project with a larger user base
  • Simpler setup process, especially for beginners
  • Supports custom subdomains for easier sharing and remembering URLs

Cons of localtunnel

  • Less performant compared to Bore, especially for larger file transfers
  • Requires a centralized server, which can be a single point of failure
  • Limited configuration options for advanced users

Code Comparison

localtunnel:

const localtunnel = require('localtunnel');

(async () => {
  const tunnel = await localtunnel({ port: 3000 });
  console.log(tunnel.url);
})();

Bore:

use bore_cli::{client, BoreholeBuilder};

let borehole = BoreholeBuilder::new()
    .port(3000)
    .to("bore.pub:2200")
    .build()?;
client::connect(borehole).await?;

Both projects aim to expose local servers to the internet, but Bore focuses on performance and security, while localtunnel prioritizes ease of use and flexibility. Bore is written in Rust, offering better performance, while localtunnel is JavaScript-based, making it more accessible to web developers. Choose based on your specific needs and technical expertise.

Expose your local web server to the internet with a public URL.

Pros of tunnelto

  • Written in Rust, potentially offering better performance and memory safety
  • Provides a web dashboard for managing tunnels and viewing logs
  • Offers a free tier with limited features

Cons of tunnelto

  • Closed-source backend, limiting customization and self-hosting options
  • Requires account creation and authentication for usage
  • May have usage limitations on the free tier

Code Comparison

tunnelto:

let tunnel = TunnelBuilder::new()
    .with_port(8080)
    .with_subdomain("myapp")
    .build()?;

tunnel.start().await?;

bore:

let server = TcpListener::bind("0.0.0.0:8080").await?;
let bore = Bore::new(server, "bore.pub:7835").await?;
bore.run().await?;

Both projects aim to provide easy-to-use tunneling solutions, but they differ in their approach and features. tunnelto offers a more user-friendly experience with its web dashboard and managed service, while bore focuses on simplicity and open-source flexibility. The code comparison shows that both projects have straightforward APIs for creating tunnels, with tunnelto offering more configuration options upfront. Ultimately, the choice between the two depends on the user's specific needs, such as the desire for a managed service versus a self-hosted solution.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

bore

Build status Crates.io

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.

Video demo

# 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 about 400 lines of safe, async Rust code and is trivial to set up — just run a single binary for the client and server.)

Installation

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

brew install bore-cli

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. The image is built for an AMD 64-bit architecture. 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.

Starts a local proxy to the remote server

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

Arguments:
  <LOCAL_PORT>  The local port to expose

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

Self-Hosting

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.

Runs the remote proxy server

Usage: bore server [OPTIONS]

Options:
      --min-port <MIN_PORT>  Minimum accepted TCP port number [default: 1024]
      --max-port <MAX_PORT>  Maximum accepted TCP port number [default: 65535]
  -s, --secret <SECRET>      Optional secret for authentication [env: BORE_SECRET]
  -h, --help                 Print help information

Protocol

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.

Authentication

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.

Acknowledgements

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.