Bare metal
The preferred way to run PutFS. No Docker overhead, direct filesystem access, systemd process management. The python dependencies for the API are minimal and can be installed on any system.
Example file layout
/opt/putfs/venv/ Python venv with putfs + granian
/srv/putfs/ Data root (or ZFS mountpoint)
/etc/putfs/keys/ API keys + presign secrets (nginx map format)
/etc/putfs/snippets/ Reusable nginx blocks (CORS, proxy tuning, XSS hardening)
/etc/putfs/cors.nginx.conf $cors_origin map (origin allowlist)
/run/putfs/putfs.sock Unix socket (created by granian)
/etc/systemd/system/putfs.service
/etc/nginx/sites-available/putfs
Setup
Install
Create data directory
For ZFS:
Keys
/etc/putfs/keys/auth.nginx.conf (start from contrib/keys/auth.nginx.conf and replace the test keys):
map "$http_x_api_key:$http_x_api_secret" $key_ok {
default 0;
"PUTFS_CHANGEME:CHANGEME" 1;
}
map "$http_x_api_key:$request_method:$uri" $auth_ok {
default 0;
"~^PUTFS_CHANGEME:[^:]+:/.+" 1;
}
# Single deny gate – /_/dl/ bypasses (HMAC validates inside that location)
map "$uri:$key_ok:$auth_ok" $deny {
default 1;
"~^/_/dl/" 0;
"~:1:1$" 0;
}
See Auth for key scoping. Presigned-URL signing secrets live in keys/presign.nginx.conf – see Presigned URLs.
Systemd service
Copy contrib/putfs.service to /etc/systemd/system/:
All granian settings are configured via Environment= directives. Override by editing the service file or using a drop-in:
Nginx
The server config includes /etc/putfs/keys/, /etc/putfs/snippets/, and /etc/putfs/cors.nginx.conf by literal path – populate the whole layout from contrib/, or nginx -t fails at config parse:
mkdir -p /etc/putfs
cp -r contrib/keys contrib/snippets contrib/cors.nginx.conf /etc/putfs/
cp contrib/putfs.nginx.conf /etc/nginx/sites-available/putfs
ln -s /etc/nginx/sites-available/putfs /etc/nginx/sites-enabled/
# Edit server_name + root path; replace the test keys under /etc/putfs/keys/
nginx -t && systemctl reload nginx
Verify
# Check service
systemctl status putfs
# Test write
curl -X PUT -H "X-Api-Key: PUTFS_CHANGEME" -H "X-Api-Secret: CHANGEME" \
-d "hello" http://localhost/test/hello.txt
# Test read
curl -H "X-Api-Key: PUTFS_CHANGEME" -H "X-Api-Secret: CHANGEME" \
http://localhost/test/hello.txt
# Check the file on disk
ls -la /srv/putfs/test/hello.txt