From 太極
Jump to navigation Jump to search


Best security practices

The Best Ways to Secure Your SSH Server

Top 20 OpenSSH Server Best Security Practices

  1. Use SSH public key based login
  2. Disable root user login
  3. Disable password based login
  4. Limit Users’ ssh access
  5. Disable Empty Passwords
  6. Use strong passwords and passphrase for ssh users/keys
  7. Firewall SSH TCP port # 22
  8. Change SSH Port and limit IP binding
  9. Use TCP wrappers (optional)
  10. Thwart SSH crackers/brute force attacks such as using fail2ban and DenyHosts software
  11. Rate-limit incoming traffic at TCP port # 22 (optional)
  12. Use port knocking (optional)
  13. Configure idle log out timeout interval
  14. Enable a warning banner for ssh users
  15. Disable .rhosts files (verification)
  16. Disable host-based authentication (verification)
  17. Patch OpenSSH and operating systems
  18. Chroot OpenSSH (Lock down users to their home directories)
  19. Disable OpenSSH server on client computer
  20. Bonus tips from Mozilla

Install OpenSSL

How to Install the latest OpenSSL version from Source on Linux

Install ssh client

sudo apt install openssh-client


How to open ssh port using ufw on Ubuntu/Debian Linux

sudo ufw allow ssh
# OR
sudo ufw allow 22/tcp

How to limit SSH connections with ufw

How to limit SSH (TCP port 22) connections with ufw on Ubuntu Linux

Configuration file ~/.ssh/config, avoid ssh connection timeout

Put the following in your ~/.ssh/config.

Host remotehost
  Port 4242
  User abcd
  IdentityFile "~/.ssh/id_rsa"
  ForwardX11 yes
  Compression yes
  TCPKeepAlive yes

    User YourUserName
    IdentityFile ~/.ssh/YourGithubSSHKey

After that we can run ssh remotehost.

To enable it for all hosts use:

Host *
  ServerAliveInterval 240

Also make sure to run chmod 600 ~/.ssh/config

Change to a different port

$ sudo nano /etc/ssh/sshd_config  # looking for the line containing port 
$ sudo service ssh restart # tested on Ubuntu 14.04

Remember to change the Router settings.

On the client PC, use ssh [email protected] -p NEWPORT for a connection.

For security reason, use the port < 1024 (privileged ports and can only be opened by root)

ProxyJump, DynamicForward

How to Manage an SSH Config File in Windows and Linux

ssh alias

  • Using linux's alias; eg put the following inside ~/.bashrc or ~/.zshrc
alias sshnocheck='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'

With this trick, ssh and scp (scp alias_name:Downloads/myfile .) work perfectly.

Modify ~/.ssh/config

Host *
  ServerAliveInterval 120
  ServerAliveCountMax 30

Host your-alias_name
  User username
  Port 50001
  IdentifyFile ~/.ssh/id_file
  ServiceAliveInterval 120

Host work
  User abcde
  ServiceAliveCountMax 5
  StrictHostKeyChecking yes

According to the man of ssh_config:

  • ServerAliveCountMax: Sets the number of server alive messages (see below) which may be sent without ssh(1) receiving any messages back from the server. If this threshold is reached while server alive messages are being sent, ssh will disconnect from the server, terminating the session.
  • ServerAliveInterval: Sets a timeout interval in seconds after which if no data has been received from the server, ssh(1) will send a message through the encrypted channel to request a response from the server. The default is 0, indicating that these messages will not be sent to the server.

Running commands on a remote host

ssh [email protected] 'COMMANDS'

ssh [email protected] "command1; command2; command3"

COMMANDS="command1; command2; command3"
ssh [email protected] "$COMMANDS"

A practical example



for IP in $IP_LIST;
  utime=$(ssh ${USER}@${IP} uptime  | awk '{ print $3 }' )
  echo $IP uptime:  $utime

Disable root log in

Modify /etc/ssh/sshd_config. Change this line:

#PermitRootLogin yes


PermitRootLogin no

