You need to move files across a network
You just finished compiling a project on your Fedora workstation and need to push the binaries to a headless server in the basement. Or maybe your laptop died and you are trying to pull your home directory from a backup machine over a flaky Wi-Fi connection. You open a terminal and reach for scp. The command hangs. Or it asks for a password every time. Or it refuses to copy a directory because of a missing flag. File transfer over SSH should be frictionless. When it breaks, it usually breaks on authentication, firewall rules, or protocol mismatches. Fix the foundation first. The transfer tools will follow.
What is actually happening under the hood
Both scp and sftp ride on top of the SSH protocol. They do not open a separate network channel. They negotiate an encrypted tunnel with the remote daemon, authenticate, and then stream data through that tunnel. Modern OpenSSH versions actually route scp through the SFTP subsystem, but the command keeps a simple cp style syntax for familiarity. sftp opens an interactive shell where you can browse, upload, and download files step by step. Think of scp as a one-way delivery truck. You load it, give it an address, and it drives off. Think of sftp as a remote terminal with a built-in file browser. You stay connected, check what is on the other side, and pull files down one by one. The encryption happens at the transport layer. Your files never touch the network in plaintext. Run ssh -v once to see the cipher negotiation. Understanding the handshake saves hours of debugging.
Set up key-based authentication first
Password prompts will break your workflow and make automation impossible. Generate an Ed25519 key pair on your local machine. This algorithm is faster and more secure than RSA, and Fedora ships with full support out of the box. OpenSSH enforces strict file permissions. If your private key is readable by other users, the client will refuse to use it.
Here is how to generate a modern key pair and lock down the permissions.
ssh-keygen -t ed25519 -C "fedora-workstation-key" -f ~/.ssh/id_ed25519
# -t ed25519 selects the modern elliptic curve algorithm
# -C adds a human-readable comment for inventory tracking
# -f specifies the exact output path to avoid overwriting existing keys
chmod 600 ~/.ssh/id_ed25519
# Restrict private key access to the owner only
# OpenSSH will silently ignore keys with group or world read permissions
Push the public key to the remote Fedora machine. The ssh-copy-id command handles the directory creation and permission fixing automatically. It also verifies the connection works before modifying the remote filesystem.
Use this command to install your public key on the remote host.
ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@192.168.1.10
# -i points to the specific public key file
# The command appends the key to ~/.ssh/authorized_keys on the remote side
# It also fixes directory permissions to 700 and file permissions to 600
After this step, both scp and sftp will authenticate silently using your key. Test it by running ssh alice@192.168.1.10. If you drop into a shell without a password prompt, the foundation is solid. Keep your private key safe. Rotate it if the machine leaves your control.
Open the remote door on Fedora
If the remote end is also running Fedora, you need to ensure the SSH daemon is active and the firewall allows the traffic. Fedora enables firewalld by default, which blocks port 22 until you explicitly whitelist the service. The daemon configuration lives in /etc/ssh/sshd_config. Never edit files in /usr/lib/ssh/. Those ship with the package and get overwritten on updates. Always modify /etc/ copies.
Run these commands on the remote Fedora server to open the door.
sudo systemctl enable --now sshd
# Enable the service to start at boot and launch it immediately
sudo firewall-cmd --permanent --add-service=ssh
# Add the SSH service to the persistent firewall configuration
sudo firewall-cmd --reload
# Apply the persistent rules to the active runtime firewall
Fedora's firewall-cmd separates runtime and persistent configurations. The --reload command is mandatory after every permanent rule change. Otherwise the runtime config and the persistent config diverge, and your rules vanish after a reboot. Check the daemon status with systemctl status sshd. It shows recent log lines and the active state in one view. Always check status before restarting.
Transfer files with scp and sftp
Now you can move data. Use scp for quick, one-off transfers. The syntax mirrors the standard cp command, with the remote host specified as user@host:/path. Progress bars show transfer speed and remaining time.
Here is how to push a local file and pull a remote directory using scp.
scp ~/documents/report.pdf alice@192.168.1.10:/home/alice/
# Copies the local PDF to the remote home directory
# Progress bar shows transfer speed and remaining time
scp -r alice@192.168.1.10:/home/alice/projects .
# -r enables recursive copying for directories
# The trailing dot tells scp to place the folder in the current working directory
When you need to inspect the remote filesystem before downloading, switch to sftp. It drops you into a dedicated prompt where local and remote paths are handled separately. This prevents accidental overwrites and makes browsing intuitive.
Start an interactive session to browse and transfer files manually.
sftp alice@192.168.1.10
# Opens an encrypted SFTP session over the established SSH connection
Inside the prompt, you will see sftp>. Type ls to list remote files and lls to list local files. Use get to download and put to upload. Type lcd ~/Downloads to change your local working directory without affecting the remote path. Type bye to close the session.
For scripted transfers, pipe commands into sftp using a heredoc. This keeps automation clean without spawning a full shell or writing temporary batch files.
Pass a batch of commands to sftp non-interactively.
sftp alice@192.168.1.10 <<'EOF'
cd /home/alice/uploads
put /home/user/data.csv
bye
EOF
# The heredoc feeds commands directly to the sftp stdin
# Single quotes around EOF prevent local shell variable expansion
# bye cleanly terminates the SFTP subsystem and closes the SSH channel
Verify the transfer
Check the remote filesystem and compare file sizes. A quick ls -lh on both sides confirms the transfer completed. If you are moving critical data, verify the checksum. Run sha256sum report.pdf locally, copy the output, and run the same command on the remote machine. The hashes must match exactly. Network drops can corrupt files silently. Trust the hash, not the progress bar. Run sha256sum on both ends. Matching hashes prove the tunnel did not corrupt the payload.
Common pitfalls and exact error messages
Connection failures usually fall into three categories. First, the remote firewall drops the packet. You will see ssh: connect to host 192.168.1.10 port 22: Connection timed out. This means the packet never reached the machine. Check firewall-cmd --list-all and verify the router is not blocking the port. Second, the SSH daemon refuses the key. The terminal prints Permission denied (publickey). This almost always means the remote ~/.ssh directory has permissions wider than 700, or the authorized_keys file is wider than 600. OpenSSH enforces strict ownership rules. Third, the transfer stalls at a specific file. scp will print scp: /path/to/file: Permission denied if the remote user lacks read access. Run ls -l on the remote side to check ownership.
If you see [FAILED] Failed to start sshd.service during boot, your SSH configuration probably references a missing host key or an invalid cipher. Run journalctl -xeu sshd to read the exact failure reason. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Fix the permission context with restorecon -Rv ~/.ssh. Run journalctl first. Read the actual error before guessing.
When to use this versus alternatives
Use scp when you need a quick, one-line command to push or pull a single file or directory. Use sftp when you need to browse the remote filesystem interactively or transfer files in batches without leaving the session. Use rsync over SSH when you are syncing large directories, need compression, or want to resume interrupted transfers. Use ssh alone when you only need remote command execution and do not care about file movement. Stay on scp for simple scripts that require minimal dependencies. Switch to rsync when bandwidth is limited or network stability is poor.