Use scp ./file user@host:/path to copy a local file to a remote host. Uppercase -P selects the SSH port; lowercase -p only preserves times and modes.
You're probably moving a database dump, uploading a release, or watching a large archive fail near completion. The command is straightforward. The production questions are harder: which paths can that account reach, what happens after an interruption, and how will you prove the destination contains the correct file?
Table of Contents
- Copy a Single File with scp and the Right Port Flag
- Choosing Between scp, SFTP and rsync for Your Transfer
- How to Copy a Directory Tree Without Breaking Links or Permissions
- How to Verify and Resume a Large File Transfer
- Common Errors and How to Fix Them
- Set Up a Restricted Transfer Account Before You Automate
Copy a Single File with scp and the Right Port Flag
scp ./backup.sql admin@example.com:/var/backups/
This copies a local database backup into the remote directory using SSH authentication and encryption. The remote operand identifies the user, host, and destination path; authentication must succeed, and the account needs write permission on the destination directory.
Confirm access before copying
- Run
ssh admin@example.comusing the account intended for the transfer. Verify the server fingerprint through an independent administrative channel before trusting a new host. - Protect the local private key with
chmod 600 ~/.ssh/id_ed25519. Use your actual key filename if it differs. - Check the destination with
ssh admin@example.com 'ls -ld /var/backups && test -w /var/backups'. A successful listing followed by a successful exit confirms that this account can write there.
Don't solve a permissions failure by switching the transfer to root. Choose a writable staging directory or correct the intended account's access.
Common scp copy scenarios and exact syntax
| Scenario | Command | What to watch |
|---|---|---|
| Local file to remote directory | scp ./backup.sql admin@example.com:/var/backups/ | Account needs destination write permission |
| Remote file to local directory | scp admin@example.com:/var/log/app.log ./logs/ | Account needs source read permission; create the local directory first |
| Nonstandard SSH port | scp -P 2222 ./backup.sql admin@example.com:/var/backups/ | Uppercase selects the port |
| Rename on arrival | scp ./report.pdf admin@example.com:/srv/share/q1-report.pdf | Destination includes the new filename |
| Preserve times and modes | scp -p ./config.yml admin@example.com:/etc/app/ | Preserves metadata, not ownership or access authorization |
| Compressed text transfer | scp -C ./dump.sql admin@example.com:/var/backups/ | Compressible text uses fewer transferred bytes at the cost of endpoint CPU |
| Directory tree | scp -rp ./release/ deploy@example.com:/srv/www/ | Follows symbolic links |
| Between remote hosts | scp admin@host1:/data/file.tar admin@host2:/data/ | Current OpenSSH routes through the local host by default; direct mode requires source-to-destination access |
The remote-to-remote distinction matters. Don't assume the source must authenticate to the destination unless you've selected direct transfer mode. Check the installed client's manual before carrying older routing assumptions into automation.
For repeated work, put a per-host Port entry in your SSH client configuration instead of typing it into every command. ARPHost's SSH default port guide covers the port-selection problem.
Practical rule: Test with the same account, key, port, and destination that the automated job will use. An administrator's successful login proves little about a restricted transfer account.
Choosing Between scp, SFTP and rsync for Your Transfer
| Criterion | scp | SFTP | rsync over SSH |
|---|---|---|---|
| Best fit | One-off file or small directory | Browsing and multiple file operations | Large files, unstable links, repeat synchronization |
| Resume after interruption | No explicit resume workflow; may restart | Partial downloads and uploads can continue | Retains partial data when configured |
| Directory handling | Recursive copying follows symbolic links | Recursive transfers depend on client options | Archive mode preserves symbolic links |
| Metadata | Times and modes with preservation enabled | Depends on client and options | Archive metadata, subject to privileges and filesystem support |
| Incremental sync | No | No | Size and modification time by default |
| Checksum comparison | Independent check afterward | Independent check afterward | Optional checksum scan before sending |
| Remote requirement | SSH server with compatible transfer support | SSH SFTP subsystem | SSH command execution and rsync on both ends |
| Port syntax | scp -P 2222 | sftp -P 2222 | rsync -e 'ssh -p 2222' |
Choose for the workflow, not the name
Use scp for a straightforward one-off upload. Use SFTP when you need to inspect directories, rename files, or perform several operations without opening separate connections.
Use rsync over SSH for backups, VM images, large archives, and repeated synchronization. The practical starting point is rsync -aP -e 'ssh -p 22' source/ user@host:/destination/.
Rsync must exist on both endpoints. A chrooted, SFTP-only account typically can't execute it, even when authentication succeeds. That's an authorization boundary, not a broken transfer client.
Current OpenSSH scp uses SFTP internally, so choosing between those clients is primarily a workflow decision, not a choice between encrypted and unencrypted transport. Legacy-only appliances may require scp -O; test that compatibility explicitly before scheduling a job.
Record versions and select the right checks
Run ssh -V and rsync --version locally. Where shell access is permitted, record the remote output with ssh admin@example.com 'ssh -V; rsync --version'.
Rsync normally decides whether a file needs updating from its size and modification time. Add checksum comparison when content might change without those attributes changing, for example with rsync -acn ./dataset/ admin@example.com:/data/dataset/.
Don't describe archive mode as preserving every possible filesystem attribute. Ownership restoration depends on privilege, and specialized metadata needs separate consideration.
An interrupted scp may start again from the beginning. Rsync with retained partial data, or SFTP resume operations against a matching partial file, can avoid retransmitting the entire file.
How to Copy a Directory Tree Without Breaking Links or Permissions
Recursive copying isn't the same as preserving a directory tree's structure. Scp follows symbolic links encountered during traversal, potentially copying their targets rather than retaining the links. That behavior and its metadata-preservation options are documented in the OpenBSD scp manual.
A deployment needs a filesystem check before it needs a faster copy.

