# `Sftpd`
[🔗](https://github.com/elixir-ssh/sftpd/blob/v0.1.1/lib/sftpd.ex#L1)

A pluggable SFTP server with support for multiple storage backends.

Sftpd wraps Erlang's `:ssh_sftpd` module and provides a clean API for
starting SFTP servers with configurable authentication and storage backends.

OTP 29 no longer enables the SFTP subsystem implicitly when starting an SSH
daemon. `Sftpd.start_server/1` passes an explicit
`:ssh_sftpd.subsystem_spec/1` to `:ssh.daemon/2`, so callers do not need to
configure the OTP daemon subsystem list themselves.

OTP 29 also disables shell and exec services by default. `Sftpd` is an
SFTP-only wrapper and does not enable remote shell or exec channels.

## Quick Start

    # Start an SFTP server with the in-memory backend
    {:ok, ref} = Sftpd.start_server(
      port: 2222,
      backend: Sftpd.Backends.Memory,
      backend_opts: [],
      auth: {:passwords, [{"dev", "dev"}]},
      system_dir: "ssh_keys"
    )

## Backends

Sftpd supports pluggable backends. Built-in backends:

- `Sftpd.Backends.Memory` - in-memory storage for development and tests
- `Sftpd.Backends.S3` - optional Amazon S3 or S3-compatible storage

To create a custom backend, implement the `Sftpd.Backend` behaviour.
See the HexDocs extras [Backends](backends.html) and
[Custom Backends](custom_backends.html) for package-level guidance and
examples. If you need persistent object storage, see the S3 backend docs for
the optional dependency set required by that backend.

## Guides

Package-level HexDocs extras:

- [Getting Started](getting_started.html)
- [Phoenix Setup](phoenix.html)
- [Backends](backends.html)
- [Custom Backends](custom_backends.html)
- [Telemetry](telemetry.html)

## Options

- `:port` - Port to listen on (default: 22)
- `:backend` - Backend module, `{:genserver, pid_or_name}`, or
  `{:genserver, pid_or_name, session: true}` (required)
- `:backend_opts` - Options passed to `backend.init/1` for module backends (default: [])
  The built-in S3 backend accepts `:bucket`, `:prefix`, and `:aws_client`.
- `:auth` - Authentication config, either `{:passwords, list}` or `{Module, opts}` (required)
- `:system_dir` - Directory containing SSH host keys (required)
- `:max_sessions` - Maximum concurrent sessions (default: 10)
- `:open_timeout` - Timeout in milliseconds for opening files (default: 30000)
- `:close_timeout` - Timeout in milliseconds for finalizing file closes (default: 30000)

## Process-Based Backends

Instead of a module, you can use a running GenServer:

    {:ok, backend_pid} = MyBackendServer.start_link()
    Sftpd.start_server(backend: {:genserver, backend_pid}, ...)

See `Sftpd.Backend` for the messages your GenServer must handle.

## Telemetry

See `Sftpd.Telemetry` and the `Telemetry` extra in HexDocs for the event
reference emitted by the server and file-handler layers.

## SSH Host Keys

You need SSH host keys for the server. Generate them with:

    ssh-keygen -t rsa -f ssh_host_rsa_key -N ""
    ssh-keygen -t ecdsa -f ssh_host_ecdsa_key -N ""

Then set `:system_dir` to the directory containing these keys.

# `server_ref`

```elixir
@type server_ref() :: :ssh.daemon_ref()
```

# `child_spec`

```elixir
@spec child_spec(keyword()) :: Supervisor.child_spec()
```

Return a child spec for supervising an SFTP server.

This lets applications start the server directly from a supervision tree:

    children = [
      {Sftpd,
       port: 2222,
       backend: Sftpd.Backends.Memory,
       backend_opts: [],
       auth: {:passwords, [{"dev", "dev"}]},
       system_dir: "ssh_keys"}
    ]

# `start_server`

```elixir
@spec start_server(keyword()) :: {:ok, server_ref()} | {:error, term()}
```

Start an SFTP server.

## Examples

    # Start with the in-memory backend
    {:ok, ref} = Sftpd.start_server(
      port: 2222,
      backend: Sftpd.Backends.Memory,
      backend_opts: [],
      auth: {:passwords, [{"admin", "secret"}]},
      system_dir: "ssh_keys"
    )

## Options

See module documentation for full list of options.

# `stop_server`

```elixir
@spec stop_server(server_ref()) :: :ok | {:error, term()}
```

Stop an SFTP server.

## Examples

    {:ok, ref} = Sftpd.start_server(opts)
    :ok = Sftpd.stop_server(ref)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
