# Quickstart

From nothing to FTP, FTPS, and SFTP transfers on loopback ports that
need no privileges. Production installs (package, container, systemd)
are in [Operations](/docs/operations.html).

## 1. Get the binary

Download a release for Linux x86_64 or aarch64 from
[Download](/download.html), or build it:

```sh
cargo build --release -p siftpd     # Rust 1.89+; a C compiler for ring and the asm kernels
./target/release/siftpd --version
```

## 2. Write a config

Hash a password, then put it in `siftp.toml`:

```sh
./target/release/siftpd hash-password 'choose a strong password'
# $argon2id$v=19$m=65536,t=3,p=4$...
```

```toml
[server]
root = "/tmp/siftp-demo/srv"
user_store = "/tmp/siftp-demo/users.toml"

[ftp]
bind = "127.0.0.1:2121"
passive_port_range = [40000, 40100]

[ftps]
# FTPS stays off until these files exist (step 4).
cert_file = "/tmp/siftp-demo/tls.crt"
key_file = "/tmp/siftp-demo/tls.key"
implicit_bind = "127.0.0.1:2990"

[sftp]
bind = "127.0.0.1:2222"
host_key_file = "/tmp/siftp-demo/ssh_host_ed25519_key"

[admin]
bind = "127.0.0.1:8080"
token = "${ENV:SIFTP_ADMIN_TOKEN}"

[logging]
audit_file = "/tmp/siftp-demo/audit.jsonl"

[[users]]
name = "alice"
password_hash = "$argon2id$v=19$m=65536,t=3,p=4$...paste the hash..."
permissions = "rwdnml"
```

`alice`'s root defaults to `/tmp/siftp-demo/srv/alice` and is created on
first login. Check the file; problems come back as JSON naming the
field:

```sh
export SIFTP_ADMIN_TOKEN=$(openssl rand -hex 32)
./target/release/siftpd --check-config --config siftp.toml
```

## 3. Run and transfer

```sh
./target/release/siftpd --config siftp.toml
```

In another terminal:

```sh
echo hello > hello.txt
curl -T hello.txt ftp://alice:'choose a strong password'@127.0.0.1:2121/
curl ftp://alice:'choose a strong password'@127.0.0.1:2121/hello.txt
sftp -P 2222 alice@127.0.0.1                                  # interactive
```

For SFTP in a script, pin the host key instead of trusting the first
connection. The fingerprint comes from the key file:

```sh
fp=$(ssh-keygen -lf /tmp/siftp-demo/ssh_host_ed25519_key | awk '{print $2}' | cut -d: -f2)
curl --hostpubsha256 "$fp" -u alice:'choose a strong password' \
  sftp://127.0.0.1:2222/hello.txt
```

## 4. Add FTPS

Put a PEM certificate and key at the paths in `[ftps]` and restart. For
a local test, a self-signed pair:

```sh
openssl req -x509 -newkey rsa:2048 -nodes -days 30 -subj /CN=localhost \
  -keyout /tmp/siftp-demo/tls.key -out /tmp/siftp-demo/tls.crt
```

Explicit FTPS uses the FTP port (`curl --ssl-reqd ftp://...`), implicit
FTPS the `implicit_bind` port (`curl ftps://...`). Set
`require_tls = true` under `[ftp]` to refuse plaintext logins. A new
certificate is picked up on `kill -HUP` without a restart.

## 5. Manage users through the API

```sh
curl -H "Authorization: Bearer $SIFTP_ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"bob","password":"bob-password","permissions":"rwl"}' \
  http://127.0.0.1:8080/api/v1/users
curl -H "Authorization: Bearer $SIFTP_ADMIN_TOKEN" http://127.0.0.1:8080/api/v1/users
```

Without `permissions`, a user gets the union of their groups'
permissions, or `rl` (read and list) if they have no groups. API users
are written to `user_store` and survive restarts. Users in the config
file stay read-only through the API.

## Next

- [Configuration](/docs/configuration.html): every key and override.
- [Users and access](/docs/identity.html): groups, directory rules,
  keys, LDAP.
- [Security](/docs/security.html) before exposing a listener.