Inspect, stage, and publish
- Inspect links. Run
find ./release -type l -ls. Empty output removes the symbolic-link concern, but doesn't prove permissions or application correctness. - If links must remain links, use
rsync -a ./release/ deploy@example.com:/srv/www/release/. Check that link targets will also make sense on the destination. - For a tree without that requirement, run
scp -rp ./release/ deploy@example.com:/srv/www/. - Inspect the result with
ssh deploy@example.com 'find /srv/www/release -maxdepth 2 -type f -printf "%M %u:%g %s %pn"'. Compare it withfind ./release -maxdepth 2 -type f -printf "%M %u:%g %s %pn"locally. Increase the listing depth for deeper trees. - For live deployment, upload into a separate release directory:
rsync -a ./release/ deploy@example.com:/srv/www/releases/candidate/. Verify it before changing the live link.
Switching a live symlink after verification avoids exposing a directory while you're still copying into it. On GNU/Linux, ssh deploy@example.com 'ln -sfnT /srv/www/releases/candidate /srv/www/current' replaces the intended link rather than following a directory target. Confirm that the live path is a symlink before running it.
Keep rollback independent of the upload
Retain the previous release. Roll back with ssh deploy@example.com 'ln -sfnT /srv/www/releases/previous /srv/www/current', leaving the candidate available for inspection.
On multi-tenant infrastructure, treat links into another account's paths as an access-review trigger. Run the link inspection on every deployment, not just the initial setup. For related filesystem operations, see moving a directory in Linux.
How to Verify and Resume a Large File Transfer
rsync -ani ./dataset/ admin@example.com:/data/dataset/
Start with a dry run. It lists proposed changes without writing them, which is particularly useful when a mistaken destination could overwrite another workload's files.
Watch the destination and publication state, not just the progress display.

