# How to Run a Private Croc Relay Server with Custom Ports

> Easily run a private croc relay server with custom ports. Secure your file transfers with a password-protected TCP relay on your chosen ports. Learn how to set it up quickly.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: how-to-guide
- Published: 2026-07-26

---

**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`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/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.

```bash

# 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`](https://github.com/schollz/croc/blob/main/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.

```bash
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.

```bash

# 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`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) requires at least two ports: one for control, one for data
- Port validation occurs in [`src/webrelay/webrelay.go`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/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`](https://github.com/schollz/croc/blob/main/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.