Skip to content

eiserv/easySFTP

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

easySFTP

CI License: MIT

Fast, secure and simple SFTP uploads for GitHub Actions.

Deploy your build output to any SFTP server, from a three-line workflow step up to fully configured multi-target deployments.

  • Fast: written in Go, files are transferred in parallel with concurrent SFTP write requests per file.
  • 🔒 Secure: optional host key pinning verifies the server's identity; atomic per-file uploads never leave half-written files; credentials are only ever read from environment variables.
  • 🧩 Simple, but configurable: sensible defaults for the simple case; gitignore-style excludes, sync/clean strategies, delete guards, dry runs, retries and outputs for the complex ones.
  • 🖥️ Cross-platform: runs natively on ubuntu-*, macos-* and windows-* runners, with no Docker required.

Table of contents

Why easySFTP?

I needed an SFTP upload step for a GitHub Actions deploy, and none of the existing options really fit. They were either no longer actively maintained, not resource-friendly, hard or barely configurable, or they simply did not work reliably. So I built my own and made it available for everyone with the same problem: an action that stays out of your way for the simple case and still handles the complex ones.

Here is how easySFTP compares to other open-source actions that tackle the same job:

Feature easySFTP Dylan700/sftp‑upload‑action SamKirkland/FTP‑Deploy‑Action wlixcc/SFTP‑Deploy‑Action wangyucode/sftp‑upload‑action
Protocol SFTP SFTP FTP / FTPS only SFTP SFTP
Implementation Go binary Node.js Node.js Docker (rsync) Python
Linux / macOS / Windows yes / yes / yes yes / yes / yes yes / yes / yes Linux only (Docker) needs Python on runner
Host key verification yes (pinned fingerprints) no n/a not documented not documented
Atomic per-file upload yes no no rsync temp file no
Skip unchanged files yes (SHA256 manifest) no yes (state file) partial (rsync) yes (MD5 hashes)
Delete removed files yes (tracked, via sync) yes (full wipe) yes yes (full wipe) yes (tracked)
Delete safety guards yes (root refusal, max_deletes) no no no no
Multiple targets / strategies yes (config file) multiple mappings single directory single directory single directory
Dry run yes no yes no no
Actively maintained yes last release 2024 yes yes yes

The matrix reflects each project's public documentation as of July 2026. "Not documented" means the feature was not found in that action's README, not that it is impossible. SamKirkland's FTP-Deploy-Action is by far the most popular deploy action, but it speaks FTP/FTPS rather than SFTP, so it is listed for context rather than as a direct SFTP alternative.

easySFTP is a clean, from-scratch implementation in Go, inspired by the no-longer-maintained Dylan700/sftp-upload-action:

  • compiled static binary instead of a Node.js runtime (fast startup, parallel transfers)
  • works on Linux, macOS and Windows runners, with no Docker required
  • host key verification, atomic uploads, retries with backoff, structured outputs and a job summary
  • end-to-end test suite against an in-process SFTP server, plus a CI self-test against a real OpenSSH server

Quick start

- name: Deploy via SFTP
  uses: eiserv/easySFTP@v1
  with:
    server: sftp.example.com
    username: ${{ secrets.SFTP_USERNAME }}
    password: ${{ secrets.SFTP_PASSWORD }}
    uploads: ./dist/ => /var/www/html/

That's it. Everything else is optional. More recipes (key auth, multi-target deploys, PR previews, .sftpignore) live in docs/examples.md.

Inputs & outputs

The most used inputs:

Input Default Description
server / port / username - / 22 / - Where and as whom to connect.
password / private-key / passphrase - Authentication, at least one of password/key. Use secrets.
host-key-fingerprint - Pin the server's SHA256 host key(s). Strongly recommended.
uploads - One local => remote mapping per line; directories are recursive.
strategy overlay How the remote side is reconciled: overlay, sync or clean.
ignore / ignore-from - Gitignore-style excludes (inline / from a file).
dry-run false Log what would happen, change nothing.
concurrency / retries / timeout 4 / 2 / 30 Parallelism, per-file retries, connection timeout (s).

Outputs: files-uploaded, files-deleted, files-skipped, bytes-uploaded, duration-ms, plus a summary table in the job summary.

➡ Full reference with every input, output and rule: docs/configuration.md

Strategies

Strategy Uploads Deletes Use for
overlay (default) all files nothing adding/updating files, leaving everything else in place
sync new & changed files files a previous sync uploaded but that are now gone locally keeping a directory an exact mirror of your build, safely
clean all files everything in the remote target first a guaranteed-fresh deploy

sync is manifest-based: it only ever deletes files it uploaded itself, skips unchanged files by content hash, and re-deploys only transfer what changed. Destructive strategies are protected by delete guards: the remote root is always refused, and max_deletes caps how much a single run may delete. Preview anything with dry-run: true.

➡ Details, manifest semantics and guard rules: docs/strategies.md

Config file for multiple targets

Multiple targets with different strategies? Point config-file at a YAML file (connection settings stay in inputs/secrets):

# .github/easysftp.yml
version: 1
guards:
  max_deletes: 200
targets:
  - local: ./dist/
    remote: /var/www/html/
    strategy: sync
  - local: ./docs/
    remote: /var/www/docs/
    strategy: clean

A JSON Schema for editor autocomplete/validation is bundled. See docs/configuration.md and the commented example config.

Security

Two rules cover most of it:

  1. Pin the host key. Without host-key-fingerprint, any server is accepted. Set it so a man-in-the-middle fails the deploy instead:

    $ ssh-keyscan sftp.example.com | ssh-keygen -lf -
  2. Keep credentials in encrypted secrets, prefer key-based auth, and use a least-privilege deploy account.

➡ Full guide (key setup, chroot, SHA pinning): docs/security.md · Vulnerability reports: SECURITY.md

Documentation

Configuration reference All inputs, outputs, mappings, ignore rules, config file.
Strategies overlay/sync/clean, manifest, delete guards, dry runs.
Examples & use cases Copy-paste recipes for common deployments.
Security guide Host key pinning, credentials, supply chain.
Troubleshooting & FAQ Common errors and fixes.

Versioning

easySFTP follows Semantic Versioning:

uses: eiserv/easySFTP@v1        # latest 1.x, recommended, gets fixes & features
uses: eiserv/easySFTP@v1.2.3    # exact, immutable pin

v1/v1.2 are rolling tags; v1.2.3 and commit SHAs never move. Releases and the changelog are generated automatically from Conventional Commits. See docs/RELEASING.md.

Contributing

Contributions are welcome! See CONTRIBUTING.md for the dev setup, test suite and PR conventions, and the good first issues for places to start. This project follows a Code of Conduct.

License

MIT

About

Fast, secure and simple SFTP uploads for GitHub Actions

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages