How to Configure croc for a Local Network: Complete Setup Guide

To run croc entirely on a local network, disable the automatic local relay with --no-local, point both peers to a LAN-hosted relay using --relay <ip>, and ensure matching --ports on all commands.

When transferring files between machines on the same LAN, you can configure croc for a local network to bypass public infrastructure entirely. This setup keeps traffic internal to your network, eliminates external dependencies, and often improves transfer speeds. The schollz/croc repository supports this through specific CLI flags that disable NAT traversal and target a self-hosted relay.

Why Use croc on a Local Network?

By default, croc attempts to traverse NAT using public relay servers, which routes your data through the internet even when both devices sit next to each other. For LAN-only transfers, this adds unnecessary latency and security exposure. Running croc on a local network ensures that file transfers never leave your internal infrastructure, making it ideal for air-gapped environments, sensitive data transfers, or high-speed exchanges between workstations.

Core CLI Flags for Local Configuration

The command-line interface defines the flags that control relay behavior in src/cli/cli.go.

Disable Automatic Local Relay with --no-local

The --no-local flag prevents croc from spawning a temporary local relay used for NAT piercing. According to the source in [cli.go](https://github.com/schollz/croc/blob/main/src/cli/cli.go#L76‑L81), this flag is essential for pure LAN operation where NAT traversal is unnecessary and can interfere with direct connections.

When sending files, include this flag to ensure croc connects only to your specified relay rather than attempting to negotiate a peer-to-peer connection through external means.

Specify the Relay Host with --relay

Use the --relay flag to direct both sender and receiver to a fixed host on your LAN. In [cli.go](https://github.com/schollz/croc/blob/main/src/cli/cli.go#L50‑L51), this flag is parsed and stored in the croc.Options struct (defined in [croc.go](https://github.com/schollz/croc/blob/main/src/croc/croc.go#L150‑L166)).

Supply a local IP address or hostname without a URL scheme, such as 192.168.1.10 or fileserver.local.

Define Allowed Ports with --ports

The --ports flag specifies which ports the relay will expose for WebSocket connections. As implemented in [cli.go](https://github.com/schollz/croc/blob/main/src/cli/cli.go#L98‑L99), this takes a comma-separated list like 9009,9010,9011,9012. Both the relay server and all clients must use identical port configurations.

Bind the Relay Server with --bind

When starting the relay using croc serve, the --bind flag controls the listening interface. In [cli.go](https://github.com/schollz/croc/blob/main/src/cli/cli.go#L11‑L12) (within the serve command definition), this defaults to localhost but should be set to 0.0.0.0:PORT to accept connections from other LAN machines.

How croc Processes Relay Addresses

Internally, croc normalizes the relay address through the normalizeRelayAddress function found in [croc.go](https://github.com/schollz/croc/blob/main/src/croc/croc.go#L2147‑L2154). If the provided address lacks a scheme (e.g., https://), it treats the input as a plain host name, appending the default port. This logic ensures that simple LAN IPs like 192.168.1.10 resolve correctly to 192.168.1.10:9009 for the underlying TCP connection.

Validation and Error Handling

The system validates relay configuration in [webrelay.go](https://github.com/schollz/croc/blob/main/src/webrelay/webrelay.go#L58‑L61). If you accidentally include a URL scheme (e.g., http://192.168.1.10), croc returns the error relay must be a host, not a URL. Always provide bare IP addresses or hostnames to avoid this validation failure.

Step-by-Step Local Network Setup

Follow this workflow to transfer files exclusively over your LAN.

1. Start the Built-in Relay Server

Designate one machine as the relay host (e.g., 192.168.1.10). Run:

croc serve --bind 0.0.0.0:9014 \
           --relay 192.168.1.10 \
           --ports 9009,9010,9011,9012

The --bind 0.0.0.0:9014 instructs the embedded HTTP/WebSocket server to listen on all network interfaces, while --relay sets the advertised address that peers will use.

2. Send Files from the Source Machine

On the device hosting the files, disable the automatic local relay and point to your LAN server:

croc send --relay 192.168.1.10 \
          --no-local \
          --ports 9009,9010,9011,9012 \
          myfile.txt

The --no-local flag prevents the sender from starting a temporary local relay, forcing it to connect directly to 192.168.1.10.

3. Receive Files on the Destination Machine

On the receiving device, connect to the same relay:

croc receive --relay 192.168.1.10 \
             --ports 9009,9010,9011,9012

Because both peers contact the same LAN relay, the transfer occurs entirely over the local network without internet traversal.

Summary

  • Use --no-local (defined in cli.go line 76) on the sender to disable automatic NAT traversal relays.
  • Set --relay <host> to a LAN IP or hostname (parsed in cli.go lines 50-51 and stored in croc.Options lines 150-166).
  • Match --ports across all commands to ensure consistent WebSocket connectivity (configured in cli.go lines 98-99).
  • Start the relay with croc serve --bind 0.0.0.0:PORT to accept LAN connections.
  • Validate that relay addresses contain no URL scheme to avoid errors from webrelay.go lines 58-61.

Frequently Asked Questions

Do both the sender and receiver need the --no-local flag?

Only the sender requires --no-local to prevent spawning an unnecessary local relay for NAT traversal. However, both peers must specify identical --relay and --ports values to ensure they connect to the same LAN relay instance, as the configuration must match across the croc.Options struct used by both parties.

Can I use a hostname instead of an IP address for the relay?

Yes. The normalizeRelayAddress function in croc.go (lines 2147-2154) treats any string without a URL scheme as a valid host. You can use fileserver.local or similar hostnames, provided your LAN's DNS or hosts file resolves the name correctly. Just ensure you do not include http:// or https://, or webrelay.go will reject it with a validation error.

Why does croc require a relay for local network transfers?

Croc uses a client-server architecture where both sender and receiver connect to a central relay that coordinates the WebSocket-to-TCP bridge, even on LANs. This design maintains croc's security model (end-to-end encrypted) and simplifies firewall traversal. By hosting the relay locally with croc serve, you keep this coordination internal while avoiding external infrastructure.

What happens if I forget the --no-local flag?

Without --no-local, the sending instance attempts to establish a temporary local relay for NAT piercing, which can cause connection failures or suboptimal routing in LAN-only environments. According to cli.go lines 76-81, this flag explicitly disables the automatic local relay logic, ensuring the client connects directly to your specified --relay host instead.

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 →