# Getting Started

This guide walks through a minimal `Sftpd` setup using the in-memory backend,
then shows how to switch to S3.

## 1. Add the dependency

This guide uses the current pinned development environment:

- Erlang/OTP 29.0
- Elixir 1.20.0-rc.5 on OTP 29

The package itself still declares an older minimum Elixir version in `mix.exs`.
The current verified minimum is Elixir 1.14.5 on OTP 26.

```elixir
def deps do
  [
    {:sftpd, "~> 0.1.1"}
  ]
end
```

Then fetch dependencies:

```bash
mix deps.get
```

## 2. Generate SSH host keys

SFTP clients expect the server to present SSH host keys. Create them once and
keep them somewhere your application can read:

```bash
mkdir -p ssh_keys
ssh-keygen -t rsa -f ssh_keys/ssh_host_rsa_key -N ""
ssh-keygen -t ecdsa -f ssh_keys/ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f ssh_keys/ssh_host_ed25519_key -N ""
```

Pass the containing directory as `system_dir`.

## 3. Start a server with the memory backend

The memory backend is the fastest way to get a working server without any
external services:

```elixir
{:ok, ref} =
  Sftpd.start_server(
    port: 2222,
    backend: Sftpd.Backends.Memory,
    backend_opts: [],
    auth: {:passwords, [{"dev", "dev"}]},
    system_dir: "ssh_keys"
  )
```

Important options:

- `:port` controls the SSH listener port
- `:backend` selects the storage implementation
- `:backend_opts` passes backend-specific configuration
- `:auth` configures authentication. Use `{:passwords, [{"dev", "dev"}]}` for
  local development, or `{MyApp.SftpAuth, opts}` for application callbacks
- `:system_dir` points at the SSH host key directory
- `:max_sessions` limits concurrent client sessions
- `:open_timeout` bounds file open setup time
- `:close_timeout` bounds close-time finalization time

OTP 29 no longer enables the SFTP subsystem implicitly for SSH daemons.
`Sftpd.start_server/1` supplies the required `:subsystems` option internally,
so the setup above works on both OTP 29 and older supported OTP releases.

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

## 4. Connect with an SFTP client

From another terminal:

```bash
sftp -P 2222 dev@localhost
```

Then try a few operations:

```text
put local.txt remote.txt
ls
get remote.txt
rm remote.txt
```

Because the memory backend is ephemeral, data disappears when the server stops.

## 5. Stop the server

```elixir
:ok = Sftpd.stop_server(ref)
```

## 6. Switch to the S3 backend

To persist files in S3-compatible storage, use `Sftpd.Backends.S3`:

The S3 backend is optional. The memory backend and custom backends work with
only `{:sftpd, "~> 0.1.1"}`. Add the S3 dependencies before using
`Sftpd.Backends.S3`:

```elixir
def deps do
  [
    {:sftpd, "~> 0.1.1"},
    {:ex_aws, "~> 2.0"},
    {:ex_aws_s3, "~> 2.0"},
    {:hackney, "~> 1.9"},
    {:sweet_xml, "~> 0.7"},
    {:jason, "~> 1.3"},
    {:configparser_ex, "~> 4.0"}
  ]
end
```

Without those dependencies, `Sftpd.Backends.S3.init/1` returns
`{:error, :missing_s3_dependency}`.

```elixir
{:ok, ref} =
  Sftpd.start_server(
    port: 2222,
    backend: Sftpd.Backends.S3,
    backend_opts: [bucket: "my-bucket", prefix: "tenant-a/"],
    auth: {:passwords, [{"dev", "dev"}]},
    system_dir: "ssh_keys"
  )
```

S3 backend options:

- `:bucket` is required
- `:prefix` scopes keys within a bucket. It can be a string or
  `{:session, key}` to read a per-user prefix from the auth session map
- `:aws_client` lets you swap in a compatible client for tests or custom
  adapters

Example ExAws configuration:

```elixir
config :ex_aws,
  access_key_id: "your-key",
  secret_access_key: "your-secret",
  region: "us-east-1"

config :ex_aws, :s3,
  scheme: "http://",
  host: "localhost",
  port: 9000
```

## 7. Add telemetry handlers if you want instrumentation

`Sftpd` depends on `:telemetry` directly. Applications only need to attach
handlers for the events they want to consume.

See [Telemetry](TELEMETRY.md) for the full event reference.

## 8. Build your own backend

If neither built-in backend fits your storage model:

- read [Backends](BACKENDS.md) for backend architecture and tradeoffs
- read [Custom Backends](CUSTOM_BACKENDS.md) for implementation guidance
- implement the `Sftpd.Backend` behaviour

## Notes and Caveats

- `Sftpd` wraps Erlang's `:ssh_sftpd` implementation and explicitly enables
  the SFTP subsystem required by OTP 29
- OTP 29 disables SSH shell and exec services by default; `Sftpd` does not
  expose or enable those services
- OTP's stock SFTP server always reports close success to the client, even if
  final close-time backend flushing fails
- backends should return POSIX-style error atoms such as `:enoent` and `:eio`
- the S3 backend models directories using `.keep` marker objects
