Top Related Projects
Minimal, self-hosted, 0-config alternative to ngrok. Caddy+OpenSSH+50 lines of Python.
Easily and securely send things from one computer to another :crocodile: :package:
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
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:
-
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.
-
Install the
bore
command-line tool using Cargo, Rust's package manager:cargo install bore
-
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". -
(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
-
(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.
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.
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.
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 designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
bore
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 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.
Top Related Projects
Minimal, self-hosted, 0-config alternative to ngrok. Caddy+OpenSSH+50 lines of Python.
Easily and securely send things from one computer to another :crocodile: :package:
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
Unified ingress for developers
expose yourself
Expose your local web server to the internet with a public URL.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot