Raxol.SSH.Server (Raxol v2.6.0)

View Source

Serves a Raxol TEA application over SSH.

Each SSH connection gets its own Lifecycle process running the TEA app, with terminal I/O redirected through the SSH channel.

Usage

Raxol.SSH.serve(CounterExample, port: 2222)

Then connect: ssh localhost -p 2222

Options

  • :port - Port to listen on (default: 2222)
  • :host_keys_dir - Directory for SSH host keys (default: ~/.raxol/ssh_keys, a persistent path so keys survive restarts)
  • :max_connections - Maximum concurrent connections (default: 50)
  • :max_per_ip - Maximum concurrent connections from one peer IP (default: 10), so a single host cannot flood the pool
  • :negotiation_timeout - Milliseconds a connection may spend in key exchange and auth before it is dropped (default: 30_000), bounding slow-handshake holds

Authentication (fail-closed)

A surface that can reach payment Actions must not be silently anonymous, so authentication is required unless anonymous access is explicitly requested:

  • :allow_anonymous - true accepts any connection (BBS/playground use).
  • :authorized_keys_dir - a directory holding an authorized_keys file; connections must present a listed public key.

With neither, the server refuses to start.

Summary

Functions

Build the :ssh.daemon authentication options, failing closed.

Returns a specification to start this module under a supervisor.

Returns the current number of active connections.

Default directory for SSH host keys: a persistent per-user path.

Registers a new connection from peer_ip.

Unregisters a connection from peer_ip when it closes.

Functions

auth_daemon_opts(opts)

@spec auth_daemon_opts(keyword()) :: {:ok, keyword()} | {:error, :ssh_auth_required}

Build the :ssh.daemon authentication options, failing closed.

Returns {:ok, opts} for allow_anonymous: true (no auth) or authorized_keys_dir: dir (public-key auth), and {:error, :ssh_auth_required} when neither is given so the caller refuses to start an anonymous surface.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

connection_count(server \\ __MODULE__)

@spec connection_count(GenServer.server()) :: non_neg_integer()

Returns the current number of active connections.

default_host_keys_dir()

@spec default_host_keys_dir() :: String.t()

Default directory for SSH host keys: a persistent per-user path.

A host key under /tmp rotates on reboot, which trains clients to click through the host-key-changed warning -- the one warning that matters. Keys live under the user's home so they survive restarts.

register_connection(server \\ __MODULE__, peer_ip \\ :unknown)

@spec register_connection(GenServer.server(), term()) ::
  :ok | {:error, :max_connections | :ip_limit}

Registers a new connection from peer_ip.

Returns :ok, {:error, :max_connections} (global cap), or {:error, :ip_limit} (this peer already holds max_per_ip connections, so a single host cannot exhaust the pool).

serve(app_module, opts \\ [])

@spec serve(
  module(),
  keyword()
) :: GenServer.on_start()

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

unregister_connection(server \\ __MODULE__, peer_ip \\ :unknown)

@spec unregister_connection(GenServer.server(), term()) :: :ok

Unregisters a connection from peer_ip when it closes.