How to Serve Croc's Web Client with a Custom Upstream Relay
You can serve the croc web client against a custom upstream relay by configuring the RelayHost, RelayPassword, and AllowedPorts fields in the webrelay.Config struct before passing it to webrelay.Run or webrelay.Handler.
The croc secure file transfer tool provides a browser-based web client that normally connects to the default public relay at croc.schollz.com. According to the schollz/croc source code, the webrelay package implements this functionality as a static-file server combined with a WebSocket-to-TCP bridge, allowing you to redirect traffic to any private relay infrastructure by modifying the runtime configuration.
Architecture of the WebRelay Package
The webrelay package ([src/webrelay/webrelay.go](https://github.com/schollz/croc/blob/main/src/webrelay/webrelay.go)) serves the embedded web UI and proxies connections to an upstream TCP relay. It never participates in the croc protocol itself; it merely forwards opaque byte streams between the browser's WebSocket and the relay's TCP ports.
Key components include:
Configstruct (webrelay/webrelay.go:32-42) – Holds runtime options includingRelayHost,RelayPassword,AllowedPorts,OriginPatterns, and the embedded static file system.Handlerfunction (webrelay/webrelay.go:59-93) – Normalizes configuration, builds the static file handler, and wires routes for/healthz,/config.js,/ws, and the root path into anhttp.ServeMux.websocketmethod (webrelay/webrelay.go:140-220) – Validates the requested port againstAllowedPorts, dials the upstream relay, upgrades the HTTP connection to a WebSocket, and proxies bidirectional traffic.newStaticHandler(webrelay/webrelay.go:300-318) – Serves the embedded UI assets from thewebassetsvirtual file system.
Configuring a Custom Upstream Relay
To use a custom upstream relay, you must override the default values in a webrelay.Config instance. The defaults are:
RelayHost:"croc.schollz.com"RelayPassword:"pass123"AllowedPorts:[]string{"9009","9010","9011","9012","9013","9014","9015","9016","9017"}
Changing these fields directs the WebSocket bridge to forward traffic to your specified relay. The static UI, health checks, and configuration endpoints remain functional regardless of the upstream target.
Required Configuration Fields
When preparing your configuration, set these fields:
RelayHost– The hostname of your custom relay (e.g.,"myrelay.example.com"). This must be a hostname only, not a URL.RelayPassword– The authentication password your relay expects. Omit or leave empty if the relay does not require authentication.AllowedPorts– A slice of strings representing the TCP ports your relay has open for croc connections (e.g.,[]string{"9009", "9010"}).
Implementation Steps
Follow these steps to serve the web client with a custom relay:
- Create a
Configstruct with your relay's hostname and the specific ports you wish to expose. - Set
RelayPasswordif your relay requires authentication. - Choose an entry point – Use
webrelay.Runfor a standalone server orwebrelay.Handlerto embed the UI in an existing HTTP mux. - Start the server – The UI will be available at the configured
ListenAddress, and the JavaScript client will fetch runtime configuration from/config.js, which automatically contains your custom relay details.
Code Examples
Standalone Server
Use webrelay.Run when you want a dedicated process serving the croc web client:
package main
import (
"context"
"log"
"github.com/schollz/croc/v10/src/webrelay"
)
func main() {
// Define custom configuration for your upstream relay.
cfg := webrelay.Config{
ListenAddress: "0.0.0.0:8080",
RelayHost: "myrelay.example.com",
RelayPassword: "my-secret-pass",
AllowedPorts: []string{"9009", "9010"},
OriginPatterns: []string{"https://mydomain.com"},
}
// Run blocks until the context is cancelled.
if err := webrelay.Run(context.Background(), cfg); err != nil {
log.Fatalf("croc web server failed: %v", err)
}
}
Embedded in Existing Server
Use webrelay.Handler when integrating the croc UI into a larger application:
mux := http.NewServeMux()
// Create the croc web handler with custom relay configuration.
handler, err := webrelay.Handler(cfg)
if err != nil {
log.Fatalf("failed to create croc web handler: %v", err)
}
// Mount the UI under a sub-path.
mux.Handle("/croc/", http.StripPrefix("/croc", handler))
log.Fatal(http.ListenAndServe(":8080", mux))
Key Source Files
| File | Purpose |
|---|---|
[src/webrelay/webrelay.go](https://github.com/schollz/croc/blob/main/src/webrelay/webrelay.go) |
Core implementation containing Config, Handler, Run, and the WebSocket bridging logic. |
[src/webassets/assets.go](https://github.com/schollz/croc/blob/main/src/webassets/assets.go) |
Embeds the static HTML, JavaScript, and assets served to browsers. |
[main.go](https://github.com/schollz/croc/blob/main/main.go) |
CLI entry point that parses flags and invokes webrelay.Run when the --web flag is present. |
[src/croc/croc.go](https://github.com/schollz/croc/blob/main/src/croc/croc.go) |
High-level transfer logic for the standard CLI client, useful for understanding relay protocol requirements. |
Summary
- The
webrelaypackage combines a static-file server with a WebSocket-to-TCP bridge to enable browser-based croc transfers. - Set the
RelayHost,RelayPassword, andAllowedPortsfields inwebrelay.Configto redirect traffic to a custom upstream relay. - Use
webrelay.Runfor standalone deployments orwebrelay.Handlerto embed the UI in existing Go HTTP servers. - The web client automatically discovers relay configuration via the
/config.jsendpoint generated by the server.
Frequently Asked Questions
What is the webrelay package in croc?
The webrelay package is a Go library within schollz/croc that serves the browser-based web client. It hosts the static UI files from an embedded filesystem and proxies WebSocket connections to a TCP relay. It handles the /ws endpoint for WebSocket upgrades, serves /config.js with runtime relay settings, and provides a /healthz health check endpoint.
How do I configure authentication for a custom relay?
Set the RelayPassword field in your webrelay.Config struct to match the password configured on your upstream relay. The default value is "pass123", which matches the public croc relay. If your custom relay requires a different password, you must explicitly set this field before starting the server.
Can I embed the croc web client in an existing HTTP server?
Yes. Instead of calling webrelay.Run, use the webrelay.Handler function to create an http.Handler that you can mount within any existing http.ServeMux. This allows you to serve the croc UI under a sub-path or integrate it into a larger web application while still using your custom upstream relay configuration.
What ports need to be allowlisted for the web client?
The AllowedPorts slice must contain the string representations of all TCP ports your upstream relay has open for croc connections. The default configuration includes ports 9009 through 9017. If your private relay only listens on specific ports (for example, 9009 and 9010), include only those in your configuration to restrict WebSocket connections to valid relay endpoints.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →