SSH PowerUser Guide (PowerShell & Bash)
Last updated: April 22, 2026
Author: Paul Namalomba
- SESKA Computational Engineer
- SEAT Backend Developer
- Software Developer
- PhD Candidate (Civil Engineering Spec. Computational and Applied Mechanics)
Contact: kabwenzenamalomba@gmail.com
Website: paulnamalomba.github.io
Overview
SSH is the standard secure remote access protocol for Linux servers, Windows servers, Git remotes, bastion hosts, and encrypted file transfer. This guide targets native OpenSSH workflows on Windows and Linux, using both PowerShell and Bash where command or path behavior differs. It covers client and server setup, key-based passwordless authentication, ~/.ssh/config design, file copying with scp and sftp, advanced forwarding and jump-host patterns, and hardening practices that are actually safe in production.
It is intentionally explicit about one point that often gets mangled in low-quality tutorials: standard OpenSSH does not have a legitimate "store my plaintext password in the config file" feature. If you want to stop typing passwords, the correct pattern is key-based authentication, optionally combined with ssh-agent, IdentityFile, IdentitiesOnly, and host aliases in the SSH config.
Contents
- SSH PowerUser Guide (PowerShell \& Bash)
- Overview
- Contents
- Quickstart
- Key Concepts
- Configuration and Best Practices
- 1. What OpenSSH Components You Actually Need
- 2. Install and Verify SSH on Windows and Linux
- 3. Generate Modern Keys Correctly
- 4. Install Public Keys for Passwordless Login
- 5. SSH Config Files That Remove Repetition Safely
- 6. Server-Side SSH Hardening
- 7. File Transfer with
scpandsftp - 8. Advanced SSH Capabilities
- Security Considerations
- Examples
- Example 1: Install OpenSSH on Windows
- Example 2: Install OpenSSH on Linux
- Example 3: Generate a Key and Load It into
ssh-agent - Example 4: Install Your Public Key on a Remote Linux Host
- Example 5: Build a Clean SSH Config
- Example 6: Upload and Download Files
- Example 7: Use a Jump Host and Port Forwarding
- Troubleshooting
- Performance and Tuning
- References and Further Reading
Quickstart
- Install the OpenSSH client on your machine and the OpenSSH server on any machine that must accept inbound SSH.
- Generate an
ed25519keypair with a passphrase usingssh-keygen. - Start
ssh-agentand add the private key so you do not retype the passphrase every single session. - Install the public key into the target account's
authorized_keysfile. - Create a host alias in the SSH config so you only type
ssh myserverinstead of repeating host, user, port, and key flags. - Once key login works, disable password authentication on servers that should not accept it.
Key Concepts
- OpenSSH client: Provides
ssh,scp,sftp,ssh-keygen,ssh-agent, andssh-add. - OpenSSH server: Provides
sshd, which accepts inbound SSH sessions. - Host key: The server's identity key. It proves you are connecting to the same server you connected to previously.
- User key: Your own private/public keypair used for authentication.
known_hosts: Local file that stores trusted server host keys.authorized_keys: Remote file that stores user public keys allowed to log in.- Passwordless SSH: Usually means key-based login. It does not mean plaintext password storage in
ssh_config. ssh-agent: A local key cache that holds decrypted private keys in memory after you unlock them once.- Host alias: A friendly name in
~/.ssh/configthat expands to real connection parameters. - Jump host / bastion: An intermediate SSH host used to reach private network targets.
- Local port forward: Exposes a remote service on your local machine.
- Remote port forward: Exposes a local service on the remote machine.
- Dynamic port forward: Creates a SOCKS proxy over SSH.
Configuration and Best Practices
1. What OpenSSH Components You Actually Need
There are two separate SSH roles and they should not be confused:
- Outbound SSH: Your machine initiates a connection to another machine. You need the OpenSSH client.
- Inbound SSH: Other machines connect to your machine. You need the OpenSSH server.
For a normal developer workstation:
- install the client
- install the server only if the workstation must be reachable remotely
For a Linux or Windows server that you manage remotely:
- install both client and server
- harden the server
- keep client tooling available for Git, backups, bastions, and cross-host admin work
Useful file locations:
| Purpose | Windows | Linux |
|---|---|---|
| Client config | %USERPROFILE%\.ssh\config |
~/.ssh/config |
| Known hosts | %USERPROFILE%\.ssh\known_hosts |
~/.ssh/known_hosts |
| User authorized keys | %USERPROFILE%\.ssh\authorized_keys for standard users |
~/.ssh/authorized_keys |
| Admin authorized keys on Windows server | C:\ProgramData\ssh\administrators_authorized_keys may be used by default |
Not applicable |
| Server config | C:\ProgramData\ssh\sshd_config |
/etc/ssh/sshd_config or /etc/ssh/sshd_config.d/*.conf |
2. Install and Verify SSH on Windows and Linux
On modern Windows 10/11 and Windows Server, OpenSSH is normally installed via Windows optional capabilities. PowerShell is the cleanest way to manage it.
On Linux, package names vary slightly, but the split is consistent: client package plus server package.
After installation, verify these basics before doing anything else:
ssh -Vsshd -Ton servers where supported- service status for
ssh,sshd, orssh-agent - whether TCP port 22 is listening on hosts that should accept connections
On Windows, useful checks are:
Get-Service sshd, ssh-agentGet-NetTCPConnection -LocalPort 22Test-NetConnection servername -Port 22
On Linux, useful checks are:
systemctl status sshorsystemctl status sshdss -tlnp | grep ':22'ssh -V
3. Generate Modern Keys Correctly
Prefer ed25519 unless you have a legacy interoperability requirement.
Why:
- shorter keys
- fast operations
- strong modern default
- less parameter tuning than RSA
Recommended rule set:
- Use one primary admin key per person, not one shared team private key.
- Add a passphrase unless the key exists purely for locked-down automation.
- Name keys deliberately if you manage multiple environments.
- Keep private keys out of sync tools and source control.
Example naming patterns:
id_ed25519for your default daily keyid_ed25519_workfor a work-specific identityid_ed25519_backupfor backup automation
4. Install Public Keys for Passwordless Login
The correct passwordless pattern is:
- generate a keypair locally
- copy only the public key to the remote host
- append the public key to
authorized_keys - keep the private key private
If ssh-copy-id exists on your Bash client, use it. On Windows PowerShell, the practical equivalents are either:
- upload the public key with
scp, then append it remotely - manually append the public key after opening a one-time password session
Key file hygiene matters:
- Linux:
chmod 700 ~/.ssh,chmod 600 ~/.ssh/authorized_keys,chmod 600 ~/.ssh/config - Windows: inherited ACLs can break OpenSSH key acceptance; use
icaclsif permissions become too broad
Windows server nuance:
- if the account is in the local Administrators group, inspect
C:\ProgramData\ssh\sshd_config - many Windows OpenSSH server defaults use a
Match Group administratorsblock - that block often redirects key lookup to
C:\ProgramData\ssh\administrators_authorized_keys - if your per-user
authorized_keysfile seems ignored, this is one of the first places to check
5. SSH Config Files That Remove Repetition Safely
The SSH config file is where quality-of-life improvements live.
Good uses of the config:
- set host aliases
- pin usernames and ports
- point specific hosts at specific keys
- define jump hosts
- set keepalive options
- add local forwarding rules for repetitive workflows
Common safe directives:
| Directive | Purpose |
|---|---|
Host |
Alias block name |
HostName |
Real DNS name or IP |
User |
Remote account |
Port |
Non-default SSH port |
IdentityFile |
Private key path |
IdentitiesOnly yes |
Forces the client to offer only the chosen key |
AddKeysToAgent yes |
Convenient on clients with ssh-agent |
ServerAliveInterval 30 |
Keepalive probe interval |
ServerAliveCountMax 3 |
Disconnect after repeated failures |
ProxyJump |
Jump through a bastion host |
LocalForward |
Persistent local port forward |
ForwardAgent |
Forward your local agent, only when needed |
StrictHostKeyChecking ask |
Safer first-connection behavior |
Bad uses of the config:
- trying to store a plaintext password there
- globally disabling host-key checking
- globally enabling agent forwarding
- using a single wildcard block that silently affects every host on every network
6. Server-Side SSH Hardening
Once key-based access is verified, harden the server.
Typical minimum baseline on Linux servers:
PermitRootLogin noPasswordAuthentication noKbdInteractiveAuthentication noPubkeyAuthentication yesPermitEmptyPasswords noMaxAuthTries 3AllowUsers youradminuserorAllowGroups ssh-admins
On Windows OpenSSH Server, not every Linux-centric directive is equally relevant, but these still matter:
PasswordAuthentication noPubkeyAuthentication yesPermitEmptyPasswords noAllowUsersorAllowGroupsMaxAuthTries 3
Operational rule:
- validate config before restart
- keep one working session open while testing a second session
Typical validation commands:
- Linux:
sudo sshd -t - Windows:
sshd -t
7. File Transfer with scp and sftp
scp and sftp ride on SSH and inherit the same config, identities, and host aliases.
What to use when:
scp: fast one-shot upload or download, recursive copy, simple scriptingsftp: interactive browsing, directory navigation, multiple put/get actions in one session
Key habits:
- quote Windows paths in PowerShell if they contain spaces
- remember that remote paths are almost always POSIX-style on Linux hosts
- if you use a host alias in the config, use that alias in
scpandsftptoo - custom ports use
-Pforscpand-o Port=or config entries forsftp
8. Advanced SSH Capabilities
Once the basics are stable, SSH becomes a secure transport toolkit rather than just a remote shell.
Important advanced patterns:
- Jump hosts:
ssh -J bastion target - Local forwarding:
ssh -L 5432:127.0.0.1:5432 db-host - Remote forwarding:
ssh -R 8080:127.0.0.1:8080 host - Dynamic forwarding:
ssh -D 1080 host - Agent forwarding:
ssh -A host, use only when necessary and trusted - Connection multiplexing: powerful on Unix-like Bash clients via
ControlMasterandControlPersist
Important accuracy note:
- connection multiplexing is a Unix-centric OpenSSH optimization used heavily on Linux, macOS, and WSL clients
- it is not a core day-to-day Windows PowerShell workflow, so do not build your main Windows setup around it unless you have verified the environment supports it cleanly
Security Considerations
- Do not disable host-key verification globally:
StrictHostKeyChecking noplusUserKnownHostsFile /dev/nullis a short-lived lab shortcut, not a production habit. - Do not try to automate plaintext passwords with config files: OpenSSH is designed around keys, agents, and host aliases for a reason.
- Use separate keys for people and automation: a backup job key should not be your personal admin key.
- Use passphrases for human-operated keys: then let
ssh-agenthandle convenience. - Restrict server-side access deliberately:
AllowUsers,AllowGroups, firewall rules, and non-root administration matter more than just changing the port. - Review host key changes carefully: an unexpected host key mismatch can indicate a rebuild, an IP reuse event, or a man-in-the-middle problem.
- Treat agent forwarding as privileged delegation: if you forward your agent into an untrusted host, that host can try to use your agent while the session exists.
- Protect private keys on disk: Linux permissions and Windows ACLs both matter.
Examples
Example 1: Install OpenSSH on Windows
Use PowerShell as Administrator.
# Inspect capability state
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
# Install client and server if needed
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# Start and persist services
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
Set-Service -Name sshd -StartupType Automatic
Start-Service sshd
# Verify
ssh -V
Get-Service sshd, ssh-agent
Get-NetTCPConnection -LocalPort 22 -ErrorAction SilentlyContinue
If the inbound firewall rule does not exist or you want to create it explicitly:
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' `
-DisplayName 'OpenSSH Server (TCP 22)' `
-Enabled True `
-Direction Inbound `
-Protocol TCP `
-Action Allow `
-LocalPort 22
Example 2: Install OpenSSH on Linux
Debian or Ubuntu style:
sudo apt update
sudo apt install -y openssh-client openssh-server
sudo systemctl enable --now ssh
ssh -V
sudo systemctl status ssh --no-pager
ss -tlnp | grep ':22'
RHEL, Rocky, AlmaLinux, Fedora style:
sudo dnf install -y openssh-clients openssh-server
sudo systemctl enable --now sshd
ssh -V
sudo systemctl status sshd --no-pager
ss -tlnp | grep ':22'
Example 3: Generate a Key and Load It into ssh-agent
PowerShell:
# Generate a modern keypair
ssh-keygen -t ed25519 -a 100 -f "$HOME\.ssh\id_ed25519_work" -C "work-admin"
# Ensure the agent is running
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
# Add the key for this login session
ssh-add "$HOME\.ssh\id_ed25519_work"
# List loaded keys
ssh-add -l
Bash:
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519_work -C "work-admin"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_work
ssh-add -l
If Windows key permissions become a problem, repair them with icacls:
icacls "$HOME\.ssh" /inheritance:r /grant:r "$env:USERNAME:(OI)(CI)F" /grant:r "SYSTEM:(OI)(CI)F"
icacls "$HOME\.ssh\id_ed25519_work" /inheritance:r /grant:r "$env:USERNAME:R" /grant:r "SYSTEM:R"
Example 4: Install Your Public Key on a Remote Linux Host
Bash with ssh-copy-id:
ssh-copy-id -i ~/.ssh/id_ed25519_work.pub admin@192.168.1.50
ssh admin@192.168.1.50
PowerShell equivalent using scp plus a remote append:
scp "$HOME\.ssh\id_ed25519_work.pub" admin@192.168.1.50:/tmp/id_ed25519_work.pub
ssh admin@192.168.1.50 "umask 077; mkdir -p ~/.ssh; cat /tmp/id_ed25519_work.pub >> ~/.ssh/authorized_keys; rm -f /tmp/id_ed25519_work.pub"
ssh admin@192.168.1.50
Manual Linux-side permission repair if login still fails:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R "$USER":"$USER" ~/.ssh
Example 5: Build a Clean SSH Config
PowerShell path:
New-Item -ItemType Directory -Force -Path "$HOME\.ssh" | Out-Null
notepad "$HOME\.ssh\config"
Bash path:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
${EDITOR:-vim} ~/.ssh/config
chmod 600 ~/.ssh/config
Shared config example:
Host bastion
HostName 203.0.113.10
User ops
Port 22
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
AddKeysToAgent yes
ServerAliveInterval 30
ServerAliveCountMax 3
Host app-prod
HostName 10.10.20.15
User ubuntu
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
ProxyJump bastion
LocalForward 15432 127.0.0.1:5432
Host git-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
Then use it cleanly:
ssh app-prod
scp ./build.tar.gz app-prod:/srv/releases/
sftp app-prod
ssh -T git-work
Example 6: Upload and Download Files
PowerShell upload to Linux host:
scp -r ".\publish" app-prod:/srv/myapp/
PowerShell download from Linux host:
scp app-prod:/var/log/nginx/access.log "$HOME\Downloads\"
Bash upload:
scp -r ./publish app-prod:/srv/myapp/
Bash download:
scp app-prod:/var/log/nginx/access.log ./
Interactive sftp session:
sftp app-prod
sftp> pwd
sftp> lpwd
sftp> put ./artifact.zip
sftp> get /var/log/syslog
sftp> mkdir uploads
sftp> cd uploads
sftp> mput ./*.csv
sftp> bye
Custom SSH port example:
scp -P 2222 ./backup.tar.gz admin@example.com:/srv/backups/
Example 7: Use a Jump Host and Port Forwarding
One-off jump host connection:
ssh -J ops@203.0.113.10 ubuntu@10.10.20.15
Local forward to a remote PostgreSQL instance:
ssh -L 15432:127.0.0.1:5432 app-prod
Now your local tools can connect to 127.0.0.1:15432 while the database remains private.
Remote forward exposing a local service to the remote host:
ssh -R 18080:127.0.0.1:8080 bastion
Dynamic SOCKS proxy:
ssh -D 1080 bastion
Unix-like Bash client multiplexing example:
Host *
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
That setting can drastically reduce repeated connection startup cost on Linux or WSL clients when you perform many sequential ssh, scp, or sftp operations.
Troubleshooting
| Problem | Likely Cause | Practical Checks |
|---|---|---|
Connection refused |
sshd not running or firewall blocked |
Check service state and TCP 22 listener |
Permission denied (publickey) |
wrong key, wrong user, bad permissions, admin-key redirect on Windows | Use ssh -vvv, inspect authorized_keys, inspect Windows Match Group administrators block |
| Host key mismatch warning | server rebuilt, DNS/IP reuse, or security event | inspect known_hosts entry before deleting it |
| Key ignored on Windows | ACLs too broad or wrong authorized keys path | repair ACLs with icacls; inspect C:\ProgramData\ssh\sshd_config |
| File transfer fails but shell login works | wrong path syntax, wrong port, permissions on remote target | test with a small file first and explicit destination |
| First connection hangs | DNS, firewall, or dead route | Test-NetConnection host -Port 22 in PowerShell, ssh -vvv host in Bash |
Useful PowerShell diagnostics:
Test-NetConnection 192.168.1.50 -Port 22
ssh -vvv app-prod
Get-Service sshd, ssh-agent
Get-WinEvent -LogName 'OpenSSH/Operational' -MaxEvents 20
Useful Linux diagnostics:
ssh -vvv app-prod
sudo journalctl -u ssh -n 50 --no-pager
sudo journalctl -u sshd -n 50 --no-pager
sudo sshd -t
ss -tlnp | grep ':22'
Performance and Tuning
- Use host aliases so repetitive workflows stay readable and consistent.
- Use
ssh-agentfor human workflows instead of unencrypted private keys or no-passphrase habits. - On Unix-like Bash clients, use connection multiplexing if you run many SSH commands in short bursts.
- Use
Compression yesonly when bandwidth is tight and CPU is not the bottleneck. - Prefer
scpfor simple scripted transfers andsftpfor interactive transfer sessions. - For very large, repetitive directory synchronization on Bash systems,
rsync -e sshis often better than repeatedscp, but it is not a native Windows PowerShell-first workflow.
Example optional compression block:
Host slow-link
HostName 198.51.100.20
User ops
Compression yes
ServerAliveInterval 30
References and Further Reading
- OpenSSH manuals: https://www.openssh.com/manual.html
- Microsoft OpenSSH for Windows documentation: https://learn.microsoft.com/windows-server/administration/openssh/openssh-overview
ssh_configreference: https://man.openbsd.org/ssh_configsshd_configreference: https://man.openbsd.org/sshd_configscpreference: https://man.openbsd.org/scpsftpreference: https://man.openbsd.org/sftp