LocalhostRun (localhost.run v0.1.0)

View Source

Elixir client for localhost.run

Usage

Via GenServer

{:ok, pid} = LocalhostRun.start_link(internal_port: 4000)

Via Supervisor

children = [
  {LocalhostRun, [internal_port: 4000]}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)

Direct

{:ok, {conn_ref, channel_id}} = LocalhostRun.connect(internal_port: 4000)

receive do
  {:ssh_cm, ^conn_ref, {:data, ^channel_id, 0, message}} ->
    case JSON.decode!(message) do
      %{"event" => "tcpip-forward", "address" => host} ->
        Logger.info("Tunnel established to #{host}")
        {:ok, host}

      %{"event" => "authn", "message" => message} ->
        Logger.info("Tunnel authentication successful: #{message}")
        :ok

      %{"message" => message} ->
        Logger.debug("Received message from SSH channel on STDOUT: #{inspect(message)}")
    end
end

Login to localhost.run

If you want custom domain names or longer lasting tunnels, you need to login to localhost.run.

See: https://localhost.run/docs/custom-domains

To do so, you have the following options:

Use SSH Agent

To use your SSH agent, ensure that it is running and that you have added your SSH key to it. You can verify that your SSH agent is running by running the following command:

ssh-add -l

If you see a list of keys, your SSH agent is running. If not, you can start it by running:

eval "$(ssh-agent -s)"

Then, add your SSH key to the agent:

ssh-add ~/.ssh/id_rsa

Afterwards you can use the LocalhostRun module with the :ssh_options option to specify the SSH agent:

{:ok, pid} = LocalhostRun.start_link(internal_port: 4000, ssh_options: [
  user: "your_username",
  key_cb: {:ssh_agent, []}
])

Check the [ssh_agent] documentation for more information.

Use SSH Key

If you want to use a specific SSH key, you can specify to use the key_cb ssh_file in the :ssh_options option:

{:ok, pid} = LocalhostRun.start_link(internal_port: 4000, ssh_options: [
  user: "your_username",
  key_cb: {:ssh_file, []}
])

Check the ssh_file documentation for more information.

Logger Metadata

The LocalhostRun module automatically sets the following metadata for the Logger module:

  • ssh_host - The SSH host to connect to.
  • ssh_port - The SSH port to connect to.
  • external_host - The external host to use for the tunnel.
  • internal_port - The internal port to forward.

Summary

Types

Options for the LocalhostRun GenServer.

Functions

Connects to the SSH server and sets up the tunnel.

Returns the exposed host for the tunnel. This function blocks until the tunnel is established and the host is available.

Starts the LocalhostRun GenServer.

Types

opts()

@type opts() :: [
  name: GenServer.name(),
  ssh_host: String.t(),
  ssh_port: :inet.port_number(),
  external_host: String.t(),
  ssh_options: :ssh.client_options(),
  connect_timeout: timeout(),
  internal_port: :inet.port_number()
]

Options for the LocalhostRun GenServer.

  • :name - The name of the GenServer process. Default is LocalhostRun.
  • :ssh_host - The SSH host to connect to. Default is localhost.run.
  • :ssh_port - The SSH port to connect to. Default is 22.
  • :external_host - The external host to use for the tunnel. Default is a random host.
  • :ssh_options - Additional SSH options. Default is an empty list.
  • :connect_timeout - The timeout for the SSH connection. Default is 10 seconds.
  • :internal_port - The internal port to forward. This is required and should be provided.

Functions

connect(opts)

@spec connect(opts :: opts()) ::
  {:ok, {:ssh.connection_ref(), :ssh.channel_id()}} | {:error, term()}

Connects to the SSH server and sets up the tunnel.

get_exposed_host(name \\ LocalhostRun)

@spec get_exposed_host(name :: GenServer.name()) :: {:ok, String.t()}

Returns the exposed host for the tunnel. This function blocks until the tunnel is established and the host is available.

start_link(opts)

Starts the LocalhostRun GenServer.

It connects to the SSH server and sets up the tunnel.

The :internal_port option is required and should be provided.