A virtualized SFTP server backed by PostgreSQL, built on the Twisted networking library.
Users are configured entirely via database — no system accounts required. Each user is restricted to their own home directory and authenticated via password or SSH public key.
- Password and SSH public-key authentication
- Per-user chroot to a configured home directory (auto-created on first login)
- Pluggable server class via
server-classconfig key - Runs as an unprivileged service
- Python 3.13+
- PostgreSQL
- uv (for local development)
docker compose upThe default compose file starts a PostgreSQL database and the SFTP server on port 8888. Add users with the script described below before connecting.
Configuration is loaded from /etc/txsftp.json. When running via Docker, the entrypoint generates this file from environment variables:
| Variable | Default | Description |
|---|---|---|
SFTP_PORT |
8888 |
Port to listen on |
SERVER_CLASS |
txsftp.handler.GPGFileTransferServer |
SFTP server implementation class |
ACCESS_LOG |
/dev/null |
Access log path |
ERROR_LOG |
(stdout) | Error log path |
DB_HOST |
db |
PostgreSQL host |
DB_PORT |
5432 |
PostgreSQL port |
DB_NAME |
txsftp |
Database name |
DB_USER |
txsftp |
Database user |
DB_PASSWORD |
(required) | Database password |
SSH host keys are generated at build time and stored in /etc/txsftp/. Mount a named volume over /etc/txsftp to persist keys across image rebuilds.
Use the provided script (run inside the container or with DB env vars set):
# Inside the container (home defaults to /data/sftp/<username>)
docker compose run txsftp python scripts/upsert_user.py <username> <password>
# Or via psql directly
docker compose exec db psql -U txsftp -d txsftpThe password column stores a DES crypt hash. Generate one with:
python3 -c "from passlib.hash import des_crypt; print(des_crypt.hash('yourpassword'))"uv sync
uv run pytest tests/
uv run twistd -n txsftp # requires a running PostgreSQL and /etc/txsftp.jsonSee scripts/init.sql for the full schema. The core table is sftp_user:
| Column | Type | Description |
|---|---|---|
username |
varchar | Login name (unique) |
password |
varchar | DES crypt hash (nullable — disables password auth) |
ssh_public_key |
text | OpenSSH public key string (nullable) |
home_directory |
varchar | Absolute path, auto-created on first login |
last_login |
timestamp | Set to NOW() on each successful authentication |
last_logout |
timestamp | Set to NOW() when the session is closed |