Use SFTP for an occasional, direct upload to an already-configured VPS. Use GitHub as the source of truth with GitHub Actions when releases are recurring, collaborative, tested, or need approvals and rollback. SFTP gets files onto a server quickly; GitHub-based deployment turns a commit into a repeatable release. A practical path is to begin with a scripted SFTP upload and move to GitHub-driven deployment as release frequency and operational risk increase.
Quick answer: which deployment method fits?
The choice is less about transfer speed than about how much release control you need. SFTP is a secure transport and file-placement tool. GitHub-based deployment combines version control with automated checkout, build, testing, packaging, and release steps.
As an Amazon Associate I earn from qualifying purchases.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →| Question | SFTP | GitHub Actions deployment |
|---|---|---|
| How fast is the first setup? | Usually the shortest path once SSH access and a destination directory exist. | Requires repository workflow configuration; a self-hosted runner also requires runner installation and maintenance. |
| Can releases be repeated consistently? | A batch file can repeat a copy, but the release process remains your responsibility. | The workflow records checkout, build, test, and release steps around a specific commit. |
| What identifies the deployed version? | You need your own naming, backup, or release-directory convention. | Each release can be tied to a Git commit and its workflow run. |
| Where does building and testing happen? | Commonly on your local machine before you upload the built files. | A hosted or self-hosted runner can build and test before anything reaches the VPS. |
| What can go wrong? | An interrupted transfer can leave a partially updated directory. | You add runner availability, queueing, workflow, and deployment-script failure modes. |
| Who maintains the platform? | You maintain the SSH account, keys, and release procedure. | You maintain workflow code and, for a self-hosted runner, the operating system, runner software, and installed tools. |
For a small static site updated a few times a year, SFTP is usually the proportionate answer. For a team that merges code daily, GitHub Actions pays back its setup cost through consistent builds, logs, review, and a known commit identity for every release.
What SFTP actually gives you
The current OpenBSD sftp(1) manual describes SFTP as “a file transfer program, similar to ftp(1), which performs all operations over an encrypted ssh(1) transport.” That definition captures both its strength and its boundary: SFTP securely moves files, but it does not decide which source revision is approved, run your tests, or define an application rollback model.
#1 Best Overall
Security and authentication
SFTP uses the SSH transport, so you can authenticate with a password or, preferably, a public/private key pair. Public-key authentication lets an automated batch run without putting a password in a script. The private key should remain on the deployment machine or in a protected CI secret; the VPS receives only the corresponding public key.
Interactive and batch operation
An interactive session lets you inspect directories and issue commands such as put and get. Batch mode is intended for non-interactive authentication, so a local script can upload a build directory without a graphical client. Recursive copies are supported, but the OpenBSD manual notes that recursive transfers do not follow symbolic links.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11What SFTP does not track
- It does not provide source history or code review.
- It does not prove which commit produced the files in the destination directory.
- It does not build or test your application.
- It does not automatically preserve a previous release for rollback.
You can add those controls yourself with release directories, checksums, naming conventions, and a deployment checklist. They are valuable, but they are conventions around SFTP rather than features supplied by the protocol.
How to deploy from localhost to a VPS with SFTP
This procedure assumes the VPS already runs SSH and that your application has a destination directory. Replace the example account, host, and paths with values from your server.
1. Create a restricted deployment account
Use a dedicated non-root account such as deploy. Give it ownership or write permission only for the application’s release or staging path. Keeping deployment separate from your administrator account limits the damage from a stolen key or an accidental command.
2. Create an SSH key on your local machine
ssh-keygen -t ed25519 -C deploy
Install the public key for the deployment account using your VPS provider’s console or an administrative SSH session. Test the login before attempting a file transfer:
Free tools Windows power users keep installed
One-click scans. No signup required.
ssh [email protected]
Verify the server host key on the first connection. Do not disable host-key checking merely to make an automated script run.
3. Build locally and identify the exact upload directory
Run the project’s normal production build on localhost. Upload only the output that the VPS needs—often a directory named dist, build, or public—rather than source files, local caches, and development secrets. Confirm that runtime configuration is supplied by the server in the way your application expects.
Rank #2
4. Test an interactive transfer
sftp [email protected]
mkdir /var/www/app-staging
put -r dist/* /var/www/app-staging/
bye
The remote mkdir command is illustrative: SFTP servers may require the directory to be created by an administrator first, and permissions must allow the deployment account to write there.
5. Turn the procedure into a batch file
Save a file such as release.sftp outside the repository if it contains environment-specific paths:
cd dist
lcd dist
put -r * /var/www/app-staging/
bye
Run it with:
sftp -b release.sftp [email protected]
A batch file makes the copy repeatable, but it does not make the release atomic or record a commit by itself. Add a local Git commit identifier to your release notes or directory name if you need to know exactly what was uploaded.
How to avoid a half-updated SFTP deployment
Uploading directly into the live directory is the main operational weakness of a simple SFTP release. If the connection drops halfway through, old and new files can coexist. A safer pattern is to upload into a new staging or release directory, validate it, and switch the application only after the transfer completes.
Staging-directory pattern
- Create a uniquely named directory such as
/var/www/releases/2026-10-16-1430. - Upload the complete build into that directory with SFTP.
- Check ownership, permissions, and required configuration on the VPS.
- Run a remote health check or smoke test.
- Switch a stable symlink such as
/var/www/currentto the new directory. - Keep the previous directory until the new release has been proven healthy.
The symlink switch must match the application and web-server configuration. Some applications write mutable data into the release directory; move that data to a shared path before adopting immutable release directories. If your server cannot make an atomic switch, schedule the change for a maintenance window and document the recovery command.
Rollback with SFTP-style releases
Rollback is straightforward only when previous releases still exist. Point the stable symlink back to the last known-good directory, restart or reload the relevant service if required, and investigate the failed release separately. Deleting the old tree immediately after every upload removes this safety net.
What GitHub-based deployment adds
GitHub Actions executes workflow jobs on hosted or self-hosted runners. GitHub defines a self-hosted runner as “a system that you deploy and manage to execute jobs from GitHub Actions on GitHub.” A workflow can check out a commit, run tests and builds, package an artifact, connect to the VPS over SSH, and run a release script.
Hosted versus self-hosted runners
A hosted runner is managed by GitHub for the job environment. A self-hosted runner is software installed on infrastructure you manage, such as a separate build machine or the VPS itself. Self-hosting gives you control over hardware, operating system, and tools, but you are responsible for maintaining the operating system and other software.
For a self-hosted runner on the VPS, the runner application must be installed and active, and the host must reach GitHub over HTTPS. GitHub’s current guidance states a minimum network speed of 70 kilobits per second for runner communication. If no matching runner becomes available, a queued job can wait up to 24 hours before GitHub fails it.
Why the commit becomes the release identity
The workflow checks out a specific revision rather than whatever happens to be in a local working directory. The run log can show the commit, test output, build artifact, and deployment result in one place. That is a materially stronger audit trail than “the files I uploaded this afternoon.”
Build a simple GitHub-to-VPS workflow
The exact SSH or SFTP implementation is a project choice. You can invoke standard OpenSSH commands in a workflow, use a deployment script already installed on the VPS, or package an artifact and transfer it with SFTP. The important design is the sequence: checkout, verify, build, test, transfer, release.
1. Keep deployment credentials out of the repository
Create a deployment key whose account can write only to the intended release path. Store the private key, host name, user name, and any known-hosts data as protected repository or environment secrets. Do not commit a private key, password, or production configuration file.
2. Define the workflow trigger and quality gates
Use a manual trigger while proving the process, then add a branch or tag trigger that matches your release policy. The workflow should fail before deployment when dependency installation, linting, unit tests, or the production build fails. A failed test must not leave a new live directory behind.
3. Package one explicit artifact
Build once and transfer that output. Rebuilding independently on the VPS can produce a different result because of operating-system packages, environment variables, or dependency resolution. Include a manifest containing the commit identifier and build time if operators need to identify a release from the server.
4. Transfer and activate on the VPS
The deployment step should upload to a new release directory, run server-side checks, and switch the stable path only after validation. Keep the activation script on the VPS or in a reviewed repository file, and make it safe to run twice. A rerun should either activate the same artifact or clearly report that the release already exists.
5. Add approvals where they matter
Use an environment or equivalent protection so production deployment requires the review your team expects. This is where GitHub differs most from an ad hoc SFTP command: the release can be linked to a reviewed change, a test result, and an explicit approval.
Rank #4
Self-hosted runner requirements and risks
A self-hosted runner is powerful because workflow code executes on a machine you control. It is also a security boundary that deserves the same care as an administrative server.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →- GitHub’s automatically generated token used to configure a self-hosted runner lasts one hour. Start the registration process when you are ready to install it rather than copying an old token into documentation.
- If automatic runner updates are disabled, GitHub gives a 30-day update window; after that, it may stop queueing jobs for the outdated runner.
- GitHub recommends using self-hosted runners only with private repositories. Public-repository pull requests can contain workflow code that runs on the runner, so an untrusted change could expose files, credentials, or network access on that machine.
- Keep the runner service account separate from the deployment account where practical, and limit filesystem permissions and outbound access.
Installing a runner directly on the production VPS reduces infrastructure, but it combines build execution and production hosting. A separate runner or hosted runner provides stronger isolation when the application or repository is exposed to untrusted contributors.
Credentials, permissions, and blast radius
Both approaches normally use SSH credentials. The safer design is the same in either case:
- Use a dedicated deployment account, never the root account.
- Restrict that account to the target directories and, where possible, a small set of release commands.
- Use a separate key for each environment or automation system.
- Store private keys in a local agent or CI secret store, not in source control.
- Mask secrets in workflow logs and rotate them when staff, machines, or responsibilities change.
- Keep the VPS host key under review so a man-in-the-middle warning is not hidden by an option that accepts every host.
SFTP from a developer laptop concentrates access in one person and one machine. GitHub Actions centralizes the process, but a compromised repository, runner, or workflow secret can affect every deployment the workflow is allowed to perform. Give automation only the permissions it needs.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Failure handling and troubleshooting
The SFTP connection fails before transfer
Check DNS or the server address, TCP access to the SSH port, the deployment user, and the key selected by your SSH configuration. A host-key mismatch should be investigated, not bypassed. If authentication succeeds but writes fail, inspect ownership and permissions on the destination directory.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteThe transfer stops halfway through
Do not treat the partially updated live directory as a release. Remove or quarantine the incomplete staging directory, reconnect, and upload the complete artifact again. A release-directory and symlink-switch pattern prevents the interrupted copy from becoming visible to users.
Files upload but the site still serves old content
Confirm the web server points to the directory you updated, check whether a stable symlink still targets the previous release, and reload the service only if the application requires it. Browser or CDN caching can also make a successful deployment appear stale; verify the server response directly.
The GitHub job waits and then fails
For a self-hosted runner, confirm that the runner service is online, has the required labels, and can reach GitHub over HTTPS. A matching runner that never becomes available can leave the job queued for up to 24 hours before failure.
Best Value
The workflow builds successfully but deployment fails
Separate build logs from deployment logs. Verify that the secret contains the expected key, that the VPS accepts the key for the intended account, and that the remote release directory is writable. Make the activation step fail closed: if validation fails, leave the current symlink pointing to the last known-good release.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
The self-hosted runner stops receiving jobs
Check the runner version and update policy. When automatic updates are disabled, the 30-day update window matters; after it, GitHub may stop queueing jobs for that runner. Also check disk space, service status, and whether a previous job left a process or lock behind.
Is GitHub Actions overkill for a single VPS?
It can be. If one person deploys an infrequently changed static or small application, the local build is trusted, and a manual release is acceptable, a documented SFTP batch file may be the better engineering choice. Adding a runner, workflow, secret store, and approval policy creates more moving parts than the application may need.
GitHub Actions becomes justified when any of these conditions apply:
- More than one person deploys or reviews changes.
- Every release should run the same tests and build steps.
- You need a record connecting production to a commit and workflow run.
- Rollback, approvals, or an auditable production process matters.
- Manual uploads are causing missed files, inconsistent builds, or avoidable outages.
A single VPS does not prevent automation. It only means you should keep the workflow proportionate: one repository, one release artifact, one restricted deployment account, and a small activation script can provide most of the value without a large platform.
Recommended Free Tools
A sensible migration path from SFTP to GitHub
- Document the current manual release. Record the build command, files that are uploaded, destination path, service reload, and rollback action.
- Make SFTP repeatable. Replace GUI-only steps with a batch file and a staging directory. Add a release name tied to the local commit.
- Move the build into a clean runner. Reproduce the local build in GitHub Actions and fix environment differences before enabling deployment.
- Deploy the same artifact. Transfer the workflow’s packaged output to a new release directory on the VPS.
- Add activation and rollback. Use a stable symlink or equivalent switch, preserve the previous release, and test the recovery procedure.
- Add protections last. Once the mechanics work, add environment approvals, branch or tag rules, secret rotation, and runner monitoring.
This progression preserves the useful part of SFTP—the straightforward transport—while gradually adding the source identity, tests, logs, and controls that teams usually want from GitHub.
Final decision
Choose SFTP when the job is simply “put this already-built directory on my configured VPS,” especially for an infrequent release by one operator. Choose GitHub Actions when deployment is a repeatable software-delivery process: a reviewed commit should produce a tested artifact, a logged release, and a predictable rollback path. In either case, use a restricted account, protect SSH keys, stage before activation, and keep a known-good release available.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