Transfer into staging and verify before publishing
- Retain interrupted data separately. Run
rsync -aP --partial-dir=.partial ./dataset/ admin@example.com:/data/dataset/. Rerun the same command after an interruption. Keep consumers away from the staging tree until verification finishes. - For a single archive, use
rsync -aP --partial-dir=.partial ./backup.tar admin@example.com:/data/backup.tar.part. The temporary name prevents consumers from mistaking an unfinished upload for the published archive. - Compare
sha256sum ./backup.tarlocally withssh admin@example.com 'sha256sum /data/backup.tar.part'. The hash strings must match. Also compare file sizes and confirm that the source wasn't modified during the transfer. - Publish only after those checks:
ssh admin@example.com 'mv /data/backup.tar.part /data/backup.tar'. Keep both names on the same filesystem for an atomic rename, and retain the previous published archive separately if rollback matters.
Rsync's reconstruction checksum is distinct from the optional pre-transfer checksum scan. Neither proves that the source archive is usable by your application. A database backup still needs an appropriate restore test.
For a visual companion to the transfer workflow, use the following walkthrough.
Resume SFTP and retain evidence
Reconnect with sftp admin@example.com. Inside the session, use reget /data/backup.tar ./backup.tar for a partial download, or reput ./backup.tar /data/backup.tar.part for a partial upload. Resume only when the partial file belongs to the same unchanged source.
Record the command, account, host fingerprint, timestamp, exit status, and verification result. The SUSE SSH administration guide is a useful operational reference for SSH-based access and transfers.
If validation fails, don't publish. Remove the rejected staging file with ssh admin@example.com 'rm /data/backup.tar.part', inspect the job-specific partial directory, and retry without disturbing the previous archive.
Exit code 0 proves transport success, not business-level correctness. Keep independent verification in the job rather than relying on an operator to remember it under deadline.
Common Errors and How to Fix Them
Permission denied (publickey) means the connection reached authentication, but the server didn't accept an offered identity. That's a different failure from an authenticated account being unable to write its destination.
Use the following order as a practical triage sequence, not a measured frequency ranking.
| Symptom | Likely cause | Fix |
|---|---|---|
| Permission denied (publickey) | Wrong user, missing authorized key, or wrong identity offered | Confirm the username and key installation; inspect verbose authentication output |
| Permission denied on destination path | Account lacks directory write permission | Inspect ownership and modes; use an approved writable path |
| Connection refused | Wrong port or no listener | Check the listener and daemon configuration before restarting |
| Connection timed out | Blocked port or unreachable host | Test connectivity, then inspect routing and firewall policy |
| Host key verification failed | Changed server identity or possible interception | Independently confirm the fingerprint before correcting the saved key |
| Protocol error or unknown option on appliance | Incompatible client or legacy-only endpoint | Test legacy mode only when the client supports it |
| No space left on device | Destination filesystem exhausted | Inspect capacity and choose an approved cleanup or destination |
| Link becomes target contents | Recursive scp followed the link | Use an appropriate link-preserving transfer and inspect the result |
Separate listener, authentication, and path problems
On the server, run ss -ltnp | grep ':2222'. A matching listener should identify the intended listening endpoint; no output means there's no matching entry in that listing.
Validate configuration with sshd -t before applying changes. Successful validation normally produces no output, but it doesn't prove the firewall permits access. The OpenSSH daemon manual documents daemon testing and configuration.
From the client, run nc -vz example.com 2222. A successful connection establishes TCP reachability, not SSH authentication.
Then run ssh -vvv -p 2222 admin@example.com 'id && command -v sftp-server'. Inspect which identity was offered and whether authentication succeeded. A missing executable path isn't conclusive evidence that SFTP is unavailable, because the server may use its internal subsystem.
Finally, run ssh -p 2222 admin@example.com 'ls -ld /var/backups; df -h /var/backups'. Check the account's directory access and the destination mount's available space.
Correct identity problems without weakening verification
The lowercase versus uppercase port flag is an easy self-inflicted failure. Check the actual endpoint in verbose output before changing firewall rules.
After a verified rebuild, remove a stale default-port entry with ssh-keygen -R example.com. For a custom port, use ssh-keygen -R '[example.com]:2222'. Reconnect only after independently confirming the replacement fingerprint.
On shared infrastructure, rebuilds and endpoint reassignment are plausible explanations for host-key changes, not permission to ignore them. Escalate when you can't verify identity, lack server-side access, see unexplained hash mismatches, or need to change isolation policy to finish a copy.
Set Up a Restricted Transfer Account Before You Automate
A working copy isn't necessarily a secure workflow. Encryption protects the connection, but an unrestricted stolen key can expose everything its account can access. An upload account can also overwrite existing files or consume storage unless you constrain it.
Match account permissions to the job rather than reusing an administrator's identity.

| Scenario | Account design | Controls to add |
|---|---|---|
| Vendor file exchange | Dedicated SFTP-only user with directory confinement | Upload policy, quota, key removal at contract end |
| Automated backup push | Dedicated key with restricted rsync or forced command | Source restriction, disabled terminal and forwarding |
| Shared hosting customer | Separate confined SFTP account per site | Quota and no access to other document roots |
| CI or deployment pipeline | Deploy user limited to release storage | Key rotation, no sudo rights, retained deployment logs |
| Administrator maintenance | Personal passphrase-protected key | Individual audit trail and offboarding removal |
Enforce confinement and test the negative case
For an existing transfer group, add a Match Group sftponly block to the SSH daemon configuration. Set ChrootDirectory /srv/transfer/%u, ForceCommand internal-sftp, AllowTcpForwarding no, and X11Forwarding no within that block.
The chroot and every parent directory must be root-owned and not writable by the transfer user. Give the account a separate writable upload directory. For an existing user named vendor, an administrator can prepare it with install -d -o root -g root -m 755 /srv/transfer/vendor followed by install -d -o vendor -g sftponly -m 750 /srv/transfer/vendor/upload.
Validate with sshd -t before reloading through the distribution's service manager. Test using sftp vendor@example.com, then confirm that ssh vendor@example.com id cannot execute the shell command.
Maintain the restrictions after handover
Use a dedicated key per job. Authorized-key restrictions such as no-pty and no-port-forwarding limit capabilities, but don't independently restrict filesystem access; a source-address restriction can further narrow approved origins.
Rotate keys, remove retired vendor credentials, apply quotas, and review journalctl -u sshd or journalctl -u ssh, depending on the distribution. A changed port isn't a substitute for these controls. For related account setup, consult SFTP access through an SSH server.
ARPHost, LLC offers infrastructure hosting and managed services for teams that need transfer accounts, SSH access, and operational controls maintained after deployment. If your copy jobs depend on shared administrator keys or unverified uploads, visit ARPHost, LLC to discuss scoped accounts, transfer validation, logging, and a rollback process that fits your servers. Bring the failing command and account requirements so the discussion starts with the actual workflow.

Leave a Reply
You must be logged in to post a comment.