How to Run a Private Croc Relay Server with Custom Ports

To run a private croc relay server with custom ports, execute croc relay --ports 1111,1112 --pass "YourSecret", which starts a password-protected TCP relay on your specified ports that clients can reach using the --relay flag.

Croc is an open-source file transfer tool that uses a relay server to route encrypted traffic between peers. When you run a private croc relay server with custom ports, you create a dedicated TCP endpoint that remains always-available for secure file transfers without relying on public infrastructure.

Understanding the Croc Relay Architecture

The croc relay consists of three main components working together. The CLI entry point in src/cli/cli.go registers the relay action and parses flags including --ports, --port, and --pass. The core relay implementation in src/croc/croc.go contains the runRelay() function that initializes TCP listeners on the configured ports. Finally, the WebSocket bridge in src/webrelay/webrelay.go serves the embedded web client and validates that incoming connections use allowed ports.

The relay authenticates clients using PAKE (password-authenticated key agreement). When you set the --pass flag or CROC_PASS environment variable, the relay requires this password before forwarding encrypted traffic between sender and receiver.

Starting a Private Relay with Custom Ports

To start a private relay, use the croc relay command with the --ports flag to specify your custom TCP ports. According to the flag definitions in src/cli/cli.go (around line 90), the parser populates the Options.RelayPorts slice, which runRelay() uses to initialize listeners.

The relay requires at least two ports because croc dedicates one port to control messages and another to the data stream. Attempting to run the relay with fewer than two ports causes the CLI to abort with an error.


# Start a relay on ports 1111 and 1112 with password protection

croc relay --ports 1111,1112 --pass "MySecretPassword"

# Alternative: Use the first port as a base (allocates consecutive ports)

croc relay --port 1111 --pass "MySecretPassword"

Configuring the WebSocket Bridge and Port Validation

The relay exposes a WebSocket endpoint at /ws for the embedded web client. In src/webrelay/webrelay.go, the code validates that requested ports appear in the configured allow-list (around line 238). If a client attempts to connect through a port not present in your --ports list, the relay returns the error "relay port is not allowed".

This validation ensures that even if clients know your host address, they cannot access arbitrary ports on your relay server. The Options.RelayPorts slice acts as the authoritative whitelist for both TCP listeners and WebSocket connections.

Running the Relay in Docker

You can containerize the relay using the official docker.io/schollz/croc image. Pass the same configuration via environment variables rather than command-line flags.

docker run -d \
  -p 1111-1112:1111-1112 \
  -e CROC_PASS="MySecretPassword" \
  -e CROC_PORTS="1111,1112" \
  docker.io/schollz/croc

The image exposes the specified ports and starts the relay process automatically. Ensure your Docker port mappings (-p) match the ports defined in CROC_PORTS.

Connecting Clients to Your Private Relay

Once your relay is running, clients must specify the custom host and port using the --relay flag. The format requires both the hostname and one of the allowed ports.


# Send a file through the custom relay

croc --relay "myhost.example.com:1111" --pass "MySecretPassword" send myfile.txt

# Receive the file (using the code phrase provided by sender)

croc --relay "myhost.example.com:1111" --pass "MySecretPassword" <code-phrase>

While you specify one port in the --relay argument, croc automatically negotiates the second port for the data stream from the Options.RelayPorts list configured on the server.

IPv6 Support and Default Configuration

For IPv6 support, set the --relay6 flag when starting your relay and ensure your firewall allows the same port range on IPv6. The --ports list applies to both IP families.

Default public relay addresses and constants are defined in src/models/constants.go, which you can reference if you need to understand the fallback behavior or modify defaults when building from source.

Summary

  • Run croc relay --ports 1111,1112 --pass "secret" to start a private relay with custom ports 1111 and 1112
  • The relay code in src/croc/croc.go requires at least two ports: one for control, one for data
  • Port validation occurs in src/webrelay/webrelay.go, which rejects connections to unlisted ports
  • Use Docker with -e CROC_PORTS and matching -p flags for containerized deployments
  • Clients connect using --relay hostname:port with the same password used on the server

Frequently Asked Questions

How many ports does a croc relay require?

A croc relay requires at least two TCP ports to function. The source code in src/croc/croc.go uses one port for control messages and another for the actual file data stream. If you supply fewer than two ports via --ports or CROC_PORTS, the CLI will abort with a validation error.

Can I use a single port for my private croc relay?

No. The architecture requires separate channels for control and data transmission. While you might attempt to specify a single port, the relay initialization logic checks the length of Options.RelayPorts and will refuse to start if fewer than two ports are configured.

How do I secure my private croc relay?

Set a strong password using the --pass flag or CROC_PASS environment variable. This enables PAKE (password-authenticated key agreement), which ensures that only clients possessing the correct password can establish encrypted sessions through your relay. Additionally, restrict access using firewalls since the relay exposes raw TCP ports.

Why does my client receive "relay port is not allowed"?

This error originates in src/webrelay/webrelay.go when a client attempts to connect through a port that is not included in the server's configured --ports list. Verify that the port specified in your client's --relay flag matches one of the ports you opened when starting the relay, and ensure the WebSocket bridge can access the same port whitelist.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →