SkillAgentSearch skills...

Connet

A p2p reverse proxy with NAT traversal. Inspired by frp, rathole and ngrok

Install / Use

/learn @connet-dev/Connet
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

connet

GitHub release Go Reference Go Report Card Apache2.0 licensed

connet is a peer-to-peer reverse proxy for NAT traversal. It is inspired by ngrok, frp, rathole and others.

connet helps expose a service running on a device to another device on the internet. Unlike the others, the connet client runs on both the device that exposes the service (called destination in connet's terms) and the device that wants to access the service (called source). This means that communication between connet clients is never public and visible to the rest of the internet, and in many cases peers can communicate directly.

Status connet is currently alpha software. We expect some issues and its APIs are subject to change.

Features

  • Peer-to-peer communication Because you run the connet client on both the destination and the source, the server is only used for sharing configuration. In many cases clients can communicate directly, which enables better privacy and performance.
  • Relay support There are cases when clients are unable to find a path to communicate directly. In such cases, they can use a relay server to maintain connectivity.
  • Security Everything is private, encrypted with TLS. Public server and client certificates are exchanged between peers and are required and verified to establish connectivity. Clients and relays need to present a mandatory token when communicating with the control server, allowing tight control over who can use connet.
  • Embeddable In case you want connet running as part of another (golang) program (as opposed to a separate executable), connet has a well defined API for running both the client and the server.

Architecture

flowchart LR
    subgraph Server
    C(Control Server)
    R(Relay Server)
    C -.->|Relay Info| R
    end
    subgraph Client Source
    S[Source] -->|Exchange Direct and Relay Info| C(Control Server)
    SC(Client) -..-> S
    end
    subgraph Client Destination
    D[Destination] -->|Exchange Direct and Relay Info| C(Control Server)
    D -..-> DC(Server)
    end
    S ---|Direct Connection| D
    S -->|Relay Connection| R
    R -->|Relay Connection| D

For all communication connet uses the QUIC protocol, which is built on top of UDP.

Quickstart

Latest builds of connet can be acquired from our releases page. We also provide docker images, check our docker section to see how you can use them. For NixOS, check the NixOS section.

To get started with connet, you'll need 3 devices:

  • Server which your clients can communicate with. In most cases, this server will have a public IP and be directly accessible by clients. A VPS instance at one of the many cloud providers goes a long way here.
  • Device D that has the destination service you want to connect to, running at port 3000.
  • Device S (aka source) which you want to connect to the service, at port 8000.

Server

In the setup above, start connet server --config server.toml with the following server.toml:

[server]
tokens = ["client-d-token", "client-s-token"]

[[server.ingress]]
cert-file = "cert.pem"
key-file = "key.pem"

TLS Certificates

To run a connet server, you'll need a TLS certificate. You have a few options to create such certificate:

  • Recommended use an ACME client to provision one for you. We've had good experiences running lego.
  • Buy a TLS certificate from a Certificate Authority like verisign, namecheap, etc.
  • Use a self-signed TLS certificate, an option most appropriate for testing.

To create a self-signed certificate, you can use openssl. Alternatively, you can use a tool like minica. When using self-signed certificate, you'll need your clients (and relays) trusting the server's certificate. Copying the certificate (or CA) public key to the clients and using server-cas-file configuration option is the easiest way to achieve this.

Client D (aka the destination)

Then, on device D run connet --config destination.toml with the following config:

# destination.toml
[client]
token = "client-d-token"
server-addr = "SERVER_IP:19190"
server-cas-file = "cert.pem"

[client.destinations.serviceA]
url = "tcp://:3000"

Client S (aka the source)

On device S run connet --config source.toml with the following config:

# source.toml
[client]
token = "client-s-token"
server-addr = "SERVER_IP:19190"
server-cas-file = "cert.pem"

[client.sources.serviceA]
url = "tcp://:8000"

Configuration

You can use both a toml config file as well as command line when running connet. If you use both a config file and command line options, the latter takes precedence, overriding any config file options. For simplicity, command line options only support a single destination or source configuration.

Client

To run a client, use connet --config client.toml command. Here is the full client client.toml configuration specification:

[client]
token-file = "path/to/relay/token" # file that contains the auth token for the control server
token = "client-token-1" # auth token for the control server (fallback when 'token-file' is not specified)
# if both 'token-file' and 'token' are empty, will read 'CONNET_TOKEN' environment variable
metadata = "home" # metadata sent when authenticating to help identify this client

server-addr = "localhost:19190" # control server address (UDP/QUIC, host:port) (defaults to '127.0.0.1:19190')
server-cas-file = "path/to/cert.pem" # control server TLS certificate authorities file, when not using public CAs
server-name = "localhost" # control server name (UDP/QUIC, host), when connecting via IP and certificate includes only domains (defaults to the host in 'server-addr')

direct-addr = ":19192" # direct server address to listen for peer connections (UDP/QUIC, [host]:port) (defaults to ':19192')
direct-stateless-reset-key = "" # the QUIC stateless reset key as a literal 32 byte value in base32hex format
direct-stateless-reset-key-file = "/path/to/reset/key" # the QUIC stateless reset key read from a file

status-addr = "127.0.0.1:19182" # status server address to listen for connections (TCP/HTTP, [host]:port) (disabled by default)
nat-pmp = "system" # support for NAT-PMP, defaults to `system`
handshake-idle-timeout = "1m" # handshake idle timeout (QUIC, duration), when there is a high latency to connect (defaults to 5s)

relay-encryptions = ["none"] # require encryption when using relay for all destination/sources, defaults to "none"

[client.destinations.serviceX]
route = "any" # what kind of routes to use, `any` will use both `direct` and `relay`
relay-encryptions = ["tls", "dhxcp"] # require `tls` or `dhxcp` encryption when using relay for this destination
proxy-proto-version = "" # proxy proto version to push origin information to the server, supports `v1` and `v2`
dial-timeout = "2s" # if URL is network connection, how long to wait for connection to establish (defaults to 0, wait forever)
url = "tcp://localhost:3000" # URL to which destination connects to, over tcp
# other options for the url field:
url = "tls://localhost:3000" # a TLS destination to connect to
url = "http://localhost:3000/path" # an HTTP destination to connect to as a reverse proxy, path rewrite included
url = "https://localhost:3000" # an HTTPS destination to connect to as a reverse proxy
url = "file:///absolute/path" # an absolute file path to serve over HTTP
url = "file:./relative/path" # a relative file path to serve over HTTP
cas-file = "/path/to/cas/file" # if connecting via TLS/HTTPS, certificate authorities if not publicly trusted
                               # `insecure-skip-verify` is a special value, to not verify self-signed certificates
cert-file = "/path/to/cert/file" # when connecting via TLS/HTTPS, client certificate to present (mutual TLS)
key-file = "/path/to/key/file" # when connecting via TLS/HTTPS, client certificate private key to present (mutual TLS)

[client.destinations.serviceY]
route = "direct" # force only direct communication between clients
url = "tcp://192.168.1.100:8000"

[client.sources.serviceX] # matches destinations.serviceX
route = "relay" # the kind of route to use
relay-encryptions = ["dhxcp"] # require `dhxcp` encryption when using relay for this source
url = "tcp://:8000" # URL for the source to listen for incoming connections to be forwarded
# other options for the url field:
url = "tls://:8003" # runs a TLS source server
url = "http://:8080/path" # runs an HTTP reverse proxy source server, path rewrite
url = "https://:8443" # runs an HTTPS reverse proxy source server
url = "ws://127.0.0.1:8080" # runs websocket tcp converter that exposes the destinations conn as a websocket
url = "wss://127.0.0.1:8083" # same as above, but exposes it on HTTPS
cert-file = "/path/to/cert/file" # the TLS/HTTPS server certificate to use
key-file = "/path/to/key/file" # the TLS/HTTPS server certificate private key to use
cas-file = "/path/to/cas/file" # the TLS/HTTPS client certificates to trust (mutual TLS)
dial-timeout = "5s" # how long to wait for single destination connection, defaults to 0 (wait forever)
lb-policy = "" # the load balancer policy, defaults to '' (none)
l
View on GitHub
GitHub Stars517
CategoryDevelopment
Updated8d ago
Forks14

Languages

Go

Security Score

100/100

Audited on Mar 26, 2026

No findings