Skip to content

Quickstart

Run with Docker

git clone https://github.com/dataresearchcenter/putfs
cd putfs
docker compose up

This starts two services:

  • api – PutFS on a unix socket (internal, not exposed)
  • nginx – reverse proxy on port 8000 (exposed)

The storage root defaults to ./data and is configured via the PUTFS_ROOT environment variable.

Set up auth key

Create a keys file at ./keys/keys.conf:

map "$http_x_api_key:$http_x_api_secret" $key_ok {
    default           0;
    "putfs_demo:demo" 1;
}

map "$http_x_api_key:$request_method:$uri" $auth_ok {
    default                          0;
    "~^putfs_demo:[^:]+:/.+"        1;
}

Then reload nginx: docker compose exec nginx nginx -s reload

See Auth for key scoping by path and method.

Usage

The examples below show the same operations across the three supported clients. The CLI and Python clients pick up PUTFS_ENDPOINT_URL, PUTFS_API_KEY, and PUTFS_API_SECRET from the environment:

export PUTFS_ENDPOINT_URL=http://localhost:8000
export PUTFS_API_KEY=putfs_demo
export PUTFS_API_SECRET=demo

Upload

curl -X PUT \
  -H "X-Api-Key: putfs_demo" \
  -H "X-Api-Secret: demo" \
  http://localhost:8000/my-dataset/hello.txt \
  -d "hello world"
echo "hello world" > hello.txt
putfs cp hello.txt putfs://localhost:8000/my-dataset/hello.txt
from putfs.client import PutFS

client = PutFS()
client.put("my-dataset/hello.txt", "hello world")

# Or stream from a file-like source
with client.open("my-dataset/hello.txt", "wb") as fh:
    fh.write(b"hello world")

Download

curl \
  -H "X-Api-Key: putfs_demo" \
  -H "X-Api-Secret: demo" \
  http://localhost:8000/my-dataset/hello.txt
putfs cp putfs://localhost:8000/my-dataset/hello.txt -  # stdout
data = client.get("my-dataset/hello.txt")

# Or stream into a file-like sink
with client.open("my-dataset/hello.txt") as fh:
    data = fh.read()

List

curl \
  -H "X-Api-Key: putfs_demo" \
  -H "X-Api-Secret: demo" \
  http://localhost:8000/my-dataset/
putfs ls putfs://localhost:8000/my-dataset/
for key in client.iterate_keys(prefix="my-dataset"):
    print(key)

Delete

curl -X DELETE \
  -H "X-Api-Key: putfs_demo" \
  -H "X-Api-Secret: demo" \
  http://localhost:8000/my-dataset/hello.txt
putfs rm putfs://localhost:8000/my-dataset/hello.txt
client.delete("my-dataset/hello.txt")

For the full HTTP spec, see HTTP. For the CLI and Python clients, see CLI and Python.

How requests flow

Nginx serves files directly from the data volume for reads. Writes, deletes, and listing go through the PutFS API upstream.

client -> nginx
            |-- GET static file -> serve from /data (fast path)
            `-- PUT/DELETE/LIST -> proxy to PutFS API

Install from PyPI

If you prefer running without Docker:

pip install putfs

Then run with granian:

export PUTFS_ROOT=/srv/putfs
granian --interface asgi --host 127.0.0.1 --port 5000 putfs.api:app

See granian tuning.