and run /etc/init.d/sshd restart.

However, that line in my Ubuntu is

PermitRootLogin without-password

According to this post, “without-password” means password authentication is disabled for root.

ssh log files

It is also helpful to check /etc/hosts.allow and /etc/hosts.deny for any possible wrong configuration.

Note that auth.log can show ssh security attacks.

$ grep sshd /var/log/auth.log
Feb 19 11:04:12 phenom sshd[16922]: Failed password for root from port 49383 ssh2
Feb 19 11:04:12 phenom sshd[16922]: Received disconnect from 11: Bye Bye [preauth]
Feb 19 11:04:14 phenom sshd[16924]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=  user=root

Feb 19 11:04:36 phenom sshd[16998]: Invalid user enea from
Feb 19 11:04:36 phenom sshd[16998]: input_userauth_request: invalid user enea [preauth]
Feb 19 11:04:37 phenom sshd[16998]: pam_unix(sshd:auth): check pass; user unknown
Feb 19 11:04:37 phenom sshd[16998]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost= 
Feb 19 11:04:39 phenom sshd[16998]: Failed password for invalid user enea from port 36090 ssh2
Feb 19 11:04:39 phenom sshd[16998]: Connection closed by [preauth]
Feb 19 11:05:11 phenom sshd[17060]: refused connect from (
Feb 19 11:05:55 phenom sshd[17353]: refused connect from (
Feb 19 11:06:38 phenom sshd[17732]: refused connect from (
Feb 19 11:07:20 phenom sshd[17850]: refused connect from (
Feb 19 11:07:40 phenom sshd[17874]: refused connect from (
Feb 19 11:08:01 phenom sshd[17955]: refused connect from (
Feb 19 11:08:41 phenom sshd[18118]: refused connect from (
Feb 19 11:09:22 phenom sshd[18280]: refused connect from (
Feb 19 11:10:02 phenom sshd[18353]: Invalid user support from
Feb 19 11:10:02 phenom sshd[18353]: input_userauth_request: invalid user support [preauth]
Feb 19 11:10:02 phenom sshd[18353]: pam_unix(sshd:auth): check pass; user unknown
Feb 19 11:10:02 phenom sshd[18353]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost= 
Feb 19 11:10:03 phenom sshd[18424]: refused connect from (
Feb 19 11:10:04 phenom sshd[18353]: Failed password for invalid user support from port 54218 ssh2
Feb 19 11:10:05 phenom sshd[18353]: fatal: Read from socket failed: Connection reset by peer [preauth]
Feb 19 11:10:07 phenom sshd[18425]: Did not receive identification string from
Feb 19 11:10:17 phenom sshd[18443]: Address maps to, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!


Note that denyhosts package is no longer available in Ubuntu 14.04, 16.04 now. We can install install from its source DenyHosts-2.6.tar.gz.

Procedures: follow the README.txt file.

Log in history: last command

The following command also shows how long a user has been logged in.

last <username> | less

w/who can show who (and when) are currently logging in.

Generate a strong password

5 Ways To Generate A Random/Strong Password In Linux Terminal: pwgen, openssl, gpg, mkpasswd, makepasswd, ...

Put in your ~/.bashrc. See Top 20 OpenSSH Server Best Security Practices.

$ genpasswd() {
	local l=$1
       	[ "$l" == "" ] && l=20
      	tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
$ genpasswd 16

login banners/messages

There are two types of banners you can configure.

Banner message to display before user log in (configure in file of your choice eg. /etc/login.warn) Banner message to display after user successfully logged in (configure in /etc/motd)

ssh -A: forwarding of the authentication agent connection

Two-factor authentication

X11 forwarding

  • Mac connect to Linux
    • On Mac Mojave 10.14.6 (client side), I need to use -Y option (Enables trusted X11 forwarding) because "-X" does not work. The answer was found when I use "-v" option in ssh.
    • The 'ForwardX11' option in ~/ssh/config file does not help.
  • Linux connect to Linux does not have a problem.

Bypass SSH password login (convenient for CVS, git etc)

  1. ssh-keygen -t rsa
  2. (make sure the remote server has .ssh directory)
  3. cat ~/.ssh/ | ssh [email protected] 'cat >> .ssh/authorized_keys'
  4. ssh [email protected]

It helps with CVS log in too when the CVS works by using ssh protocol. Note that step 3 allows to run a shell command at a remote machine.

See also for similar instruction when work on github.

The ssh key can be copied to another a machine (pay attention to mode). Or let the new machine to create its own key pair and use ssh-copy-id to append the identity file to remote machine's ~/.ssh/authorized_keys file. See

We can even have multiple ssh key on local machine by using <.ssh/config> file. See

Allow for a user

How to Enable/Disable SSH access for a particular user or user group in Linux

SSH file server

How to create a personal file server with SSH on Linux

SSHFS: mount a remote file system over ssh

ssh key

SSH key is useful if you want a password-less login to a remote system. Some useful resources:

Also there are different kinds of keys (see for example <~/.ssh/known_hosts file>): RSA, DSA and ECDSA (newer). They're keys generated using different encryption algorithms. See SSH key-type, rsa, dsa, ecdsa, are there easy answers for which to choose when?

The steps are

  • Check if there is an existing key
ls -al ~/.ssh
  • Create a new RSA key pair:
ssh-keygen -t rsa
ssh-keygen -f ~/.ssh/personalid -C "bitbucket"

where the comment 'bitbucket' will appear at the end of <~/.ssh/personalid> file.

  • Copy the public key to a remote host ([email protected]) over ssh. The current user (eg brb) and the remote user (eg git)have not any relationship (they most likely have different user names):
ssh-copy-id -i ~/.ssh/ [email protected] # this will 'append' the key to the remote-host’s .ssh/authorized_key.

Or (may not work:()

cat ~/.ssh/ | ssh [email protected] "mkdir -p ~/.ssh && cat >>  ~/.ssh/authorized_keys"
  • Delete the authorized key. Open the text file '.ssh/authorized_keys' and remove the offending lines.
  • Test if this is working by trying 'ssh [email protected]'.
  • To disable the password for root login. Type sudo nano /etc/ssh/sshd_config
PermitRootLogin without-password

Then run the following to put the changes into effect:

reload ssh
# Or service ssh restart

If we like to ask all users to use key-based to log in, we can modify the line

PasswordAuthentication no

in sshd_config.

Default key file

Force SSH Client To Use Given Private Key ( identity file )

The default is ~/.ssh/identity for protocol version 1, and ~/.ssh/id_rsa and ~/.ssh/id_dsa for protocol version 2.

Multiple ssh keys and ssh-add; ssh-agent

<Method 1> If we want to use a specific key in ssh, use

ssh -i ~/.ssh/xxx_id_rsa [email protected]

<Method 2> Another way is to use ssh-add & ssh-agent to manager your keys. ssh-agent keeps your key in its memory and pulls it up whenever it is asked for it.

$ ssh-keygen -f ~/.ssh/personalid -C "bitbucket"
$ eval $(ssh-agent -s)       # Ensure ssh-agent is enabled:
$ ssh-add ~/.ssh/personalid  # ssh-add program will ask you for your passphrase

$ ssh-add -l  # Display the entries loaded in ssh-agent

<Method 3> <~/.ssh/config> file.

ssh key management

Copy ssh keys to another computer

# Copy
$ ssh-copy-id -p 22 -i ~/.ssh/ [email protected]

# Test
$ ssh -p 24 -i ~/.ssh/MyKey [email protected]

$ chown brb:brb ~/.ssh/id_rsa*
$ chmod 600 ~/.ssh/id_rsa
$ chmod 644 ~/.ssh/

If we do not change the permission correctly in <id_rsa>, we will get a warning: Unprotected private key file. Permissions 0664 for '/home/USERNAME/.ssh/id_rsa' are too open.

Preserve ssh keys when upgrading computers

ls -l /etc/ssh/*key* > ~/key_list  # optional
mkdir ~/serverkeys && sudo cp -p /etc/ssh/*key* ~/serverkeys/ # back up, -p will preserve mode, ownership and timestamps
sudo cp -p ~/serverkeys/*key* /etc/ssh  # copy back
ls -l /etc/ssh/*key* | diff - ~/key_list # optional

If diff produces no output, you're finished.

Pay attention to the permissions. All the /etc/ssh/* files should be owned by root:root, with 644 permissions except for those that end in *key, which should be 600.

[email protected]:~$ ls -l /etc/ssh/*key*
total 32
-rw------- 1 root root  668 Dec  8 14:43 ssh_host_dsa_key
-rw-r--r-- 1 root root  599 Dec  8 14:43
-rw------- 1 root root  227 Dec  8 14:43 ssh_host_ecdsa_key
-rw-r--r-- 1 root root  171 Dec  8 14:43
-rw------- 1 root root  399 Dec  8 14:43 ssh_host_ed25519_key
-rw-r--r-- 1 root root   91 Dec  8 14:43
-rw------- 1 root root 1679 Dec  8 14:43 ssh_host_rsa_key
-rw-r--r-- 1 root root  391 Dec  8 14:43

[email protected]:~$ cd /etc/ssh; sudo tar -czvf ~/Downloads/sshkeys.tar.gz *key*
-rw------- root/root       668 2017-12-08 14:43 ssh_host_dsa_key
-rw-r--r-- root/root       599 2017-12-08 14:43
-rw------- root/root       227 2017-12-08 14:43 ssh_host_ecdsa_key
-rw-r--r-- root/root       171 2017-12-08 14:43
-rw------- root/root       399 2017-12-08 14:43 ssh_host_ed25519_key
-rw-r--r-- root/root        91 2017-12-08 14:43
-rw------- root/root      1679 2017-12-08 14:43 ssh_host_rsa_key
-rw-r--r-- root/root       391 2017-12-08 14:43

[email protected]:~/$ cd /etc/ssh; sudo tar -xzvf ~/Downloads/sshkeys.tar.gz  

Disable SSH host key checking

ssh -o UserKnownHostsFile=/dev/null \
    -o StrictHostKeyChecking=no \
     [email protected]

To disable the checking for all hosts, in your ~/.ssh/config (if this file doesn't exist, just create it):

Host *
    StrictHostKeyChecking no

Or for certain domains

Host * 
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  User foo
  LogLevel QUIET

Handling the ssh key change when connecting to a remote machine

An article from

  • Method 1. Remove the key using ssh-keygen -R command.
$ ssh-keygen -R {}
$ ssh-keygen -R {ssh.server.ip.address}
$ ssh-keygen -R
$ ssh-keygen -f "/home/$USERNAME/.ssh/known_hosts" -R ""
  • Method 2. Add correct host key in /home/user/.ssh/known_hosts
  • Method 3. Just delete the known_hosts file If you have only used one ssh server
  • Method 4. Use ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no method. See Alias or Disable SSH host key checking.

SSH Port forwarding

Verizon Quantum Gateway Router

User guide p98. Click 'Advanced' button first.

  • Source port: Any (this is the key)
  • Destination Ports: the port you want to use (connect from outside)
  • Forward to Port: Same as incoming port or the port used in the local computer

What is tunnel A tunnel provides a direct path that avoids some type of complexity you would otherwise have to deal with.

'L'ocal port forwarding: view a certain port web page on a remote domain locally

This port forwarding involves three computers (local, remote/application server, host/secure shell server). If the remote is the same as the host, it will be reduced to involving 2 computers.

For example, we like to access home's router ( information from an outsider computer. Suppose the host 'hostname' is one computer in the home network and it can be accessed from outside world.

Another example is if we want to use Jupyter running on a remote machine from local browser.

# ssh -L localPort:remoteIP:remotePort [email protected]
ssh -L 8080: [email protected]
ssh -L 8080:localhost:80 [email protected]   # access http://hostname:80 using http://localhost:8080
ssh -i someKey.pem -L 443: [email protected]

The -L option specifies local port forwarding. In this case, port 8080 on the local machine was forwarded to port 80 on the remote machine. For the duration of the SSH session, pointing your browser at http://localhost:8080/ would send you to as if you are in the same local network of 'hostname'. We can try other ports like 1234 instead of 8080; it can be anything above 1024.

The reason it works is because the 'ssh' trick. In addition to being able to make yourself in the home network environment, the traffic on http://localhost:8080 is encrypted too.

Note that this forwarding uses port 8080 on the client rather than port 80. Binding to port 80 would require using root privileges every time we SSH.

To stop the ssh session, use ps -ef to find the process id and kill it.

Remote port forwarding (Reverse port forwarding)

This is most useful in situations where you have a machine which isn't publicly accessible from the internet, but you want others to be able to access a service on this machine. In this case, if you have SSH access to a remote machine which is publicly accessible on the internet, you can set up a reverse port forward on that remote machine to the local machine which is running the service.

ssh -R 8000:localhost:80 [email protected]_MACHINE

This will forward port 8000 on the remote machine to port 80 on the local machine. Using this method, if you browse to http://localhost on the remote machine, you will actually connected to a web server running on port 8000 of the local machine.

Example 2: Suppose you have two machine

  • machine A (userA): under firewall. cannot be directly accessed (like corporate machines)
  • machine B (userB): local machine (like home machines)

Our goal is to access machine A directly from machine B.

We can run the following on the machine A

# ssh -R remoteIP:remoteport:localIP:localport hostname
# ssh -R remoteport:localIP:localport hostname
ssh -R 2222:localhost:22 [email protected]_IP
ssh -i /path/to/priv/key/id_rsa -f -N -R 2222:localhost:22 [email protected]_IP

Then we can access machine A from machine B by

ssh -p 2222 [email protected]

If you want remote port forwarding configured every time you connect to a host, use the RemoteForward option in ssh_config .

LocalForward server-IP:server-port client-IP:client-port

'D'ynamic port forwarding, SOCKS proxy, bypass blocked websites from work computer

ssh -D 4096 [email protected]
ssh -D 4096 -p 23 [email protected]

ssh -D 4096 -p 23 -f -N -q -C [email protected]

This will require you to enter the password and leave you in the remote machine. If a nonstandard port is required, we can use -p option. -f is to fork process into background, -N means don't open a shell, -q means quiet and -C means compress data sent through tunnel. In order to close the connection, you need to find the process ID and kill it manually. You can use other port like 1080 (or something like 4321 which is also easy to remember too).

Now in the firefox, we need to go to Edit -> Preferences -> Advanced -> Network tab -> Settings... Check 'Manual proxy configuration' (The default is 'Use system proxy settings') and enter 'localhost' for SOCKS (SOCKS5 by default) Host and '4096' for the Port. Don't enter 'localhost' in the HTTP Proxy. Also check the option Proxy DNS when using SOCKS v5; otherwise someone on the network can see which site you are trying to get to even they are unable to see what you are seeing.

Open and search my ip to check if the change works.

Note that in addition to the Firefox, we can use

  • Chrome or chromium
  • SeaMonkey (seems better than Firefox since the form works better on 1024x600 resolution).
  • Brave browser does not support proxy

On Windows, we can use Putty. In short, in the left-hand panel, navigate through Connection > SSH > Tunnels. Enter 4096 in the Source Port box and select the Dynamic radio button. Click Add and “D4096″ will appear in the Forwarded Ports list. The setting in the firefox end is the same. See also my Windows wiki page.

Linux journal also put a video on youtube. We can use to check the current location. The port number is 1080 in the example. The example actually also use '-N' option which means no interaction; i.e. ssh -N -D 1080 [email protected] So we won't see anything after we type our password. Once we want to stop SOCK proxy, we just need to hit Ctr+C on terminal.

Backgrounding OpenSSH Forwarding

Use the -N flag to tell ssh to not run anything, including a terminal, on the remote server, and the -f flag to tell ssh to go into the background on the client.

ssh -fNL 2222:localhost:22 [email protected] &

By backgrounding this command, you get your original terminal back.

ssh through an intermediate server

Simple method is

Another method is to use ssh ProxyCommand to tunnel connections.

A third method is to

$ ssh -L 9999:host2:22 [email protected]  # leave this terminal 
# open a new terminal tab
$ ssh -p 9999 [email protected]


file path with spaces (parentheses)

Use double quotes around the full path and a backslash to escape any space.

scp [email protected]:"web/tmp/Master\ File\ 18\ 10\ 13.xls" .

Use the 'Tab' key to get the full path used by Linux.

$ cd Calibre\ Library/calibre/Calibre-2\ days\ \(582\)/
$ exit
~/Downloads$ scp "taichimd:~/Calibre\ Library/calibre/Calibre-2\ days\ \(582\)/*.mobi" .

# Use the path we understand does not work
~/Downloads$ scp "taichimd:~/Calibre Library/calibre/Calibre-2 days (582)/*.mobi" .
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `scp -f ~/Calibre Library/calibre/Calibre-2 days (582)/*.mobi'


You either need quotes, or a backslash before the star, but not both. And scp is not the one expanding it, the shell is. See How to use wildcards (*) when copying with scp?

scp [email protected]:/abc/def/*.txt .   # no matches found:
scp [email protected]:/abc/def/\*.txt .

Copy multiple files

scp or sftp copy multiple files with single command

From local to remote: use space character.

scp foo.txt bar.txt [email protected]:

From remote to local: use escaped parentheses and comma sign.

scp [email protected]:~/\{foo.txt,bar.txt\} .

Some uses double quotes around the files with the space character to separate files but it does not work when I try to copy files from remote(biowulf) to local(mac).

Recursive copying

Use -r parameter.

Preserve permissions and modes

Use -p parameter.

scp files through one intermediate host

The following command is tested.

scp -o 'ProxyCommand ssh [email protected] nc %h %p' [email protected]:path/to/file .

A second method which is useful for ssh and scp commands

$ ssh -L 9999:host2:22 [email protected] # leave the terminal
# Open a new terminal
$ scp -P 9999 fileName [email protected]:/path/to/dest/fileName   # transfer from local to remote. Note: Upper P.
$ scp -P 9999 [email protected]:/path/to/source/fileName fileName # transfer from remote to local. Note: Upper P.
# If we only want to use ssh
$ ssh -p 9999 [email protected] # Note: lower p.

scp with non-standard port: -P (capital)

Use -P argument.

scp -P 23 myfile [email protected]:

scp without a password

Assume the ssh key has been copied to the remote computer

scp -p -P 22 -i ~/.ssh/MyKey [email protected]:MyFile .


  1. Verify that local-host and remote-host is running openSSH (ssh -V)
  2. Generate key-pair on the local-host using ssh-keygen (Enter a passphrase here, do not leave it empty. A passphrase should be at least several words long, something you can easily remember. It's a bad idea to use a single word as a passphrase.)
  3. Install public key on the remote-host
  4. Give appropriate permission to the .ssh directory on the remote-host (chmod 755 ~/.ssh; chmod 644 ~/.ssh/authorized_keys)
  5. Login from the local-host to remote-host using the SSH key authentication to verify whether it works properly
  6. Start the SSH Agent on local-host to perform ssh and scp without having to enter the passphrase several times (ssh-agent $SHELL)
  7. Load the private key to the SSH agent on the local-host (ssh-add, need to enter the passphrase 1 time only)
  8. Perform SSH or SCP to remote-home from local-host without entering the password. It works for all remote machines containing the key from local-local.

Another option is to use ssh -i IDENTITY_FILE. See

ssh with password on the command line

Install sshpass utility. See

Rsync does use your ssh config

SCP user’s migration guide to rsync.

Some advantages of rsync over scp:

  • In-flight compression
  • Delta transfers
  • Syncing