Tailcat Server Mode Service Types: The Complete Guide to Built-in Network Services

Tailcat server mode supports six distinct service types: all, exit-node, ssh, no-auth-ssh, files, and exec, each exposing different server capabilities that clients can connect to over the tailnet.

Tailcat—an open-source networking tool from the Tailscale ecosystem—provides a flexible serve subcommand that transforms any node into a multi-protocol server. Understanding the available Tailcat server mode service types is essential for configuring secure file transfers, remote shells, traffic forwarding, and custom command execution across your private network.

Overview of Tailcat Server Mode

When you invoke tailcat serve, the binary initializes a tailcat.Server struct that dispatches incoming connections based on the service flags you specify. According to the source code in main/cmd/tailcat/tailcat.go, the service names are parsed by the parsePortSet helper (lines 94–104) and validated to prevent incompatible combinations (lines 1264–1273). This architecture allows a single Tailcat instance to expose multiple services simultaneously while maintaining strict security boundaries.

The Six Supported Service Types

all: Full-Port Exposure

The all service type exposes every port—both TCP and UDP—on the server’s Tailscale address. This mode effectively turns the node into a transparent proxy where any incoming connection attempt is accepted, making it useful for development environments or testing scenarios where you need unrestricted access without configuring individual ports.

exit-node: Full-Mesh Traffic Forwarding

When configured as an exit-node, the server acts as a full-mesh router that forwards traffic to arbitrary destinations outside the tailnet. This service implements the forwarding logic found in main/cmd/tailcat/forward.go, allowing clients to route internet-bound traffic through the server. Exit nodes are particularly valuable for accessing geo-restricted content or enforcing centralized internet filtering policies.

ssh: Authenticated SSH Server

The ssh service spins up a public-key-authenticated SSH server using the implementation in main/tailcat_ssh.go. To use this service, you must provide the --ssh-authorized-keys flag pointing to a file containing permitted public keys. This creates a secure, key-based remote shell accessible only to holders of the corresponding private keys.

no-auth-ssh: Authentication-Free SSH Access

For scenarios requiring immediate access without key management—such as automated testing or secure sandboxed environments—the no-auth-ssh service provides an SSH server that does not require authentication. While convenient, this should only be deployed in trusted network segments due to its open-access nature.

files: SFTP and SCP File Service

The files service enables SFTP/scp file transfers through the logic implemented in main/tailcat_files.go. Configure this service using the --files flag with a path and mode suffix:

  • :ro for read-only access
  • :rw for read-write access
  • :wo for write-only access

This creates a hardened file server without requiring separate SFTP daemon configuration.

exec: Per-Connection Command Execution

The exec service—implemented in main/tailcat_exec.go—executes a specified command for each incoming connection, piping the network stream directly to the process’s stdio. Append -- followed by your command to the serve invocation. This transforms Tailcat into a network-wrapped process supervisor, ideal for creating ad-hoc TCP/IP services from standard Unix tools.

Service Validation and Conflict Detection

The Tailcat CLI enforces strict validation rules to prevent security-impossible configurations. In main/cmd/tailcat/tailcat.go (lines 1264–1273), the validation logic explicitly rejects attempts to combine mutually exclusive services. For example, you cannot simultaneously enable ssh and no-auth-ssh on the same instance, as this would create ambiguous authentication requirements. The parsePortSet function handles the initial string parsing of comma-separated service lists before this validation occurs.

Configuration Examples

Hosting SSH and File Services Together

Expose both authenticated SSH and read-write file access:

$ tailcat serve \
    --ssh-authorized-keys=~/.ssh/id_rsa.pub \
    --files=/srv/share:rw \
    ssh,files

Unauthenticated SSH with Command Execution

Create a netcat-like service that runs /usr/bin/cat for every connection without requiring SSH keys:

$ tailcat serve \
    --serve=no-auth-ssh,exec \
    -- /usr/bin/cat

Programmatic Exit Node Configuration

Using the Go library to start an exit node server:

package main

import (
    "log"
    "tailscale.com/tailcat"
)

func main() {
    srv := &tailcat.Server{
        // Exit-node mode is activated implicitly or via configuration
    }
    if err := srv.Start(); err != nil {
        log.Fatalf("server start: %v", err)
    }
    // Server now forwards traffic as a full-mesh exit node
}

Summary

  • Tailcat supports six service types: all, exit-node, ssh, no-auth-ssh, files, and exec, defined in main/cmd/tailcat/tailcat.go lines 94–104.
  • Validation prevents conflicts: The source code at lines 1264–1273 explicitly blocks incompatible combinations like ssh with no-auth-ssh.
  • Authentication requirements vary: The ssh service requires --ssh-authorized-keys, while no-auth-ssh provides immediate access.
  • File permissions are granular: The files service supports read-only (:ro), read-write (:rw), and write-only (:wo) modes via the --files flag.
  • Implementation is modular: Each service maps to specific source files like main/tailcat_ssh.go, main/tailcat_files.go, and main/tailcat_exec.go.

Frequently Asked Questions

Can I combine multiple Tailcat service types in a single command?

Yes, you can specify multiple services as comma-separated values to the --serve flag, such as ssh,files or exit-node,exec. However, the validation logic in main/cmd/tailcat/tailcat.go will reject combinations that create security conflicts, such as mixing authenticated and unauthenticated SSH services on the same instance.

What is the difference between the ssh and no-auth-ssh services?

The ssh service requires public key authentication via the --ssh-authorized-keys flag, using the implementation in main/tailcat_ssh.go to verify credentials before granting shell access. In contrast, no-auth-ssh immediately grants access without credential verification, making it suitable for automated testing but inappropriate for production environments requiring access control.

How do I configure the files service for read-only access?

Append the :ro suffix to your path in the --files flag. For example: --files=/srv/data:ro creates a read-only SFTP endpoint. You can also specify :rw for read-write or :wo for write-only access, with the permission logic enforced by the file service implementation in main/tailcat_files.go.

Can I run an exit node alongside other services like files or exec?

Yes, the exit-node service can coexist with other service types such as files or exec. The exit node functionality—implemented in main/cmd/tailcat/forward.go—operates independently of the application-layer services, allowing your node to simultaneously route traffic for the mesh network and host specific application services for direct client connections.

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 →