Skip to content

About

A single-binary SFTP server for ad-hoc file transfers on a trusted network. Run it in a directory, connect with any SFTP client, stop it when you're done.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

portable-sftp

A single-binary SFTP server for ad-hoc file transfers on a trusted network.

Run it in a directory, connect with any SFTP client, stop it when you're done. No daemon, no system configuration, no root privileges, no config file.

$ portable-sftp

portable-sftp v1.0.0

  serving    /home/you/Pictures  (read-write)
  listening  [::]:2222
  user       sftp
  password   cAds-L29c-W88E-KWce
             (generated for this run; set -password or $SFTP_PASSWORD to choose your own)
  host key   SHA256:PAbgL0iubsiG2h4YN1Fp9REmEGy2ai4L6q91JOvKTa4

  connect with:
    sftp -P 2222 sftp@192.168.1.2

  Ctrl-C to stop.

Why

Moving a few files between a laptop and a phone, or between two machines on the same network, is a solved problem with about six unsatisfying solutions. This is one binary you can drop anywhere and delete afterwards.

Install

Download a binary from Releases, or:

go install github.com/H7O/portable-sftp@latest

Build it yourself:

git clone https://github.com/H7O/portable-sftp
cd portable-sftp
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o portable-sftp .

CGO_ENABLED=0 produces a static binary that runs on any Linux of the same architecture. Cross-compile with GOOS/GOARCH:

GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o portable-sftp-arm64 .

Requires Go 1.25 or newer to build (it uses os.Root for path confinement).

Usage

portable-sftp [flags]
Flag Default Meaning
-root . Directory to serve
-user sftp Username clients must log in as
-password generated Password to require
-keyfile authorized_keys file to accept instead of a password
-port 2222 Port to listen on (0 picks a free one)
-bind all Address to bind; 127.0.0.1 for local only
-read-only false Refuse writes, renames, and deletions
-max-conns 10 Maximum concurrent connections
-hostkey ~/.config/portable-sftp/host_key Host key path
-stats-interval 0 Log a summary at this interval
-verbose false Log every request, including rejected ones
-version Print the version and exit

Examples

Share a folder read-only:

portable-sftp -root ~/Pictures -read-only

Use a password you choose, without putting it in your shell history or in ps:

SFTP_PASSWORD='the one you want' portable-sftp

Use key authentication:

portable-sftp -keyfile ~/.ssh/authorized_keys

Accept connections from this machine only:

portable-sftp -bind 127.0.0.1

Run it on a cloud VM for an hour, with keys only, on a port that sees less scanner traffic:

# on the VM
portable-sftp -root ~/transfer -keyfile ~/.ssh/authorized_keys -port 52222

# from your laptop
sftp -P 52222 -i ~/.ssh/id_ed25519 sftp@203.0.113.10

A client that tries a password never sees a prompt, just Permission denied (publickey). The unusual port only cuts scanner noise — it is not a control, and everything under Security still applies. If you can already reach the machine over SSH, the next example avoids exposing a port at all.

Reach it through an SSH connection you already have, instead of opening it to the network:

# on the remote machine
portable-sftp -root ~/transfer -bind 127.0.0.1 -keyfile ~/.ssh/authorized_keys

# on your laptop
ssh -f -N -L 2222:localhost:2222 you@vm
sftp -P 2222 sftp@127.0.0.1

-bind 127.0.0.1 listens on loopback only, so nothing on the network can reach the server; the SSH connection carries the traffic. The forwarded port on your laptop is loopback-only too. -f puts the forward in the background, where it stays until you kill it. The username is still sftp, not your account on the remote machine.

Authentication

If you give neither -password nor -keyfile, a strong password is generated and printed once at startup. There is no default password.

-password and -keyfile are mutually exclusive, and only the corresponding authentication method is offered to clients. -keyfile accepts a normal OpenSSH authorized_keys file, so multiple keys and comments work as expected.

Host key

A persistent Ed25519 host key is generated on first run and stored in ~/.config/portable-sftp/host_key, so your client won't warn about a changed fingerprint every time you start the server. The fingerprint is printed at startup — check it against what your client shows on first connection.

The key is deliberately kept outside the served directory, and the server refuses to start if -hostkey points inside -root, since a client could otherwise download it and impersonate the server.

Graphical file managers

GNOME Files connects from "Other Locations → Connect to Server" with a URI (Thunar, Nemo and Caja use the same GVfs backend and take the same URI in their location bar, Ctrl+L, if your distribution's gvfs backends are installed):

sftp://sftp@203.0.113.10:52222/

The username is your -user value, sftp — not your account name on either machine. Leave it out and the connection is refused. The port is required too, or the client tries 22. Through the forward above, the same URI is sftp://sftp@127.0.0.1:2222/.

With a password you get a prompt. With a key there is nowhere in the dialog to point at a key file — GVfs runs the OpenSSH client without -i, so the key has to come from your desktop session's ssh-agent (GVfs asks the keyring for it, so an agent you started yourself in a shell is not the one it uses) or from an IdentityFile line in ~/.ssh/config. A Host pattern there has to match the host as you typed it in the URI, not a friendly alias.

Through a forwarded loopback port the file manager shows no fingerprint prompt, because GVfs passes -oNoHostAuthenticationForLocalhost yes. The sftp command in the example above still prompts, and the ssh -L connection's own host key check is what authenticates the machine.

KDE's Dolphin takes the same URI form, but speaks SSH through libssh rather than the OpenSSH client, so the agent and ~/.ssh/config details above do not carry over unchanged. Windows Explorer and macOS Finder have no native sftp:// support; use WinSCP, Cyberduck, or FileZilla.

Security

This is a tool for trusted local networks. Do not expose it to the internet.

What it does

  • Serves exactly one directory. Paths are confined with os.Root, which resolves every path component through the kernel (openat2 with RESOLVE_BENEATH where available). .., absolute paths, and symlinks pointing outside the root are all rejected, with no window between checking a path and opening it.
  • Never creates symlinks or hard links on the client's behalf.
  • Offers only the authentication method you configured.
  • Compares credentials in constant time.
  • Caps concurrent connections and bounds the pre-authentication handshake.
  • Recovers from panics in a session without taking down the server.

What it does not do

  • No rate limiting on failed passwords. SSH caps attempts per connection, but nothing stops a client from reconnecting. Use the generated password or a key; don't pick a short one.
  • No encryption at rest, no auditing, no multi-user support. One user, one directory, one password or key set.
  • No protection against whoever runs it. The server has your filesystem permissions. -root is a boundary for the client, not a sandbox for you.
  • Not hardened for hostile networks. It has not been audited, and it is not a replacement for OpenSSH.

If you need a real SFTP server, use OpenSSH with ChrootDirectory.

Found a security problem? See SECURITY.md.

Development

go test ./...            # unit and end-to-end tests
go test -race ./...      # the end-to-end tests are concurrent
go vet ./...
govulncheck ./...        # go install golang.org/x/vuln/cmd/govulncheck@latest
gofmt -l .

The test suite starts real servers on ephemeral ports and drives them with a real SFTP client, including regression tests for path escapes, authentication bypasses, malformed protocol messages, and connection-limit enforcement.

License

MIT

About

A single-binary SFTP server for ad-hoc file transfers on a trusted network. Run it in a directory, connect with any SFTP client, stop it when you're done.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

⌂ 换网址